[patch/rfc] function descriptor handling for push_dummy_call

Randolph Chung randolph@tausq.org
Tue May 18 06:12:00 GMT 2004


This implements the idea discussed in:

http://sources.redhat.com/ml/gdb-patches/2004-05/msg00093.html

Instead of passing a dereferenced function value into push_dummy_call (), it 
passes the entire "struct value *function".  This is not a complete patch; it
is only for comments.

The first bit updates gdbarch.{sh,h,c} with the new prototype, and shows how 
$(ARCH)-tdep.c will have to change. There are two cases: in most of the cases
the func_addr argument in the original prototype is not used, so it is 
sufficient to only change the function declaration without changing 
functionality.  This will apply to almost all the targets. (hppa-tdep.c is
updated as an example.)

In a few other cases where the method needs the function address,
it will need to either make a call to find_function_addr () or
value_as_address (). This includes rs6000-tdep.c, ia64-tdep.c, and possibly
other function-descriptor targets.

The second patch shows how this is used to implement function descriptor
handling for the hppa target. This is based on the comments to my original
patch posted at:

http://sources.redhat.com/ml/gdb-patches/2004-04/msg00662.html

Andrew had ok'ed the patch except for the handling of the gp register in the
convert_from_func_ptr_addr method, so this tries to fix it properly :)

Comments? If this looks like an ok approach I will try to patch the other 
targets.

thanks,
randolph

==========================  patch 1 ==========================

2004-05-17  Randolph Chung  <tausq@debian.org>

	* gdbarch.sh (PUSH_DUMMY_CALL): Change CORE_ADDR func_addr argument
	to struct value *function.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Likewise.
	* infcall.c (call_function_by_hand): Pass entire function value
	to push_dummy_call.
	* hppa-tdep.c (hppa32_push_dummy_call, hppa64_push_dummy_call): Update
	prototype.

Index: gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.317
diff -u -p -r1.317 gdbarch.sh
--- gdbarch.sh	8 May 2004 21:52:50 -0000	1.317
+++ gdbarch.sh	18 May 2004 05:45:55 -0000
@@ -514,7 +514,7 @@ F::DEPRECATED_TARGET_READ_FP:CORE_ADDR:d
 
 # See gdbint.texinfo.  See infcall.c.  New, all singing all dancing,
 # replacement for DEPRECATED_PUSH_ARGUMENTS.
-M::PUSH_DUMMY_CALL:CORE_ADDR:push_dummy_call:CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr:func_addr, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr
+M::PUSH_DUMMY_CALL:CORE_ADDR:push_dummy_call:struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr:function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr
 # PUSH_DUMMY_CALL is a direct replacement for DEPRECATED_PUSH_ARGUMENTS.
 F:2:DEPRECATED_PUSH_ARGUMENTS:CORE_ADDR:deprecated_push_arguments:int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr:nargs, args, sp, struct_return, struct_addr
 # Implement PUSH_RETURN_ADDRESS, and then merge in
Index: gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.290
diff -u -p -r1.290 gdbarch.c
--- gdbarch.c	8 May 2004 21:52:50 -0000	1.290
+++ gdbarch.c	18 May 2004 05:45:54 -0000
@@ -3073,13 +3073,13 @@ gdbarch_push_dummy_call_p (struct gdbarc
 }
 
 CORE_ADDR
-gdbarch_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->push_dummy_call != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_push_dummy_call called\n");
-  return gdbarch->push_dummy_call (gdbarch, func_addr, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr);
+  return gdbarch->push_dummy_call (gdbarch, function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr);
 }
 
 void
Index: gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.253
diff -u -p -r1.253 gdbarch.h
--- gdbarch.h	8 May 2004 21:52:50 -0000	1.253
+++ gdbarch.h	18 May 2004 05:45:54 -0000
@@ -721,8 +721,8 @@ extern void set_gdbarch_deprecated_targe
 
 extern int gdbarch_push_dummy_call_p (struct gdbarch *gdbarch);
 
