This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[rfc] Fix stepping into solib function on powerpc64-linux


Hello,

this fixes stepping into shared library function calls on powerpc64-linux.

This was broken due to several different issues:
- the "standard linkage" call stub pattern was slightly incorrect
- current binutils actually generate two new variants of the standard
  linkage call stubs that were not supported at all
- the target of the call stub may in fact be a glink stub -- now that
  we have @plt synthetic symbols on those, find_solib_trampoline_target
  can be used to resolve them
- however, find_solib_trampoline_target did not handle minimal symbols
  that point to function descriptors

The patch fixes all these issues, resolving the gdb1555.exp FAILs with
older binutils, and a number of other regressions with newer binutils.

Tested on powerpc64-linux and powerpc-linux.

Bye,
Ulrich


ChangeLog:

	* minsyms.c: Include "target.h".
	(find_solib_trampoline_target): Handle minimal symbols pointing
	to function descriptors as well.
	* Makefile.in (minsyms.o): Update dependencies.

	* ppc-linux-tdep.c (ppc64_standard_linkage): Rename to ...
	(ppc64_standard_linkage1): ... this.  Fix optional instructions.
	(PPC64_STANDARD_LINKAGE_LEN): Rename to ...
	(PPC64_STANDARD_LINKAGE1_LEN): ... this.
	(ppc64_standard_linkage2, ppc64_standard_linkage3): New.
	(PPC64_STANDARD_LINKAGE2_LEN, PPC64_STANDARD_LINKAGE3_LEN): New.
	(ppc64_standard_linkage_target): Rename to ...
	(ppc64_standard_linkage1_target): ... this.
	(ppc64_standard_linkage2_target, ppc64_standard_linkage3_target): New.
	(ppc64_skip_trampoline_code): Support three variants of standard
	linkage stubs.  Call find_solib_trampoline_target to handle
	glink stubs.


diff -urNp gdb-orig/gdb/Makefile.in gdb-head/gdb/Makefile.in
--- gdb-orig/gdb/Makefile.in	2008-05-14 15:57:26.000000000 +0200
+++ gdb-head/gdb/Makefile.in	2008-05-15 01:43:04.204648051 +0200
@@ -2502,7 +2502,8 @@ mep-tdep.o: $(defs_h) $(frame_h) $(frame
 mingw-hdep.o: mingw-hdep.c $(defs_h) $(serial_h) $(event_loop_h) \
 	$(gdb_assert_h) $(gdb_select_h) $(gdb_string_h) $(readline_h)
 minsyms.o: minsyms.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \
-	$(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(cp_abi_h)
+	$(symfile_h) $(objfiles_h) $(demangle_h) $(value_h) $(cp_abi_h) \
+	$(target_h)
 mips64obsd-nat.o: mips64obsd-nat.c $(defs_h) $(inferior_h) $(regcache_h) \
 	$(target_h) $(mips_tdep_h) $(inf_ptrace_h)
 mips64obsd-tdep.o: mips64obsd-tdep.c $(defs_h) $(osabi_h) $(regcache_h) \
diff -urNp gdb-orig/gdb/minsyms.c gdb-head/gdb/minsyms.c
--- gdb-orig/gdb/minsyms.c	2008-05-14 20:26:07.000000000 +0200
+++ gdb-head/gdb/minsyms.c	2008-05-15 01:42:51.730578330 +0200
@@ -47,6 +47,7 @@
 #include "demangle.h"
 #include "value.h"
 #include "cp-abi.h"
+#include "target.h"
 
 /* Accumulate the minimal symbols for each objfile in bunches of BUNCH_SIZE.
    At the end, copy them all into one newly allocated location on an objfile's
@@ -1110,6 +1111,22 @@ find_solib_trampoline_target (struct fra
 	    && strcmp (SYMBOL_LINKAGE_NAME (msymbol),
 		       SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
 	  return SYMBOL_VALUE_ADDRESS (msymbol);
+
+	/* Also handle minimal symbols pointing to function descriptors.  */
+	if (MSYMBOL_TYPE (msymbol) == mst_data
+	    && strcmp (SYMBOL_LINKAGE_NAME (msymbol),
+		       SYMBOL_LINKAGE_NAME (tsymbol)) == 0)
+	  {
+	    CORE_ADDR func;
+	    func = gdbarch_convert_from_func_ptr_addr
+		    (get_objfile_arch (objfile),
+		     SYMBOL_VALUE_ADDRESS (msymbol),
+		     &current_target);
+
+	    /* Ignore data symbols that are not function descriptors.  */
+	    if (func != SYMBOL_VALUE_ADDRESS (msymbol))
+	      return func;
+	  }
       }
     }
   return 0;
