2004-06-06 Randolph Chung <tausq@debian.org>
authorRandolph Chung <tausq@debian.org>
Mon, 7 Jun 2004 02:08:07 +0000 (02:08 +0000)
committerRandolph Chung <tausq@debian.org>
Mon, 7 Jun 2004 02:08:07 +0000 (02:08 +0000)
* hppa-tdep.h (struct value): Forward declaration.
(gdbarch_tdep): Define tdep find_global_pointer method.
* hppa-tdep.c (hppa32_push_dummy_call): Find the global pointer
associated with the function we are trying to call, and write it
to the gp register.
(hppa32_convert_from_funct_ptr_addr): New function.
(hppa_find_global_pointer): New function.
(hppa_gdbarch_init): Set default find_global_pointer method; set
convert_from_func_ptr_addr method.
* hppa-linux-tdep.c (hppa_linux_find_global_pointer): New function.
(hppa_linux_init_abi): Set find_global_pointer method.
* Makefile.in (hppa-linux-tdep.o): Add value.h dependency.

gdb/ChangeLog
gdb/Makefile.in
gdb/hppa-linux-tdep.c
gdb/hppa-tdep.c
gdb/hppa-tdep.h

index 0924853cdc32424023f34c564abfc762ea339722..88f39daed9a80842393d950a709d30e92898acca 100644 (file)
@@ -1,3 +1,18 @@
+2004-06-06  Randolph Chung  <tausq@debian.org>
+
+       * hppa-tdep.h (struct value): Forward declaration.
+       (gdbarch_tdep): Define tdep find_global_pointer method.
+       * hppa-tdep.c (hppa32_push_dummy_call): Find the global pointer
+       associated with the function we are trying to call, and write it
+       to the gp register.
+       (hppa32_convert_from_funct_ptr_addr): New function.
+       (hppa_find_global_pointer): New function.
+       (hppa_gdbarch_init): Set default find_global_pointer method; set
+       convert_from_func_ptr_addr method.
+       * hppa-linux-tdep.c (hppa_linux_find_global_pointer): New function.
+       (hppa_linux_init_abi): Set find_global_pointer method.
+       * Makefile.in (hppa-linux-tdep.o): Add value.h dependency.
+
 2004-06-06  Randolph Chung  <tausq@debian.org>
 
        * gdbarch.sh (PUSH_DUMMY_CALL): Change CORE_ADDR func_addr argument
index 5a303c2c4b20a651867baa40f515051f4063c0e5..8cb27b5895961fdf5ece38f67855de3b3171d204 100644 (file)
@@ -1845,7 +1845,7 @@ hppa-tdep.o: hppa-tdep.c $(defs_h) $(frame_h) $(bfd_h) $(inferior_h) \
 hppa-linux-tdep.o: hppa-linux-tdep.c $(defs_h) $(gdbcore_h) $(osabi_h) \
        $(target_h) $(objfiles_h) $(solib_svr4_h) $(glibc_tdep_h) \
        $(frame_unwind_h) $(trad_frame_h) $(dwarf2_frame_h) $(hppa_tdep_h) \
-       $(elf_common_h) 
+       $(elf_common_h) $(value_h)
 hppa-linux-nat.o: hppa-linux-nat.c $(defs_h) $(gdbcore_h) $(regcache_h) \
        $(gdb_string_h) $(inferior_h)
 hpread.o: hpread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(hp_symtab_h) \
index f1639247bb8d216f77f7b5c45413185b44993239..32c6068dbd9cd5d6737da407871715a83fbf47de 100644 (file)
@@ -28,8 +28,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include "frame-unwind.h"
 #include "trad-frame.h"
 #include "dwarf2-frame.h"
+#include "value.h"
 #include "hppa-tdep.h"
 
+#include "elf/common.h"
+
 #if 0
 /* Convert DWARF register number REG to the appropriate register
    number used by GDB.  */
@@ -466,6 +469,93 @@ hppa_linux_sigtramp_unwind_sniffer (struct frame_info *next_frame)
   return NULL;
 }
 
