2005-12-09 Randolph Chung <tausq@debian.org>
authorRandolph Chung <tausq@debian.org>
Fri, 9 Dec 2005 11:13:34 +0000 (11:13 +0000)
committerRandolph Chung <tausq@debian.org>
Fri, 9 Dec 2005 11:13:34 +0000 (11:13 +0000)
* 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.

gdb/ChangeLog
gdb/hppa-tdep.c

index 44f8f48..5971c56 100644 (file)
@@ -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.
index 88eb1dc..ce0b487 100644 (file)
@@ -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)
        {