#include "inferior.h"
#include "symfile.h" /* for entry_point_address */
#include "gdbcore.h"
+#include "arch-utils.h"
#include "floatformat.h"
#include "objfiles.h"
#include "elf/common.h" /* for DT_PLTGOT value */
#include "elf-bfd.h"
+/* Hook for determining the global pointer when calling functions in
+ the inferior under AIX. The initialization code in ia64-aix-nat.c
+ sets this hook to the address of a function which will find the
+ global pointer for a given address.
+
+ The generic code which uses the dynamic section in the inferior for
+ finding the global pointer is not of much use on AIX since the
+ values obtained from the inferior have not been relocated. */
+
+CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0;
+
+/* An enumeration of the different IA-64 instruction types. */
+
typedef enum instruction_type
{
A, /* Integer ALU ; I-unit or M-unit */
struct gdbarch_tdep
{
int os_ident; /* From the ELF header, one of the ELFOSABI_
- constants: ELFOSABI_LINUX, ELFOSABI_MONTEREY,
+ constants: ELFOSABI_LINUX, ELFOSABI_AIX,
etc. */
CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int);
/* OS specific function which, given a frame address
and register number, returns the offset to the
given register from the start of the frame. */
+ CORE_ADDR (*find_global_pointer) (CORE_ADDR);
};
-#define SIGCONTEXT_REGISTER_ADDRESS (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
+#define SIGCONTEXT_REGISTER_ADDRESS \
+ (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
+#define FIND_GLOBAL_POINTER \
+ (gdbarch_tdep (current_gdbarch)->find_global_pointer)
static char *
ia64_register_name (int reg)
/* We don't really want to use this, but remote.c needs to call it in order
to figure out if Z-packets are supported or not. Oh, well. */
unsigned char *
-ia64_breakpoint_from_pc (pcptr, lenptr)
- CORE_ADDR *pcptr;
- int *lenptr;
+ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
static unsigned char breakpoint[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int mem_stack_frame_size = 0;
int spill_reg = 0;
CORE_ADDR spill_addr = 0;
+ char instores[8];
+ char infpstores[8];
+
+ memset (instores, 0, sizeof instores);
+ memset (infpstores, 0, sizeof infpstores);
if (frame && !frame->saved_regs)
{
if (next_pc == 0)
break;
- if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
+ if (it == B || ((instr & 0x3fLL) != 0LL))
+ {
+ /* Exit loop upon hitting a branch instruction or a predicated
+ instruction. */
+ break;
+ }
+ else if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
{
/* Move from BR */
int b2 = (int) ((instr & 0x0000000e000LL) >> 13);
spill_addr = 0; /* must be done spilling */
last_prologue_pc = next_pc;
}
+ else if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+ {
+ /* Allow up to one store of each input register. */
+ instores[rM-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M && ((instr & 0x1ff08000000LL) == 0x08c00000000LL))
+ {
+ /* One of
+ st1 [rN] = rM
+ st2 [rN] = rM
+ st4 [rN] = rM
+ st8 [rN] = rM
+ Note that the st8 case is handled in the clause above.
+
+ Advance over stores of input registers. One store per input
+ register is permitted. */
+ int rM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
+ {
+ instores[rM-32] = 1;
+ last_prologue_pc = next_pc;
+ }
+ }
+ else if (it == M && ((instr & 0x1ff88000000LL) == 0x0cc80000000LL))
+ {
+ /* Either
+ stfs [rN] = fM
+ or
+ stfd [rN] = fM
+
+ Advance over stores of floating point input registers. Again
+ one store per register is permitted */
+ int fM = (int) ((instr & 0x000000fe000LL) >> 13);
+ int qp = (int) (instr & 0x0000000003fLL);
+ if (qp == 0 && 8 <= fM && fM < 16 && !infpstores[fM - 8])
+ {
+ infpstores[fM-8] = 1;
+ last_prologue_pc = next_pc;
+ }
}
else if (it == M
&& ( ((instr & 0x1ffc8000000LL) == 0x08ec0000000LL)
last_prologue_pc = next_pc;
}
}
- else if (it == B || ((instr & 0x3fLL) != 0LL))
- break;
pc = next_pc;
}
if (do_fsr_stuff) {
int i;
CORE_ADDR addr;
+ int sor, rrb_gr;
+
+ /* Extract the size of the rotating portion of the stack
+ frame and the register rename base from the current
+ frame marker. */
+ sor = ((frame->extra_info->cfm >> 14) & 0xf) * 8;
+ rrb_gr = (frame->extra_info->cfm >> 18) & 0x7f;
for (i = 0, addr = frame->extra_info->bsp;
i < frame->extra_info->sof;
{
addr += 8;
}
- frame->saved_regs[IA64_GR32_REGNUM + i] = addr;
+ if (i < sor)
+ frame->saved_regs[IA64_GR32_REGNUM + ((i + (sor - rrb_gr)) % sor)]
+ = addr;
+ else
+ frame->saved_regs[IA64_GR32_REGNUM + i] = addr;
if (i+32 == cfm_reg)
frame->saved_regs[IA64_CFM_REGNUM] = addr;
int prN_val;
ia64_get_saved_register (pr_raw_buffer, &pr_optim, &pr_addr,
frame, IA64_PR_REGNUM, &pr_lval);
+ if (IA64_PR16_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
+ {
+ /* Fetch predicate register rename base from current frame
+ marker for this frame. */
+ int rrb_pr = (frame->extra_info->cfm >> 32) & 0x3f;
+
+ /* Adjust the register number to account for register rotation. */
+ regnum = IA64_PR16_REGNUM
+ + ((regnum - IA64_PR16_REGNUM) + rrb_pr) % 48;
+ }
prN_val = extract_bit_field ((unsigned char *) pr_raw_buffer,
regnum - IA64_PR0_REGNUM, 1);
store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), prN_val);
}
else
{
+ if (IA64_FR32_REGNUM <= regnum && regnum <= IA64_FR127_REGNUM)
+ {
+ /* Fetch floating point register rename base from current
+ frame marker for this frame. */
+ int rrb_fr = (frame->extra_info->cfm >> 25) & 0x7f;
+
+ /* Adjust the floating point register number to account for
+ register rotation. */
+ regnum = IA64_FR32_REGNUM
+ + ((regnum - IA64_FR32_REGNUM) + rrb_fr) % 96;
+ }
+
generic_get_saved_register (raw_buffer, optimized, addrp, frame,
regnum, lval);
}
d_un.d_ptr value is the global pointer. */
static CORE_ADDR
-find_global_pointer (CORE_ADDR faddr)
+generic_elf_find_global_pointer (CORE_ADDR faddr)
{
struct obj_section *faddr_sect;
fdesc = *fdaptr;
*fdaptr += 16;
- global_pointer = find_global_pointer (faddr);
+ global_pointer = FIND_GLOBAL_POINTER (faddr);
if (global_pointer == 0)
global_pointer = read_register (IA64_GR1_REGNUM);
CORE_ADDR
ia64_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
- CORE_ADDR global_pointer = find_global_pointer (pc);
+ CORE_ADDR global_pointer = FIND_GLOBAL_POINTER (pc);
if (global_pointer != 0)
write_register (IA64_GR1_REGNUM, global_pointer);
case 0 :
*os_ident_ptr = ELFOSABI_LINUX;
break;
-#if 0 /* FIXME: Enable after internal repository is synced with sourceware */
case 1 :
*os_ident_ptr = ELFOSABI_HURD;
break;
case 2 :
*os_ident_ptr = ELFOSABI_SOLARIS;
break;
-#endif
default :
internal_error (
"process_note_abi_sections: unknown OS number %d", os_number);
os_ident = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
/* If os_ident is 0, it is not necessarily the case that we're on a
- SYSV system. (ELFOSABI_SYSV is defined to be 0.) GNU/Linux uses
+ SYSV system. (ELFOSABI_NONE is defined to be 0.) GNU/Linux uses
a note section to record OS/ABI info, but leaves e_ident[EI_OSABI]
zero. So we have to check for note sections too. */
if (os_ident == 0)
else
tdep->sigcontext_register_address = 0;
+ /* We know that Linux won't have to resort to the native_find_global_pointer
+ hackery. But that's the only one we know about so far, so if
+ native_find_global_pointer is set to something non-zero, then use
+ it. Otherwise fall back to using generic_elf_find_global_pointer.
+ This arrangement should (in theory) allow us to cross debug Linux
+ binaries from an AIX machine. */
+ if (os_ident == ELFOSABI_LINUX)
+ tdep->find_global_pointer = generic_elf_find_global_pointer;
+ else if (native_find_global_pointer != 0)
+ tdep->find_global_pointer = native_find_global_pointer;
+ else
+ tdep->find_global_pointer = generic_elf_find_global_pointer;
+
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_sp_regnum (gdbarch, sp_regnum);
set_gdbarch_fp_regnum (gdbarch, fp_regnum);
set_gdbarch_pc_regnum (gdbarch, pc_regnum);
+ set_gdbarch_fp0_regnum (gdbarch, IA64_FR0_REGNUM);
set_gdbarch_register_name (gdbarch, ia64_register_name);
set_gdbarch_register_size (gdbarch, 8);