+/* 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 Elf32_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
+hppa_linux_find_global_pointer (struct value *function)
+{
+  struct obj_section *faddr_sect;
+  CORE_ADDR faddr;
+  
+  faddr = value_as_address (function);
+
+  /* Is this a plabel? If so, dereference it to get the gp value.  */
+  if (faddr & 2)
+    {
+      int status;
+      char buf[4];
+
+      faddr &= ~3;
+
+      status = target_read_memory (faddr + 4, buf, sizeof (buf));
+      if (status == 0)
+       return extract_unsigned_integer (buf, sizeof (buf));
+    }
+
+  /* If the address is in the plt section, then the real function hasn't 
+     yet been fixed up by the linker so we cannot determine the gp of 
+     that function.  */
+  if (in_plt_section (faddr, NULL))
+    return 0;
+
+  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[4];
+
+             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 + 4, buf, sizeof (buf));
+                 if (status != 0)
+                   break;
+                 global_pointer = extract_unsigned_integer (buf, sizeof (buf));
+
+                 /* The payoff... */
+                 return global_pointer;
+               }
+
+             if (tag == DT_NULL)
+               break;
+
+             addr += 8;
+           }
+       }
+    }
+  return 0;
+}
+
 /* Forward declarations.  */
 extern initialize_file_ftype _initialize_hppa_linux_tdep;
 
@@ -477,6 +567,8 @@ hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   /* Linux is always ELF.  */
   tdep->is_elf = 1;
 
+  tdep->find_global_pointer = hppa_linux_find_global_pointer;
+
   set_gdbarch_write_pc (gdbarch, hppa_linux_target_write_pc);
 
   frame_unwind_append_sniffer (gdbarch, hppa_linux_sigtramp_unwind_sniffer);
index 4af061f85e95146a60ce0bdff675ab4548edf48d..a5b2f852c9e64d78a01cacfd72d49e1c442f56ab 100644 (file)
@@ -727,6 +727,12 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* Two passes.  First pass computes the location of everything,
      second pass writes the bytes out.  */
   int write_pass;
+
+  /* Global pointer (r19) of the function we are trying to call.  */
+  CORE_ADDR gp;
+
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   for (write_pass = 0; write_pass < 2; write_pass++)
     {
       CORE_ADDR struct_ptr = 0;
@@ -847,6 +853,11 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   if (struct_return)
     write_register (28, struct_addr);
 
+  gp = tdep->find_global_pointer (function);
+
+  if (gp != 0)
+    write_register (19, gp);
+
   /* Set the return address.  */
   regcache_cooked_write_unsigned (regcache, HPPA_RP_REGNUM, bp_addr);
 
@@ -979,6 +990,22 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   return param_end + 64;
 }
 
+static CORE_ADDR
+hppa32_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+                                  CORE_ADDR addr,
+                                  struct target_ops *targ)
+{
+  if (addr & 2)
+    {
+      CORE_ADDR plabel;
+
+      plabel = addr & ~3;
+      target_read_memory(plabel, (char *)&addr, 4);
+    }
+
+  return addr;
+}
+
 static CORE_ADDR
 hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
@@ -2309,6 +2336,12 @@ hppa_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
     store_unsigned_integer (buf, sizeof(tmp), tmp);
 }
 
+static CORE_ADDR
+hppa_find_global_pointer (struct value *function)
+{
+  return 0;
+}
+
 void
 hppa_frame_prev_register_helper (struct frame_info *next_frame,
                                 struct trad_frame_saved_reg saved_regs[],
@@ -2410,6 +2443,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   else
     tdep->bytes_per_address = 4;
 
+  tdep->find_global_pointer = hppa_find_global_pointer;
+
   /* Some parts of the gdbarch vector depend on whether we are running
      on a 32 bits or 64 bits target.  */
   switch (tdep->bytes_per_address)
@@ -2469,6 +2504,8 @@ hppa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     case 4:
       set_gdbarch_push_dummy_call (gdbarch, hppa32_push_dummy_call);
       set_gdbarch_frame_align (gdbarch, hppa32_frame_align);
+      set_gdbarch_convert_from_func_ptr_addr
+        (gdbarch, hppa32_convert_from_func_ptr_addr);
       break;
     case 8:
       set_gdbarch_push_dummy_call (gdbarch, hppa64_push_dummy_call);
index c5a78fa9754ae3f010aa95cbfe9695949320bafd..3f2235ddcd8dc59916e4871e7a807ae431631558 100644 (file)
@@ -78,6 +78,10 @@ struct gdbarch_tdep
   /* Is this an ELF target? This can be 64-bit HP-UX, or a 32/64-bit GNU/Linux
      system.  */
   int is_elf;
+
+  /* Given a function address, try to find the global pointer for the 
+     corresponding shared object.  */
+  CORE_ADDR (*find_global_pointer) (struct value *);
 };
 
 /*