This is the mail archive of the gdb-patches@sources.redhat.com 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]

[patch] fallback unwinder for hppa


This introduces one more frame unwinder for hppa which can handle functions
that have no unwind information encoded by the toolchain.  This might 
conceivably be handled as a "stub", but currently the stub unwinder assumes the
frame does not alter the stack or store the return pointer on the stack. The
new unwinder handles those cases as well.  This is needed for example on for
hand-written assembly routines that have no unwind information, or for some
glibc syscall wrappers on hppa-linux. Previously the unwinder will notice that 
there is no unwind information and then return an incorrect frame cache in 
those cases. We only use this unwinder as a last resort, as it is probably 
slow and not very accurate.

cvs diff makes the patch a bit difficult to read, hopefully the changelog is 
clear :)

comments?

randolph

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

	* hppa-tdep.c (hppa_frame_prev_register_helper): New function to 
	do common handling of the pcoqt register.
	(hppa_frame_prev_register, hppa_stub_frame_prev_register): Convert
	to use helper function.
	(hppa_frame_unwind_sniffer): Only use if unwind entry is present.
	(hppa_fallback_frame_cache, hppa_fallback_frame_this_id)
	(hppa_fallback_frame_prev_register, hppa_fallback_frame_unwind): New
	generic fallback unwinder when all else fails.
	(hppa_gdbarch_init): Add fallback sniffer.
	* hppa-tdep.h (hppa_frame_prev_register_helper): Prototype.
	* hppa-linux-tdep.c (hppa_linux_sigtramp_frame_prev_register): Convert
	to use helper function.

Index: hppa-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.c,v
retrieving revision 1.153
diff -u -p -r1.153 hppa-tdep.c
--- hppa-tdep.c	29 Apr 2004 03:36:49 -0000	1.153
+++ hppa-tdep.c	4 May 2004 15:08:17 -0000
@@ -1856,55 +1893,136 @@ hppa_frame_this_id (struct frame_info *n
 
 static void
 hppa_frame_prev_register (struct frame_info *next_frame,
-				 void **this_cache,
-				 int regnum, int *optimizedp,
-				 enum lval_type *lvalp, CORE_ADDR *addrp,
-				 int *realnump, void *valuep)
+			  void **this_cache,
+			  int regnum, int *optimizedp,
+			  enum lval_type *lvalp, CORE_ADDR *addrp,
+			  int *realnump, void *valuep)
 {
   struct hppa_frame_cache *info = hppa_frame_cache (next_frame, this_cache);
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  if (regnum == PCOQ_TAIL_REGNUM)
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+		                   optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_frame_unwind =
+{
+  NORMAL_FRAME,
+  hppa_frame_this_id,
+  hppa_frame_prev_register
+};
+
+static const struct frame_unwind *
+hppa_frame_unwind_sniffer (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+  if (find_unwind_entry (pc))
+    return &hppa_frame_unwind;
+
+  return NULL;
+}
+
+/* This is a generic fallback frame unwinder that kicks in if we fail all
+   the other ones.  Normally we would expect the stub and regular unwinder
+   to work, but in some cases we might hit a function that just doesn't
+   have any unwind information available.  In this case we try to do
+   unwinding solely based on code reading.  This is obviously going to be
+   slow, so only use this as a last resort.  Currently this will only
+   identify the stack and pc for the frame.  */
+
+static struct hppa_frame_cache *
+hppa_fallback_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct hppa_frame_cache *cache;
+  CORE_ADDR pc, start_pc, end_pc, cur_pc;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct hppa_frame_cache);
+  (*this_cache) = cache;
+  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+  pc = frame_func_unwind (next_frame);
+  cur_pc = frame_pc_unwind (next_frame);
+
+  find_pc_partial_function (pc, NULL, &start_pc, &end_pc);
+
+  if (start_pc == 0 || end_pc == 0)
+    {
+      error ("Cannot find bounds of current function (@0x%s), unwinding will "
+	     "fail.", paddr_nz (pc));
+      return cache;
+    }
+
+  if (end_pc > cur_pc)
+    end_pc = cur_pc;
+
+  for (pc = start_pc; pc < end_pc; pc += 4)
     {
-      /* The PCOQ TAIL, or NPC, needs to be computed from the unwound
-	 PC register.  */
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = 0;
-      if (valuep)
+      unsigned int insn;
+
+      insn = read_memory_unsigned_integer (pc, 4);
+
+      /* There are limited ways to store the return pointer into the
+	 stack.  */
+      if (insn == 0x6bc23fd9) /* stw rp,-0x14(sr0,sp) */
+	{
+	  cache->saved_regs[RP_REGNUM].addr = -20;
+	  break;
+	}
+      else if (insn == 0x0fc212c1) /* std rp,-0x10(sr0,sp) */
 	{
-	  int regsize = register_size (gdbarch, PCOQ_HEAD_REGNUM);
-	  CORE_ADDR pc;
-	  int optimized;
-	  enum lval_type lval;
-	  CORE_ADDR addr;
-	  int realnum;
-	  bfd_byte value[MAX_REGISTER_SIZE];
-	  trad_frame_prev_register (next_frame, info->saved_regs,
-				    PCOQ_HEAD_REGNUM, &optimized, &lval, &addr,
-				    &realnum, &value);
-	  pc = extract_unsigned_integer (&value, regsize);
-	  store_unsigned_integer (valuep, regsize, pc + 4);
+	  cache->saved_regs[RP_REGNUM].addr = -16;
+	  break;
 	}
     }
