summaryrefslogtreecommitdiff
path: root/gdb/ia64-tdep.c
diff options
context:
space:
mode:
authorKevin Buettner <kevinb@redhat.com>2000-03-23 04:27:26 +0000
committerKevin Buettner <kevinb@redhat.com>2000-03-23 04:27:26 +0000
commitacdb2b219e99f442c0738e5cf0f7a097bf03f851 (patch)
tree66b64cc3f6d78d9988e044e45abf42b7fe5a88ac /gdb/ia64-tdep.c
parente96734b68287678feaca9fdf0a4ced00b3b6c507 (diff)
downloadgdb-acdb2b219e99f442c0738e5cf0f7a097bf03f851.tar.gz
HFA, function descriptor handling for IA-64.
Diffstat (limited to 'gdb/ia64-tdep.c')
-rw-r--r--gdb/ia64-tdep.c375
1 files changed, 294 insertions, 81 deletions
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index be3a9009a4d..850b7263a51 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -87,8 +87,8 @@ static gdbarch_push_arguments_ftype ia64_push_arguments;
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;
@@ -384,7 +384,7 @@ replace_slotN_contents (unsigned 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 */
@@ -445,7 +445,7 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr)
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;
@@ -639,7 +639,6 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
{
CORE_ADDR next_pc;
CORE_ADDR last_prologue_pc = pc;
- int done = 0;
instruction_type it;
long long instr;
int do_fsr_stuff = 0;
@@ -1137,20 +1136,45 @@ ia64_get_saved_register (char *raw_buffer,
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,
- &regbuf[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,
+ &regbuf[REGISTER_BYTE (regnum)], valbuf + offset);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
else
- memcpy (valbuf, &regbuf[REGISTER_BYTE (IA64_GR8_REGNUM)], TYPE_LENGTH (type));
+ memcpy (valbuf, &regbuf[REGISTER_BYTE (IA64_GR8_REGNUM)],
+ TYPE_LENGTH (type));
}
/* FIXME: Turn this into a stack of some sort. Unfortunately, something
@@ -1219,7 +1243,6 @@ ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
else
{
struct frame_info *frn = frame->next;
- CORE_ADDR cfm_addr;
FRAME_INIT_SAVED_REGS (frn);
@@ -1243,7 +1266,198 @@ ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
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 (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 (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;
+}
+
+
+/* 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
+find_global_pointer (CORE_ADDR faddr)
+{
+ struct partial_symtab *pst;
+
+ pst = find_pc_psymtab (faddr);
+ 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));
+
+ 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 partial_symtab *pst;
+ struct obj_section *osect;
+
+ /* Return early if faddr is already a function descriptor */
+ osect = find_pc_section (faddr);
+ if (osect && strcmp (osect->the_bfd_section->name, ".opd") == 0)
+ return faddr;
+
+ pst = find_pc_psymtab (faddr);
+ if (pst != NULL)
+ {
+ ALL_OBJFILE_OSECTIONS (pst->objfile, osect)
+ {
+ if (strcmp (osect->the_bfd_section->name, ".opd") == 0)
+ break;
+ }
+
+ if (osect < pst->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,
@@ -1253,11 +1467,12 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
value_ptr 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++)
{
@@ -1270,12 +1485,17 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
if (len > 8 && (nslots & 1))
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);
@@ -1292,18 +1512,51 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
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);
+
+ /* 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 */
if (len > 8 && (slotnum & 1))
slotnum++;
argoffset = 0;
@@ -1323,14 +1576,28 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
len -= 8;
slotnum++;
}
- if (TYPE_CODE (type) == TYPE_CODE_FLT && floatreg < IA64_FR16_REGNUM)
- {
- ia64_register_convert_to_raw (type, floatreg, VALUE_CONTENTS (arg),
- &registers[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,
+ &registers[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 (&registers[REGISTER_BYTE (IA64_GR8_REGNUM)],
@@ -1338,7 +1605,7 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
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
@@ -1359,64 +1626,10 @@ ia64_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
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];
+ CORE_ADDR global_pointer = find_global_pointer (pc);
- 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... */
- 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;