/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
- Copyright 1999, 2000
+ Copyright 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GDB.
#include "inferior.h"
#include "symfile.h" /* for entry_point_address */
#include "gdbcore.h"
+#include "arch-utils.h"
#include "floatformat.h"
+#include "regcache.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
{
#define BUNDLE_LEN 16
-extern void _initialize_ia64_tdep (void);
+/* FIXME: These extern declarations should go in ia64-tdep.h. */
+extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int);
+extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int);
static gdbarch_init_ftype ia64_gdbarch_init;
static gdbarch_push_return_address_ftype ia64_push_return_address;
static gdbarch_pop_frame_ftype ia64_pop_frame;
static gdbarch_saved_pc_after_call_ftype ia64_saved_pc_after_call;
-
static void ia64_pop_frame_regular (struct frame_info *frame);
+static struct type *is_float_or_hfa_type (struct type *t);
static int ia64_num_regs = 590;
};
struct frame_extra_info
-{
- CORE_ADDR bsp; /* points at r32 for the current frame */
- CORE_ADDR cfm; /* cfm value for current frame */
- int sof; /* Size of frame (decoded from cfm value) */
- int sol; /* Size of locals (decoded from cfm value) */
- CORE_ADDR after_prologue;
- /* Address of first instruction after the last
+ {
+ CORE_ADDR bsp; /* points at r32 for the current frame */
+ CORE_ADDR cfm; /* cfm value for current frame */
+ int sof; /* Size of frame (decoded from cfm value) */
+ int sol; /* Size of locals (decoded from cfm value) */
+ CORE_ADDR after_prologue;
+ /* Address of first instruction after the last
prologue instruction; Note that there may
be instructions from the function's body
intermingled with the prologue. */
- int mem_stack_frame_size;
- /* Size of the memory stack frame (may be zero),
+ int mem_stack_frame_size;
+ /* Size of the memory stack frame (may be zero),
or -1 if it has not been determined yet. */
- int fp_reg; /* Register number (if any) used a frame pointer
- for this frame. 0 if no register is being used
+ int fp_reg; /* Register number (if any) used a frame pointer
+ for this frame. 0 if no register is being used
as the frame pointer. */
-};
+ };
+
+struct gdbarch_tdep
+ {
+ int os_ident; /* From the ELF header, one of the ELFOSABI_
+ 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 FIND_GLOBAL_POINTER \
+ (gdbarch_tdep (current_gdbarch)->find_global_pointer)
static char *
ia64_register_name (int reg)
(reg <= IA64_FR0_REGNUM ? 0 : 8 * ((reg > IA64_FR127_REGNUM) ? 128 : reg - IA64_FR0_REGNUM));
}
+/* Read the given register from a sigcontext structure in the
+ specified frame. */
+
+static CORE_ADDR
+read_sigcontext_register (struct frame_info *frame, int regnum)
+{
+ CORE_ADDR regaddr;
+
+ if (frame == NULL)
+ internal_error (__FILE__, __LINE__,
+ "read_sigcontext_register: NULL frame");
+ if (!frame->signal_handler_caller)
+ internal_error (__FILE__, __LINE__,
+ "read_sigcontext_register: frame not a signal_handler_caller");
+ if (SIGCONTEXT_REGISTER_ADDRESS == 0)
+ internal_error (__FILE__, __LINE__,
+ "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0");
+
+ regaddr = SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regnum);
+ if (regaddr)
+ return read_memory_integer (regaddr, REGISTER_RAW_SIZE (regnum));
+ else
+ internal_error (__FILE__, __LINE__,
+ "read_sigcontext_register: Register %d not in struct sigcontext", regnum);
+}
+
/* Extract ``len'' bits from an instruction bundle starting at
bit ``from''. */
-long long
+static long long
extract_bit_field (char *bundle, int from, int len)
{
long long result = 0LL;
/* Replace the specified bits in an instruction bundle */
-void
+static void
replace_bit_field (char *bundle, long long val, int from, int len)
{
int to = from + len;
/* Return the contents of slot N (for N = 0, 1, or 2) in
and instruction bundle */
-long long
-slotN_contents (unsigned char *bundle, int slotnum)
+static long long
+slotN_contents (char *bundle, int slotnum)
{
return extract_bit_field (bundle, 5+41*slotnum, 41);
}
/* Store an instruction in an instruction bundle */
-void
-replace_slotN_contents (unsigned char *bundle, long long instr, int slotnum)
+static void
+replace_slotN_contents (char *bundle, long long instr, int slotnum)
{
replace_bit_field (bundle, instr, 5+41*slotnum, 41);
}
-static template_encoding_table[32][3] =
+static enum instruction_type template_encoding_table[32][3] =
{
{ M, I, I }, /* 00 */
{ M, I, I }, /* 01 */
long long template;
int val;
+ /* Warn about slot numbers greater than 2. We used to generate
+ an error here on the assumption that the user entered an invalid
+ address. But, sometimes GDB itself requests an invalid address.
+ This can (easily) happen when execution stops in a function for
+ which there are no symbols. The prologue scanner will attempt to
+ find the beginning of the function - if the nearest symbol
+ happens to not be aligned on a bundle boundary (16 bytes), the
+ resulting starting address will cause GDB to think that the slot
+ number is too large.
+
+ So we warn about it and set the slot number to zero. It is
+ not necessarily a fatal condition, particularly if debugging
+ at the assembly language level. */
if (slotnum > 2)
- error("Can't fetch instructions for slot numbers greater than 2.");
+ {
+ warning ("Can't fetch instructions for slot numbers greater than 2.\n"
+ "Using slot 0 instead");
+ slotnum = 0;
+ }
addr &= ~0x0f;
template = extract_bit_field (bundle, 0, 5);
*it = template_encoding_table[(int)template][slotnum];
- if (slotnum == 2 || slotnum == 1 && *it == L)
+ if (slotnum == 2 || (slotnum == 1 && *it == L))
addr += 16;
else
addr += (slotnum + 1) * SLOT_MULTIPLIER;
/* 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 };
}
CORE_ADDR
-ia64_read_pc (int pid)
+ia64_read_pc (ptid_t ptid)
{
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, pid);
- CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, pid);
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
+ CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, ptid);
int slot_num = (psr_value >> 41) & 3;
return pc_value | (slot_num * SLOT_MULTIPLIER);
}
void
-ia64_write_pc (CORE_ADDR new_pc, int pid)
+ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
{
int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, pid);
+ CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
psr_value &= ~(3LL << 41);
psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
new_pc &= ~0xfLL;
- write_register_pid (IA64_PSR_REGNUM, psr_value, pid);
- write_register_pid (IA64_IP_REGNUM, new_pc, pid);
+ write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
+ write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
}
#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
CORE_ADDR
ia64_frame_chain (struct frame_info *frame)
{
- FRAME_INIT_SAVED_REGS (frame);
-
- if (frame->saved_regs[IA64_VFP_REGNUM])
- return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
+ if (frame->signal_handler_caller)
+ return read_sigcontext_register (frame, sp_regnum);
+ else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+ return frame->frame;
else
- return frame->frame + frame->extra_info->mem_stack_frame_size;
+ {
+ FRAME_INIT_SAVED_REGS (frame);
+ if (frame->saved_regs[IA64_VFP_REGNUM])
+ return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
+ else
+ return frame->frame + frame->extra_info->mem_stack_frame_size;
+ }
}
CORE_ADDR
ia64_frame_saved_pc (struct frame_info *frame)
{
- FRAME_INIT_SAVED_REGS (frame);
+ if (frame->signal_handler_caller)
+ return read_sigcontext_register (frame, pc_regnum);
+ else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+ return generic_read_register_dummy (frame->pc, frame->frame, pc_regnum);
+ else
+ {
+ FRAME_INIT_SAVED_REGS (frame);
+
+ if (frame->saved_regs[IA64_VRAP_REGNUM])
+ return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
+ else if (frame->next && frame->next->signal_handler_caller)
+ return read_sigcontext_register (frame->next, IA64_BR0_REGNUM);
+ else /* either frameless, or not far enough along in the prologue... */
+ return ia64_saved_pc_after_call (frame);
+ }
+}
+
+/* Limit the number of skipped non-prologue instructions since examining
+ of the prologue is expensive. */
+static int max_skip_non_prologue_insns = 10;
+
+/* Given PC representing the starting address of a function, and
+ LIM_PC which is the (sloppy) limit to which to scan when looking
+ for a prologue, attempt to further refine this limit by using
+ the line data in the symbol table. If successful, a better guess
+ on where the prologue ends is returned, otherwise the previous
+ value of lim_pc is returned. TRUST_LIMIT is a pointer to a flag
+ which will be set to indicate whether the returned limit may be
+ used with no further scanning in the event that the function is
+ frameless. */
+
+static CORE_ADDR
+refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
+{
+ struct symtab_and_line prologue_sal;
+ CORE_ADDR start_pc = pc;
- if (frame->saved_regs[IA64_VRAP_REGNUM])
- return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
- else /* either frameless, or not far enough along in the prologue... */
- return ia64_saved_pc_after_call (frame);
+ /* Start off not trusting the limit. */
+ *trust_limit = 0;
+
+ prologue_sal = find_pc_line (pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ int i;
+ CORE_ADDR addr = prologue_sal.end;
+
+ /* Handle the case in which compiler's optimizer/scheduler
+ has moved instructions into the prologue. We scan ahead
+ in the function looking for address ranges whose corresponding
+ line number is less than or equal to the first one that we
+ found for the function. (It can be less than when the
+ scheduler puts a body instruction before the first prologue
+ instruction.) */
+ for (i = 2 * max_skip_non_prologue_insns;
+ i > 0 && (lim_pc == 0 || addr < lim_pc);
+ i--)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (addr, 0);
+ if (sal.line == 0)
+ break;
+ if (sal.line <= prologue_sal.line
+ && sal.symtab == prologue_sal.symtab)
+ {
+ prologue_sal = sal;
+ }
+ addr = sal.end;
+ }
+
+ if (lim_pc == 0 || prologue_sal.end < lim_pc)
+ {
+ lim_pc = prologue_sal.end;
+ if (start_pc == get_pc_function_start (lim_pc))
+ *trust_limit = 1;
+ }
+ }
+ return lim_pc;
}
#define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
{
CORE_ADDR next_pc;
CORE_ADDR last_prologue_pc = pc;
- int done = 0;
instruction_type it;
long long instr;
int do_fsr_stuff = 0;
int mem_stack_frame_size = 0;
int spill_reg = 0;
CORE_ADDR spill_addr = 0;
+ char instores[8];
+ char infpstores[8];
+ int trust_limit;
+
+ memset (instores, 0, sizeof instores);
+ memset (infpstores, 0, sizeof infpstores);
if (frame && !frame->saved_regs)
{
&& frame->extra_info->after_prologue <= lim_pc)
return frame->extra_info->after_prologue;
+ lim_pc = refine_prologue_limit (pc, lim_pc, &trust_limit);
+
/* Must start with an alloc instruction */
next_pc = fetch_instruction (pc, &it, &instr);
if (pc < lim_pc && next_pc
pc = next_pc;
}
else
- pc = lim_pc; /* We're done early */
+ {
+ pc = lim_pc; /* Frameless: We're done early. */
+ if (trust_limit)
+ last_prologue_pc = lim_pc;
+ }
/* Loop, looking for prologue instructions, keeping track of
where preserved registers were spilled. */
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;
void
ia64_frame_init_saved_regs (struct frame_info *frame)
{
- CORE_ADDR func_start;
-
if (frame->saved_regs)
return;
- func_start = get_pc_function_start (frame->pc);
- examine_prologue (func_start, frame->pc, frame);
-}
+ if (frame->signal_handler_caller && SIGCONTEXT_REGISTER_ADDRESS)
+ {
+ int regno;
-static CORE_ADDR
-ia64_find_saved_register (frame, regnum)
- struct frame_info *frame;
- int regnum;
-{
- register CORE_ADDR addr = 0;
+ frame_saved_regs_zalloc (frame);
- if ((IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
- || regnum == IA64_VFP_REGNUM
- || regnum == IA64_VRAP_REGNUM)
- {
- FRAME_INIT_SAVED_REGS (frame);
- return frame->saved_regs[regnum];
- }
- else if (regnum == IA64_IP_REGNUM && frame->next)
- {
- FRAME_INIT_SAVED_REGS (frame->next);
- return frame->next->saved_regs[IA64_VRAP_REGNUM];
+ frame->saved_regs[IA64_VRAP_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_IP_REGNUM);
+ frame->saved_regs[IA64_CFM_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CFM_REGNUM);
+ frame->saved_regs[IA64_PSR_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PSR_REGNUM);
+#if 0
+ frame->saved_regs[IA64_BSP_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_BSP_REGNUM);
+#endif
+ frame->saved_regs[IA64_RNAT_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_RNAT_REGNUM);
+ frame->saved_regs[IA64_CCV_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CCV_REGNUM);
+ frame->saved_regs[IA64_UNAT_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_UNAT_REGNUM);
+ frame->saved_regs[IA64_FPSR_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_FPSR_REGNUM);
+ frame->saved_regs[IA64_PFS_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PFS_REGNUM);
+ frame->saved_regs[IA64_LC_REGNUM] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_LC_REGNUM);
+ for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
+ if (regno != sp_regnum)
+ frame->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
+ for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
+ frame->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
+ for (regno = IA64_FR2_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
+ frame->saved_regs[regno] =
+ SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
}
else
{
- struct frame_info *frame1 = NULL;
- while (1)
- {
- QUIT;
- frame1 = get_prev_frame (frame1);
- if (frame1 == 0 || frame1 == frame)
- break;
- FRAME_INIT_SAVED_REGS (frame1);
- if (frame1->saved_regs[regnum])
- addr = frame1->saved_regs[regnum];
- }
- }
+ CORE_ADDR func_start;
- return addr;
+ func_start = get_pc_function_start (frame->pc);
+ examine_prologue (func_start, frame->pc, frame);
+ }
}
void
int regnum,
enum lval_type *lval)
{
- CORE_ADDR addr;
+ int is_dummy_frame;
if (!target_has_registers)
error ("No registers.");
if (optimized != NULL)
*optimized = 0;
- addr = ia64_find_saved_register (frame, regnum);
- if (addr != 0)
- {
- if (lval != NULL)
- *lval = lval_memory;
- if (regnum == SP_REGNUM)
- {
- if (raw_buffer != NULL)
- {
- /* Put it back in target format. */
- store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), (LONGEST) addr);
- }
- if (addrp != NULL)
- *addrp = 0;
- return;
- }
- if (raw_buffer != NULL)
- read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
- }
- else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
- {
- /* r32 - r127 must be fetchable via memory. If they aren't,
- then the register is unavailable */
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
- memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
- }
- else if (regnum == IA64_IP_REGNUM)
- {
- CORE_ADDR pc;
- if (frame->next)
- {
- /* This case will normally be handled above, except when it's
- frameless or we haven't advanced far enough into the prologue
- of the top frame to save the register. */
- addr = REGISTER_BYTE (regnum);
- if (lval != NULL)
- *lval = lval_register;
- pc = ia64_saved_pc_after_call (frame);
- }
- else
- {
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
- pc = read_pc ();
- }
- store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
- }
- else if (regnum == SP_REGNUM && frame->next)
+
+ if (addrp != NULL)
+ *addrp = 0;
+
+ if (lval != NULL)
+ *lval = not_lval;
+
+ is_dummy_frame = PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame);
+
+ if (regnum == SP_REGNUM && frame->next)
{
/* Handle SP values for all frames but the topmost. */
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
}
else if (regnum == IA64_BSP_REGNUM)
{
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
frame->extra_info->bsp);
}
above. If the function lacks one of these frame pointers, we can
still provide a value since we know the size of the frame */
CORE_ADDR vfp = frame->frame + frame->extra_info->mem_stack_frame_size;
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_VFP_REGNUM), vfp);
}
else if (IA64_PR0_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
{
- char pr_raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *pr_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
int pr_optim;
enum lval_type pr_lval;
CORE_ADDR pr_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);
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
{
- char unat_raw_buffer[MAX_REGISTER_RAW_SIZE];
+ char *unat_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
int unat_optim;
enum lval_type unat_lval;
CORE_ADDR unat_addr;
regnum - IA64_NAT0_REGNUM, 1);
store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum),
unatN_val);
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
}
else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
{
int natval = 0;
/* Find address of general register corresponding to nat bit we're
interested in. */
- CORE_ADDR gr_addr =
- ia64_find_saved_register (frame,
- regnum - IA64_NAT0_REGNUM + IA64_GR0_REGNUM);
+ CORE_ADDR gr_addr = 0;
+
+ if (!is_dummy_frame)
+ {
+ FRAME_INIT_SAVED_REGS (frame);
+ gr_addr = frame->saved_regs[ regnum - IA64_NAT0_REGNUM
+ + IA64_GR0_REGNUM];
+ }
if (gr_addr)
{
/* Compute address of nat collection bits */
natval = (nat_collection >> nat_bit) & 1;
}
store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), natval);
- addr = 0;
- if (lval != NULL)
- *lval = not_lval;
+ }
+ else if (regnum == IA64_IP_REGNUM)
+ {
+ CORE_ADDR pc;
+ if (frame->next)
+ {
+ /* FIXME: Set *addrp, *lval when possible. */
+ pc = ia64_frame_saved_pc (frame->next);
+ }
+ else
+ {
+ pc = read_pc ();
+ }
+ store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
+ }
+ else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
+ {
+ CORE_ADDR addr = 0;
+ if (!is_dummy_frame)
+ {
+ FRAME_INIT_SAVED_REGS (frame);
+ addr = frame->saved_regs[regnum];
+ }
+
+ if (addr != 0)
+ {
+ if (lval != NULL)
+ *lval = lval_memory;
+ if (addrp != NULL)
+ *addrp = addr;
+ read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
+ }
+ else
+ {
+ /* r32 - r127 must be fetchable via memory. If they aren't,
+ then the register is unavailable */
+ memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
+ }
}
else
{
- if (lval != NULL)
- *lval = lval_register;
- addr = REGISTER_BYTE (regnum);
- if (raw_buffer != NULL)
- read_register_gen (regnum, raw_buffer);
+ 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);
}
- if (addrp != NULL)
- *addrp = addr;
}
/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
int
ia64_use_struct_convention (int gcc_p, struct type *type)
{
- /* FIXME: Need to check for HFAs; structures containing (only) up to 8
- floating point values of the same size are returned in floating point
- registers. */
+ struct type *float_elt_type;
+
+ /* HFAs are structures (or arrays) consisting entirely of floating
+ point values of the same length. Up to 8 of these are returned
+ in registers. Don't use the struct convention when this is the
+ case. */
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL
+ && TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type) <= 8)
+ return 0;
+
+ /* Other structs of length 32 or less are returned in r8-r11.
+ Don't use the struct convention for those either. */
return TYPE_LENGTH (type) > 32;
}
void
ia64_extract_return_value (struct type *type, char *regbuf, char *valbuf)
{
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- ia64_register_convert_to_virtual (IA64_FR8_REGNUM, type,
- ®buf[REGISTER_BYTE (IA64_FR8_REGNUM)], valbuf);
+ struct type *float_elt_type;
+
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ int offset = 0;
+ int regnum = IA64_FR8_REGNUM;
+ int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+ while (n-- > 0)
+ {
+ ia64_register_convert_to_virtual (regnum, float_elt_type,
+ ®buf[REGISTER_BYTE (regnum)], valbuf + offset);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
else
- memcpy (valbuf, ®buf[REGISTER_BYTE (IA64_GR8_REGNUM)], TYPE_LENGTH (type));
+ memcpy (valbuf, ®buf[REGISTER_BYTE (IA64_GR8_REGNUM)],
+ TYPE_LENGTH (type));
}
/* FIXME: Turn this into a stack of some sort. Unfortunately, something
int
ia64_frameless_function_invocation (struct frame_info *frame)
{
- /* FIXME: Implement */
- return 0;
+ FRAME_INIT_SAVED_REGS (frame);
+ return (frame->extra_info->mem_stack_frame_size == 0);
}
CORE_ADDR
ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
{
CORE_ADDR bsp, cfm;
+ int next_frame_is_call_dummy = ((frame->next != NULL)
+ && PC_IN_CALL_DUMMY (frame->next->pc, frame->next->frame,
+ frame->next->frame));
frame->extra_info = (struct frame_extra_info *)
frame_obstack_alloc (sizeof (struct frame_extra_info));
cfm = read_register (IA64_CFM_REGNUM);
}
+ else if (frame->next->signal_handler_caller)
+ {
+ bsp = read_sigcontext_register (frame->next, IA64_BSP_REGNUM);
+ cfm = read_sigcontext_register (frame->next, IA64_CFM_REGNUM);
+ }
+ else if (next_frame_is_call_dummy)
+ {
+ bsp = generic_read_register_dummy (frame->next->pc, frame->next->frame,
+ IA64_BSP_REGNUM);
+ cfm = generic_read_register_dummy (frame->next->pc, frame->next->frame,
+ IA64_CFM_REGNUM);
+ }
else
{
struct frame_info *frn = frame->next;
- CORE_ADDR cfm_addr;
FRAME_INIT_SAVED_REGS (frn);
if (frn->saved_regs[IA64_CFM_REGNUM] != 0)
cfm = read_memory_integer (frn->saved_regs[IA64_CFM_REGNUM], 8);
+ else if (frn->next && frn->next->signal_handler_caller)
+ cfm = read_sigcontext_register (frn->next, IA64_PFS_REGNUM);
+ else if (frn->next
+ && PC_IN_CALL_DUMMY (frn->next->pc, frn->next->frame,
+ frn->next->frame))
+ cfm = generic_read_register_dummy (frn->next->pc, frn->next->frame,
+ IA64_PFS_REGNUM);
else
- cfm = read_register (IA64_CFM_REGNUM);
+ cfm = read_register (IA64_PFS_REGNUM);
bsp = frn->extra_info->bsp;
}
frame->extra_info->cfm = cfm;
frame->extra_info->sof = cfm & 0x7f;
frame->extra_info->sol = (cfm >> 7) & 0x7f;
- if (frame->next == 0)
+ if (frame->next == 0
+ || frame->next->signal_handler_caller
+ || next_frame_is_call_dummy)
frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sof);
else
frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sol);
frame->extra_info->fp_reg = 0;
}
-#define ROUND_UP(n,a) (((n)+(a)-1) & ~((a)-1))
+static int
+is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
+{
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_FLT:
+ if (*etp)
+ return TYPE_LENGTH (*etp) == TYPE_LENGTH (t);
+ else
+ {
+ *etp = t;
+ return 1;
+ }
+ break;
+ case TYPE_CODE_ARRAY:
+ return
+ is_float_or_hfa_type_recurse (check_typedef (TYPE_TARGET_TYPE (t)),
+ etp);
+ break;
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (t); i++)
+ if (!is_float_or_hfa_type_recurse
+ (check_typedef (TYPE_FIELD_TYPE (t, i)), etp))
+ return 0;
+ return 1;
+ }
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+/* Determine if the given type is one of the floating point types or
+ and HFA (which is a struct, array, or combination thereof whose
+ bottom-most elements are all of the same floating point type.) */
+
+static struct type *
+is_float_or_hfa_type (struct type *t)
+{
+ struct type *et = 0;
+
+ return is_float_or_hfa_type_recurse (t, &et) ? et : 0;
+}
+
+
+/* Return 1 if the alignment of T is such that the next even slot
+ should be used. Return 0, if the next available slot should
+ be used. (See section 8.5.1 of the IA-64 Software Conventions
+ and Runtime manual.) */
+
+static int
+slot_alignment_is_next_even (struct type *t)
+{
+ switch (TYPE_CODE (t))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_FLT:
+ if (TYPE_LENGTH (t) > 8)
+ return 1;
+ else
+ return 0;
+ case TYPE_CODE_ARRAY:
+ return
+ slot_alignment_is_next_even (check_typedef (TYPE_TARGET_TYPE (t)));
+ case TYPE_CODE_STRUCT:
+ {
+ int i;
+
+ for (i = 0; i < TYPE_NFIELDS (t); i++)
+ if (slot_alignment_is_next_even
+ (check_typedef (TYPE_FIELD_TYPE (t, i))))
+ return 1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/* Attempt to find (and return) the global pointer for the given
+ function.
+
+ This is a rather nasty bit of code searchs for the .dynamic section
+ in the objfile corresponding to the pc of the function we're trying
+ to call. Once it finds the addresses at which the .dynamic section
+ lives in the child process, it scans the Elf64_Dyn entries for a
+ DT_PLTGOT tag. If it finds one of these, the corresponding
+ d_un.d_ptr value is the global pointer. */
+
+static CORE_ADDR
+generic_elf_find_global_pointer (CORE_ADDR faddr)
+{
+ struct obj_section *faddr_sect;
+
+ faddr_sect = find_pc_section (faddr);
+ if (faddr_sect != NULL)
+ {
+ struct obj_section *osect;
+
+ ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+ {
+ if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
+ break;
+ }
+
+ if (osect < faddr_sect->objfile->sections_end)
+ {
+ CORE_ADDR addr;
+
+ addr = osect->addr;
+ while (addr < osect->endaddr)
+ {
+ int status;
+ LONGEST tag;
+ char buf[8];
+
+ status = target_read_memory (addr, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ tag = extract_signed_integer (buf, sizeof (buf));
+
+ if (tag == DT_PLTGOT)
+ {
+ CORE_ADDR global_pointer;
+
+ status = target_read_memory (addr + 8, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ global_pointer = extract_address (buf, sizeof (buf));
+
+ /* The payoff... */
+ return global_pointer;
+ }
+
+ if (tag == DT_NULL)
+ break;
+
+ addr += 16;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Given a function's address, attempt to find (and return) the
+ corresponding (canonical) function descriptor. Return 0 if
+ not found. */
+static CORE_ADDR
+find_extant_func_descr (CORE_ADDR faddr)
+{
+ struct obj_section *faddr_sect;
+
+ /* Return early if faddr is already a function descriptor */
+ faddr_sect = find_pc_section (faddr);
+ if (faddr_sect && strcmp (faddr_sect->the_bfd_section->name, ".opd") == 0)
+ return faddr;
+
+ if (faddr_sect != NULL)
+ {
+ struct obj_section *osect;
+ ALL_OBJFILE_OSECTIONS (faddr_sect->objfile, osect)
+ {
+ if (strcmp (osect->the_bfd_section->name, ".opd") == 0)
+ break;
+ }
+
+ if (osect < faddr_sect->objfile->sections_end)
+ {
+ CORE_ADDR addr;
+
+ addr = osect->addr;
+ while (addr < osect->endaddr)
+ {
+ int status;
+ LONGEST faddr2;
+ char buf[8];
+
+ status = target_read_memory (addr, buf, sizeof (buf));
+ if (status != 0)
+ break;
+ faddr2 = extract_signed_integer (buf, sizeof (buf));
+
+ if (faddr == faddr2)
+ return addr;
+
+ addr += 16;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Attempt to find a function descriptor corresponding to the
+ given address. If none is found, construct one on the
+ stack using the address at fdaptr */
+
+static CORE_ADDR
+find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
+{
+ CORE_ADDR fdesc;
+
+ fdesc = find_extant_func_descr (faddr);
+
+ if (fdesc == 0)
+ {
+ CORE_ADDR global_pointer;
+ char buf[16];
+
+ fdesc = *fdaptr;
+ *fdaptr += 16;
+
+ global_pointer = FIND_GLOBAL_POINTER (faddr);
+
+ if (global_pointer == 0)
+ global_pointer = read_register (IA64_GR1_REGNUM);
+
+ store_address (buf, 8, faddr);
+ store_address (buf + 8, 8, global_pointer);
+
+ write_memory (fdesc, buf, 16);
+ }
+
+ return fdesc;
+}
CORE_ADDR
-ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
+ia64_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
int argno;
- value_ptr arg;
+ struct value *arg;
struct type *type;
int len, argoffset;
- int nslots, rseslots, memslots, slotnum;
+ int nslots, rseslots, memslots, slotnum, nfuncargs;
int floatreg;
- CORE_ADDR bsp, cfm, pfs, new_bsp;
+ CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr;
nslots = 0;
+ nfuncargs = 0;
/* Count the number of slots needed for the arguments */
for (argno = 0; argno < nargs; argno++)
{
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
- /* FIXME: This is crude and it is wrong (IMO), but it matches
- what gcc does, I think. */
- if (len > 8 && (nslots & 1))
+ if ((nslots & 1) && slot_alignment_is_next_even (type))
nslots++;
+ if (TYPE_CODE (type) == TYPE_CODE_FUNC)
+ nfuncargs++;
+
nslots += (len + 7) / 8;
}
+ /* Divvy up the slots between the RSE and the memory stack */
rseslots = (nslots > 8) ? 8 : nslots;
memslots = nslots - rseslots;
+ /* Allocate a new RSE frame */
cfm = read_register (IA64_CFM_REGNUM);
bsp = read_register (IA64_BSP_REGNUM);
cfm |= rseslots;
write_register (IA64_CFM_REGNUM, cfm);
-
-
- sp = sp - 16 - memslots * 8;
+ /* We will attempt to find function descriptors in the .opd segment,
+ but if we can't we'll construct them ourselves. That being the
+ case, we'll need to reserve space on the stack for them. */
+ funcdescaddr = sp - nfuncargs * 16;
+ funcdescaddr &= ~0xfLL;
+
+ /* Adjust the stack pointer to it's new value. The calling conventions
+ require us to have 16 bytes of scratch, plus whatever space is
+ necessary for the memory slots and our function descriptors */
+ sp = sp - 16 - (memslots + nfuncargs) * 8;
sp &= ~0xfLL; /* Maintain 16 byte alignment */
+ /* Place the arguments where they belong. The arguments will be
+ either placed in the RSE backing store or on the memory stack.
+ In addition, floating point arguments or HFAs are placed in
+ floating point registers. */
slotnum = 0;
floatreg = IA64_FR8_REGNUM;
for (argno = 0; argno < nargs; argno++)
{
+ struct type *float_elt_type;
+
arg = args[argno];
type = check_typedef (VALUE_TYPE (arg));
len = TYPE_LENGTH (type);
- if (len > 8 && (slotnum & 1))
+
+ /* Special handling for function parameters */
+ if (len == 8
+ && TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
+ {
+ char val_buf[8];
+
+ store_address (val_buf, 8,
+ find_func_descr (extract_address (VALUE_CONTENTS (arg), 8),
+ &funcdescaddr));
+ if (slotnum < rseslots)
+ write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+ else
+ write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
+ slotnum++;
+ continue;
+ }
+
+ /* Normal slots */
+
+ /* Skip odd slot if necessary... */
+ if ((slotnum & 1) && slot_alignment_is_next_even (type))
slotnum++;
+
argoffset = 0;
while (len > 0)
{
len -= 8;
slotnum++;
}
- if (TYPE_CODE (type) == TYPE_CODE_FLT && floatreg < IA64_FR16_REGNUM)
- {
- ia64_register_convert_to_raw (type, floatreg, VALUE_CONTENTS (arg),
- ®isters[REGISTER_BYTE (floatreg)]);
- floatreg++;
+
+ /* Handle floating point types (including HFAs) */
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ argoffset = 0;
+ len = TYPE_LENGTH (type);
+ while (len > 0 && floatreg < IA64_FR16_REGNUM)
+ {
+ ia64_register_convert_to_raw (
+ float_elt_type,
+ floatreg,
+ VALUE_CONTENTS (arg) + argoffset,
+ ®isters[REGISTER_BYTE (floatreg)]);
+ floatreg++;
+ argoffset += TYPE_LENGTH (float_elt_type);
+ len -= TYPE_LENGTH (float_elt_type);
+ }
}
}
+ /* Store the struct return value in r8 if necessary. */
if (struct_return)
{
store_address (®isters[REGISTER_BYTE (IA64_GR8_REGNUM)],
struct_addr);
}
-
+ /* Sync gdb's idea of what the registers are with the target. */
target_store_registers (-1);
/* FIXME: This doesn't belong here! Instead, SAVE_DUMMY_FRAME_TOS needs
CORE_ADDR
ia64_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
{
- struct partial_symtab *pst;
-
- /* Attempt to determine and set global pointer (r1) for this pc.
-
- This rather nasty bit of code searchs for the .dynamic section
- in the objfile corresponding to the pc of the function we're
- trying to call. Once it finds the addresses at which the .dynamic
- section lives in the child process, it scans the Elf64_Dyn entries
- for a DT_PLTGOT tag. If it finds one of these, the corresponding
- d_un.d_ptr value is the global pointer. */
- pst = find_pc_psymtab (pc);
- if (pst != NULL)
- {
- struct obj_section *osect;
-
- ALL_OBJFILE_OSECTIONS (pst->objfile, osect)
- {
- if (strcmp (osect->the_bfd_section->name, ".dynamic") == 0)
- break;
- }
-
- if (osect < pst->objfile->sections_end)
- {
- CORE_ADDR addr;
-
- addr = osect->addr;
- while (addr < osect->endaddr)
- {
- int status;
- LONGEST tag;
- char buf[8];
-
- status = target_read_memory (addr, buf, sizeof (buf));
- if (status != 0)
- break;
- tag = extract_signed_integer (buf, sizeof (buf));
+ CORE_ADDR global_pointer = FIND_GLOBAL_POINTER (pc);
- if (tag == DT_PLTGOT)
- {
- CORE_ADDR global_pointer;
-
- status = target_read_memory (addr + 8, buf, sizeof (buf));
- if (status != 0)
- break;
- global_pointer = extract_address (buf, sizeof (buf));
-
- /* The payoff... */
- write_register (IA64_GR1_REGNUM, global_pointer);
- break;
- }
-
- if (tag == DT_NULL)
- break;
-
- addr += 16;
- }
- }
- }
+ if (global_pointer != 0)
+ write_register (IA64_GR1_REGNUM, global_pointer);
write_register (IA64_BR0_REGNUM, CALL_DUMMY_ADDRESS ());
return sp;
*targ_len = nr_bytes;
}
+static void
+process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+ int *os_ident_ptr = obj;
+ const char *name;
+ unsigned int sectsize;
+
+ name = bfd_get_section_name (abfd, sect);
+ sectsize = bfd_section_size (abfd, sect);
+ if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+ {
+ unsigned int name_length, data_length, note_type;
+ char *note = alloca (sectsize);
+
+ bfd_get_section_contents (abfd, sect, note,
+ (file_ptr) 0, (bfd_size_type) sectsize);
+
+ name_length = bfd_h_get_32 (abfd, note);
+ data_length = bfd_h_get_32 (abfd, note + 4);
+ note_type = bfd_h_get_32 (abfd, note + 8);
+
+ if (name_length == 4 && data_length == 16 && note_type == 1
+ && strcmp (note + 12, "GNU") == 0)
+ {
+ int os_number = bfd_h_get_32 (abfd, note + 16);
+
+ /* The case numbers are from abi-tags in glibc */
+ switch (os_number)
+ {
+ case 0 :
+ *os_ident_ptr = ELFOSABI_LINUX;
+ break;
+ case 1 :
+ *os_ident_ptr = ELFOSABI_HURD;
+ break;
+ case 2 :
+ *os_ident_ptr = ELFOSABI_SOLARIS;
+ break;
+ default :
+ internal_error (__FILE__, __LINE__,
+ "process_note_abi_sections: unknown OS number %d", os_number);
+ break;
+ }
+ }
+ }
+}
+
static struct gdbarch *
ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ int os_ident;
+
+ if (info.abfd != NULL
+ && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+ {
+ 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_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)
+ {
+ bfd_map_over_sections (info.abfd,
+ process_note_abi_tag_sections,
+ &os_ident);
+ }
+ }
+ else
+ os_ident = -1;
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ if (gdbarch_tdep (current_gdbarch)->os_ident != os_ident)
+ continue;
+ return arches->gdbarch;
+ }
+
+ tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->os_ident = os_ident;
- gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Set the method of obtaining the sigcontext addresses at which
+ registers are saved. The method of checking to see if
+ native_find_global_pointer is nonzero to indicate that we're
+ on AIX is kind of hokey, but I can't think of a better way
+ to do it. */
+ if (os_ident == ELFOSABI_LINUX)
+ tdep->sigcontext_register_address = ia64_linux_sigcontext_register_address;
+ else if (native_find_global_pointer != 0)
+ tdep->sigcontext_register_address = ia64_aix_sigcontext_register_address;
+ 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_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);
set_gdbarch_saved_pc_after_call (gdbarch, ia64_saved_pc_after_call);
set_gdbarch_frame_chain (gdbarch, ia64_frame_chain);
- set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
+ set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
set_gdbarch_frame_saved_pc (gdbarch, ia64_frame_saved_pc);
set_gdbarch_frame_init_saved_regs (gdbarch, ia64_frame_init_saved_regs);