-typedef CORE_ADDR (gdbarch_push_dummy_call_ftype) (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
-extern CORE_ADDR gdbarch_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+typedef CORE_ADDR (gdbarch_push_dummy_call_ftype) (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+extern CORE_ADDR gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
 extern void set_gdbarch_push_dummy_call (struct gdbarch *gdbarch, gdbarch_push_dummy_call_ftype *push_dummy_call);
 
 /* PUSH_DUMMY_CALL is a direct replacement for DEPRECATED_PUSH_ARGUMENTS. */
Index: infcall.c
===================================================================
RCS file: /cvs/src/src/gdb/infcall.c,v
retrieving revision 1.47
diff -u -p -r1.47 infcall.c
--- infcall.c	8 May 2004 22:19:30 -0000	1.47
+++ infcall.c	18 May 2004 05:45:56 -0000
@@ -660,7 +660,7 @@ You must use a pointer to function type 
     /* When there is no push_dummy_call method, should this code
        simply error out.  That would the implementation of this method
        for all ABIs (which is probably a good thing).  */
-    sp = gdbarch_push_dummy_call (current_gdbarch, funaddr, current_regcache,
+    sp = gdbarch_push_dummy_call (current_gdbarch, function, current_regcache,
 				  bp_addr, nargs, args, sp, struct_return,
 				  struct_addr);
   else  if (DEPRECATED_PUSH_ARGUMENTS_P ())
Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.159
diff -u -p -r1.159 hppa-tdep.c
--- hppa-tdep.c	17 May 2004 16:46:06 -0000	1.159
+++ hppa-tdep.c	18 May 2004 05:45:55 -0000
@@ -714,7 +713,7 @@ hppa64_register_name (int i)
    arguments into their proper slots.  */
    
 CORE_ADDR
-hppa32_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 			struct regcache *regcache, CORE_ADDR bp_addr,
 			int nargs, struct value **args, CORE_ADDR sp,
 			int struct_return, CORE_ADDR struct_addr)
@@ -875,7 +889,7 @@ hppa32_push_dummy_call (struct gdbarch *
    to the callee, so we do that too.  */
    
 CORE_ADDR
-hppa64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 			struct regcache *regcache, CORE_ADDR bp_addr,
 			int nargs, struct value **args, CORE_ADDR sp,
 			int struct_return, CORE_ADDR struct_addr)

==========================  patch 2 ==========================

2004-05-17  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.

Index: hppa-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.h,v
retrieving revision 1.9
diff -u -p -r1.9 hppa-tdep.h
--- hppa-tdep.h	16 May 2004 04:33:41 -0000	1.9
+++ hppa-tdep.h	18 May 2004 05:45:55 -0000
@@ -22,8 +22,7 @@
 #define HPPA_TDEP_H
 
 struct trad_frame_saved_reg;
+struct value;

 enum { HPPA_INSTRUCTION_SIZE = 4 };
 
 /* Register numbers of various important registers.
@@ -79,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 *);
 };
 
 /*
Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.159
diff -u -p -r1.159 hppa-tdep.c
--- hppa-tdep.c	17 May 2004 16:46:06 -0000	1.159
+++ hppa-tdep.c	18 May 2004 05:45:55 -0000
@@ -729,6 +728,12 @@ hppa32_push_dummy_call (struct gdbarch *
   /* 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;
@@ -852,6 +861,11 @@ hppa32_push_dummy_call (struct gdbarch *
   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);
 
@@ -985,6 +999,23 @@ hppa64_push_dummy_call (struct gdbarch *
 }
 
 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;
+      unsigned int gp;
+
+      plabel = addr & ~3;
+      target_read_memory(plabel, (char *)&addr, 4);
+    }
+
+  return addr;
+}
+
+static CORE_ADDR
 hppa32_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
     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[],
@@ -2372,6 +2441,8 @@ hppa_gdbarch_init (struct gdbarch_info i
   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)
@@ -2431,6 +2502,8 @@ hppa_gdbarch_init (struct gdbarch_info i
     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: hppa-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-linux-tdep.c,v
retrieving revision 1.5
diff -u -p -r1.5 hppa-linux-tdep.c
--- hppa-linux-tdep.c	8 May 2004 03:59:34 -0000	1.5
+++ hppa-linux-tdep.c	18 May 2004 05:45:55 -0000
@@ -28,8 +28,11 @@ Foundation, Inc., 59 Temple Place - Suit
 #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 (stru
   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;
 
@@ -476,6 +566,8 @@ hppa_linux_init_abi (struct gdbarch_info
 
   /* 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);
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.572
diff -u -p -r1.572 Makefile.in
--- Makefile.in 17 May 2004 15:16:39 -0000      1.572
+++ Makefile.in 18 May 2004 06:07:30 -0000
@@ -1838,7 +1838,7 @@ hppa-tdep.o: hppa-tdep.c $(defs_h) $(fra
 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) \
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/



More information about the Gdb-patches mailing list