+
+  cache->base = frame_unwind_register_unsigned (next_frame, HPPA_SP_REGNUM);
+
+  if (trad_frame_addr_p (cache->saved_regs, RP_REGNUM))
+    {
+      cache->saved_regs[RP_REGNUM].addr += cache->base;
+      cache->saved_regs[PCOQ_HEAD_REGNUM] = cache->saved_regs[RP_REGNUM];
+    }
   else
     {
-      trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-				optimizedp, lvalp, addrp, realnump, valuep);
+      ULONGEST rp = frame_unwind_register_unsigned (next_frame, RP_REGNUM);
+      trad_frame_set_value (cache->saved_regs, PCOQ_HEAD_REGNUM, rp);
     }
+
+  return cache;
 }
 
-static const struct frame_unwind hppa_frame_unwind =
+static void
+hppa_fallback_frame_this_id (struct frame_info *next_frame, void **this_cache,
+			     struct frame_id *this_id)
+{
+  struct hppa_frame_cache *info = 
+    hppa_fallback_frame_cache (next_frame, this_cache);
+  (*this_id) = frame_id_build (info->base, frame_func_unwind (next_frame));
+}
+
+static void
+hppa_fallback_frame_prev_register (struct frame_info *next_frame,
+			  void **this_cache,
+			  int regnum, int *optimizedp,
+			  enum lval_type *lvalp, CORE_ADDR *addrp,
+			  int *realnump, void *valuep)
+{
+  struct hppa_frame_cache *info = 
+    hppa_fallback_frame_cache (next_frame, this_cache);
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+		                   optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind hppa_fallback_frame_unwind =
 {
   NORMAL_FRAME,
-  hppa_frame_this_id,
-  hppa_frame_prev_register
+  hppa_fallback_frame_this_id,
+  hppa_fallback_frame_prev_register
 };
 
 static const struct frame_unwind *
-hppa_frame_unwind_sniffer (struct frame_info *next_frame)
+hppa_fallback_unwind_sniffer (struct frame_info *next_frame)
 {
-  return &hppa_frame_unwind;
+  return &hppa_fallback_frame_unwind;
 }
 
 static CORE_ADDR
@@ -1971,23 +2089,12 @@ hppa_stub_frame_prev_register (struct fr
 			       void **this_prologue_cache,
 			       int regnum, int *optimizedp,
 			       enum lval_type *lvalp, CORE_ADDR *addrp,
-			       int *realnump, void *bufferp)
+			       int *realnump, void *valuep)
 {
   struct hppa_stub_unwind_cache *info
     = hppa_stub_frame_unwind_cache (next_frame, this_prologue_cache);
-  int pcoqt = (regnum == PCOQ_TAIL_REGNUM);
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  int regsize = register_size (gdbarch, PCOQ_HEAD_REGNUM);
-
-  if (pcoqt)
-    regnum = PCOQ_HEAD_REGNUM;
-
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
-
-  if (pcoqt)
-    store_unsigned_integer (bufferp, regsize, 
-		      	    extract_unsigned_integer (bufferp, regsize) + 4);
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+		                   optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static const struct frame_unwind hppa_stub_frame_unwind = {
@@ -2230,6 +2337,34 @@ hppa_pseudo_register_read (struct gdbarc
     store_unsigned_integer (buf, sizeof(tmp), tmp);
 }
 
+void
+hppa_frame_prev_register_helper (struct frame_info *next_frame,
+			         struct trad_frame_saved_reg saved_regs[],
+				 int regnum, int *optimizedp,
+				 enum lval_type *lvalp, CORE_ADDR *addrp,
+				 int *realnump, void *valuep)
+{
+  int pcoqt = (regnum == PCOQ_TAIL_REGNUM);
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  int regsize = register_size (gdbarch, PCOQ_HEAD_REGNUM);
+
+  if (pcoqt)
+    regnum = PCOQ_HEAD_REGNUM;
+
+  trad_frame_prev_register (next_frame, saved_regs, regnum,
+                            optimizedp, lvalp, addrp, realnump, valuep);
+
+  if (pcoqt)
+    store_unsigned_integer (valuep, regsize, 
+		      	    extract_unsigned_integer (valuep, regsize) + 4);
+}
+
 /* Here is a table of C type sizes on hppa with various compiles
    and options.  I measured this on PA 9000/800 with HP-UX 11.11
    and these compilers:
@@ -2391,6 +2530,7 @@ hppa_gdbarch_init (struct gdbarch_info i
   /* Hook in the default unwinders.  */
   frame_unwind_append_sniffer (gdbarch, hppa_stub_unwind_sniffer);
   frame_unwind_append_sniffer (gdbarch, hppa_frame_unwind_sniffer);
+  frame_unwind_append_sniffer (gdbarch, hppa_fallback_unwind_sniffer);
   frame_base_append_sniffer (gdbarch, hppa_frame_base_sniffer);
 
   return gdbarch;
Index: hppa-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/hppa-tdep.h,v
retrieving revision 1.4
diff -u -p -r1.4 hppa-tdep.h
--- hppa-tdep.h	23 Apr 2004 02:54:21 -0000	1.4
+++ hppa-tdep.h	4 May 2004 15:09:31 -0000
@@ -145,5 +149,12 @@ int hppa_extract_21 (unsigned);
 int hppa_extract_14 (unsigned);
 int hppa_low_sign_extend (unsigned int, unsigned int);
 int hppa_sign_extend (unsigned int, unsigned int);
+
+void
+hppa_frame_prev_register_helper (struct frame_info *next_frame,
+			         struct trad_frame_saved_reg saved_regs[],
+				 int regnum, int *optimizedp,
+				 enum lval_type *lvalp, CORE_ADDR *addrp,
+				 int *realnump, void *valuep);
 
 #endif  /* HPPA_TDEP_H */
Index: hppa-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/hppa-linux-tdep.c,v
retrieving revision 1.1
diff -u -p -r1.1 hppa-linux-tdep.c
--- hppa-linux-tdep.c	29 Apr 2004 03:36:49 -0000	1.1
+++ hppa-linux-tdep.c	4 May 2004 15:09:31 -0000
@@ -415,21 +433,12 @@ hppa_linux_sigtramp_frame_prev_register 
 					 int regnum, int *optimizedp,
 					 enum lval_type *lvalp, 
 					 CORE_ADDR *addrp,
-					 int *realnump, void *bufferp)
+					 int *realnump, void *valuep)
 {
   struct hppa_linux_sigtramp_unwind_cache *info
     = hppa_linux_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
-  int pcoqt = (regnum == PCOQ_TAIL_REGNUM);
-
-  if (pcoqt)
-    regnum = PCOQ_HEAD_REGNUM;
-
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
-
-  if (pcoqt)
-    store_unsigned_integer (bufferp, 4, 
-		      	    extract_unsigned_integer (bufferp, 4) + 4);
+  hppa_frame_prev_register_helper (next_frame, info->saved_regs, regnum,
+		                   optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static const struct frame_unwind hppa_linux_sigtramp_frame_unwind = {
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/


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