diff -urNp gdb-orig/gdb/ppc-linux-tdep.c gdb-head/gdb/ppc-linux-tdep.c
--- gdb-orig/gdb/ppc-linux-tdep.c	2008-05-14 20:28:48.000000000 +0200
+++ gdb-head/gdb/ppc-linux-tdep.c	2008-05-15 00:59:48.168236097 +0200
@@ -440,7 +440,7 @@ ppc64_desc_entry_point (CORE_ADDR desc)
 /* Pattern for the standard linkage function.  These are built by
    build_plt_stub in elf64-ppc.c, whose GLINK argument is always
    zero.  */
-static struct insn_pattern ppc64_standard_linkage[] =
+static struct insn_pattern ppc64_standard_linkage1[] =
   {
     /* addis r12, r2, <any> */
     { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
@@ -452,17 +452,16 @@ static struct insn_pattern ppc64_standar
     { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
 
     /* addis r12, r12, 1 <optional> */
-    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 2, 1), 1 },
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
 
     /* ld r2, <any>(r12) */
     { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
 
     /* addis r12, r12, 1 <optional> */
-    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 2, 1), 1 },
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
 
     /* mtctr r11 */
-    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467),
-      0 },
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
 
     /* ld r11, <any>(r12) */
     { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
@@ -472,8 +471,68 @@ static struct insn_pattern ppc64_standar
 
     { 0, 0, 0 }
   };
-#define PPC64_STANDARD_LINKAGE_LEN \
-  (sizeof (ppc64_standard_linkage) / sizeof (ppc64_standard_linkage[0]))
+#define PPC64_STANDARD_LINKAGE1_LEN \
+  (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0]))
+
+static struct insn_pattern ppc64_standard_linkage2[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addi r12, r12, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+      
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+#define PPC64_STANDARD_LINKAGE2_LEN \
+  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
+
+static struct insn_pattern ppc64_standard_linkage3[] =
+  {
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
+
+    /* addi r2, r2, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
+      
+    /* ld r2, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+#define PPC64_STANDARD_LINKAGE3_LEN \
+  (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0]))
+
 
 /* When the dynamic linker is doing lazy symbol resolution, the first
    call to a function in another object will go like this:
@@ -522,8 +581,8 @@ static struct insn_pattern ppc64_standar
    standard linkage function will send them.  (This doesn't deal with
    dynamic linker lazy symbol resolution stubs.)  */
 static CORE_ADDR
-ppc64_standard_linkage_target (struct frame_info *frame,
-			       CORE_ADDR pc, unsigned int *insn)
+ppc64_standard_linkage1_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
 
@@ -539,20 +598,72 @@ ppc64_standard_linkage_target (struct fr
   return ppc64_desc_entry_point (desc);
 }
 
+static CORE_ADDR
+ppc64_standard_linkage2_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage3_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + insn_ds_field (insn[1]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (desc);
+}
+
 
 /* Given that we've begun executing a call trampoline at PC, return
    the entry point of the function the trampoline will go to.  */
 static CORE_ADDR
 ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
-  unsigned int ppc64_standard_linkage_insn[PPC64_STANDARD_LINKAGE_LEN];
-
-  if (insns_match_pattern (pc, ppc64_standard_linkage,
-                           ppc64_standard_linkage_insn))
-    return ppc64_standard_linkage_target (frame, pc,
-					  ppc64_standard_linkage_insn);
+  unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN];
+  unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN];
+  unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN];
+  CORE_ADDR target;
+
+  if (insns_match_pattern (pc, ppc64_standard_linkage1,
+                           ppc64_standard_linkage1_insn))
+    pc = ppc64_standard_linkage1_target (frame, pc,
+					 ppc64_standard_linkage1_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage2,
+				ppc64_standard_linkage2_insn))
+    pc = ppc64_standard_linkage2_target (frame, pc,
+					 ppc64_standard_linkage2_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage3,
+				ppc64_standard_linkage3_insn))
+    pc = ppc64_standard_linkage3_target (frame, pc,
+					 ppc64_standard_linkage3_insn);
   else
     return 0;
+
+  /* The PLT descriptor will either point to the already resolved target
+     address, or else to a glink stub.  As the latter carry synthetic @plt
+     symbols, find_solib_trampoline_target should be able to resolve them.  */
+  target = find_solib_trampoline_target (frame, pc);
+  return target? target : pc;
 }
 
 
-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]