aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog7
-rw-r--r--gdb/hppa-tdep.c65
2 files changed, 70 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 44f8f48..5971c56 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,12 @@
2005-12-09 Randolph Chung <tausq@debian.org>
+ * hppa-tdep.c (hppa64_convert_code_addr_to_fptr): New function.
+ (hppa64_push_dummy_call): If passing a function pointer, ensure
+ it is a function descriptor address instead of the function entry
+ point.
+
+2005-12-09 Randolph Chung <tausq@debian.org>
+
* hppa-tdep.c (hppa64_dwarf_reg_to_regnum): New funtion.
(hppa_gdbarch_init): Set dwarf_reg_to_regnum and
dwarf2_reg_to_regnum methods.
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 88eb1dc..ce0b487 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -897,6 +897,50 @@ hppa64_floating_p (const struct type *type)
return 0;
}
+/* If CODE points to a function entry address, try to look up the corresponding
+ function descriptor and return its address instead. If CODE is not a
+ function entry address, then just return it unchanged. */
+static CORE_ADDR
+hppa64_convert_code_addr_to_fptr (CORE_ADDR code)
+{
+ struct obj_section *sec, *opd;
+
+ sec = find_pc_section (code);
+
+ if (!sec)
+ return code;
+
+ /* If CODE is in a data section, assume it's already a fptr. */
+ if (!(sec->the_bfd_section->flags & SEC_CODE))
+ return code;
+
+ ALL_OBJFILE_OSECTIONS (sec->objfile, opd)
+ {
+ if (strcmp (opd->the_bfd_section->name, ".opd") == 0)
+ break;
+ }
+
+ if (opd < sec->objfile->sections_end)
+ {
+ CORE_ADDR addr;
+
+ for (addr = opd->addr; addr < opd->endaddr; addr += 2 * 8)
+ {
+ ULONGEST opdaddr;
+ char tmp[8];
+
+ if (target_read_memory (addr, tmp, sizeof (tmp)))
+ break;
+ opdaddr = extract_unsigned_integer (tmp, sizeof (tmp));
+
+ if (opdaddr == code)
+ return addr - 16;
+ }
+ }
+
+ return code;
+}
+
static CORE_ADDR
hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
@@ -917,6 +961,7 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct type *type = value_type (arg);
int len = TYPE_LENGTH (type);
const bfd_byte *valbuf;
+ bfd_byte fptrbuf[8];
int regnum;
/* "Each parameter begins on a 64-bit (8-byte) boundary." */
@@ -992,10 +1037,26 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
}
}
+ /* If we are passing a function pointer, make sure we pass a function
+ descriptor instead of the function entry address. */
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
+ {
+ ULONGEST codeptr, fptr;
+
+ codeptr = unpack_long (type, value_contents (arg));
+ fptr = hppa64_convert_code_addr_to_fptr (codeptr);
+ store_unsigned_integer (fptrbuf, TYPE_LENGTH (type), fptr);
+ valbuf = fptrbuf;
+ }
+ else
+ {
+ valbuf = value_contents (arg);
+ }
+
/* Always store the argument in memory. */
- write_memory (sp + offset, value_contents (arg), len);
+ write_memory (sp + offset, valbuf, len);
- valbuf = value_contents (arg);
regnum = HPPA_ARG0_REGNUM - offset / 8;
while (regnum > HPPA_ARG0_REGNUM - 8 && len > 0)
{