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: Make PowerPC backtraces more robust


The PowerPC ABI is pretty explicit about the layout of the stack: if there
is a stack frame, the LR gets saved right after the backchain.  Various bits
of handwritten assembly that I've surveyed honor this convention, as does
GCC.  This patch takes advantage of that to handle backtraces in a couple of
cases that would otherwise be impossible.

This patch helps when there's no symbols available (-> frame_func_unwind
returns 0, skip_prologue does nothing), or where GDB can not handle a
prologue (e.g. assembly stubs which have a fast path which does not set up a
stack frame, falling back to a slow path which does).

It adds a simple heuristic: if the prologue analyzer did not find a stack
frame or a saved link register, then take a look at this frame's LR.  If it
points to the same address as the current PC, or if we can see that it
definitively points to somewhere in the current function, then we know that
the unwound LR is wrong, and/or the function really does have a frame.
If neither of those were true, the function would be recursive without a
stack frame.  So in this case, assume the ABI-mandated backchain and saved
LR.  We can't guess at saved registers, but having the stack is a big
improvement over not.

It seems to work very well.  I've regression tested it on powerpc64-linux
and manually checked some improved cases on powerpc-linux.

Comments?  OK?

-- 
Daniel Jacobowitz
CodeSourcery, LLC

2005-09-23  Daniel Jacobowitz  <dan@codesourcery.com>

	* rs6000-tdep.c (rs6000_frame_cache): Handle misdetected frameless
	functions.

Index: rs6000-tdep.c
===================================================================
RCS file: /big/fsf/rsync/src/src/gdb/rs6000-tdep.c,v
retrieving revision 1.243
diff -u -p -r1.243 rs6000-tdep.c
--- rs6000-tdep.c	19 Sep 2005 17:38:03 -0000	1.243
+++ rs6000-tdep.c	23 Sep 2005 18:26:39 -0000
@@ -2852,6 +2852,7 @@ rs6000_frame_cache (struct frame_info *n
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct rs6000_framedata fdata;
   int wordsize = tdep->wordsize;
+  CORE_ADDR func, pc;
 
   if ((*this_cache) != NULL)
     return (*this_cache);
@@ -2859,35 +2860,56 @@ rs6000_frame_cache (struct frame_info *n
   (*this_cache) = cache;
   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
-  skip_prologue (frame_func_unwind (next_frame), frame_pc_unwind (next_frame),
-		 &fdata);
+  func = frame_func_unwind (next_frame);
+  pc = frame_pc_unwind (next_frame);
+  skip_prologue (func, pc, &fdata);
+
+  /* Figure out the parent's stack pointer.  */
+
+  /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most
+     address of the current frame.  Things might be easier if the
+     ->frame pointed to the outer-most address of the frame.  In
+     the mean time, the address of the prev frame is used as the
+     base address of this frame.  */
+  cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
+
+  /* If the function appears to be frameless, check a couple of likely
+     indicators that we have simply failed to find the frame setup.
+     Two common cases of this are missing symbols (i.e.
+     frame_func_unwind returns the wrong address or 0), and assembly
+     stubs which have a fast exit path but set up a frame on the slow
+     path.
+
+     If the LR appears to return to this function, then presume that
+     we have an ABI compliant frame that we failed to find.  */
+  if (fdata.frameless && fdata.lr_offset == 0)
+    {
+      CORE_ADDR saved_lr;
+      int make_frame = 0;
+
+      func = frame_func_unwind (next_frame);
+      saved_lr = frame_unwind_register_unsigned (next_frame,
+						 tdep->ppc_lr_regnum);
+      if (func == 0 && saved_lr == pc)
+	make_frame = 1;
+      else if (func != 0)
+	{
+	  CORE_ADDR saved_func = get_pc_function_start (saved_lr);
+	  if (func == saved_func)
+	    make_frame = 1;
+	}
 
-  /* If there were any saved registers, figure out parent's stack
-     pointer.  */
-  /* The following is true only if the frame doesn't have a call to
-     alloca(), FIXME.  */
-
-  if (fdata.saved_fpr == 0
-      && fdata.saved_gpr == 0
-      && fdata.saved_vr == 0
-      && fdata.saved_ev == 0
-      && fdata.lr_offset == 0
-      && fdata.cr_offset == 0
-      && fdata.vr_offset == 0
-      && fdata.ev_offset == 0)
-    cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
-  else
-    {
-      /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most
-	 address of the current frame.  Things might be easier if the
-	 ->frame pointed to the outer-most address of the frame.  In
-	 the mean time, the address of the prev frame is used as the
-	 base address of this frame.  */
-      cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
-      if (!fdata.frameless)
-	/* Frameless really means stackless.  */
-	cache->base = read_memory_addr (cache->base, wordsize);
+      if (make_frame)
+	{
+	  fdata.frameless = 0;
+	  fdata.lr_offset = wordsize;
+	}
     }
+
+  if (!fdata.frameless)
+    /* Frameless really means stackless.  */
+    cache->base = read_memory_addr (cache->base, wordsize);
+
   trad_frame_set_value (cache->saved_regs, SP_REGNUM, cache->base);
 
   /* if != -1, fdata.saved_fpr is the smallest number of saved_fpr.


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