Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [patch] fallback unwinder for hppa
@ 2004-05-04 15:24 Randolph Chung
  2004-05-07  1:19 ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Randolph Chung @ 2004-05-04 15:24 UTC (permalink / raw)
  To: gdb-patches

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/


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] fallback unwinder for hppa
  2004-05-04 15:24 [patch] fallback unwinder for hppa Randolph Chung
@ 2004-05-07  1:19 ` Andrew Cagney
  2004-05-07  2:38   ` Randolph Chung
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2004-05-07  1:19 UTC (permalink / raw)
  To: Randolph Chung; +Cc: gdb-patches

> +  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);
> +}

It should be possible to encode this information directly in the 
saved_regs array.  For instance, near the end, round:

> +  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);
>      }
> +

have:

    saved_regs[PCOQ_TAIL_REGNUM] = saved_regs[PCOQ_HEAD_REGNUM]

andrew




^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] fallback unwinder for hppa
  2004-05-07  1:19 ` Andrew Cagney
@ 2004-05-07  2:38   ` Randolph Chung
  2004-05-07 20:37     ` Andrew Cagney
  0 siblings, 1 reply; 4+ messages in thread
From: Randolph Chung @ 2004-05-07  2:38 UTC (permalink / raw)
  To: Andrew Cagney; +Cc: gdb-patches

> It should be possible to encode this information directly in the 
> saved_regs array.  For instance, near the end, round:
[...]
>    saved_regs[PCOQ_TAIL_REGNUM] = saved_regs[PCOQ_HEAD_REGNUM]

hrm? i don't see how that gives the same thing? we want an unwind of
PCOQ_TAIL_REGNUM to always return the value of PCOQ_HEAD_REGNUM + 4

randolph
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [patch] fallback unwinder for hppa
  2004-05-07  2:38   ` Randolph Chung
@ 2004-05-07 20:37     ` Andrew Cagney
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Cagney @ 2004-05-07 20:37 UTC (permalink / raw)
  To: Randolph Chung; +Cc: gdb-patches

>>It should be possible to encode this information directly in the 
>>> saved_regs array.  For instance, near the end, round:
> 
> [...]
> 
>>>    saved_regs[PCOQ_TAIL_REGNUM] = saved_regs[PCOQ_HEAD_REGNUM]
> 
> 
> hrm? i don't see how that gives the same thing? we want an unwind of
> PCOQ_TAIL_REGNUM to always return the value of PCOQ_HEAD_REGNUM + 4

Ah (it should be possible to encode that, but thats getting a bit beyond 
the current problem).

Ok then.

Andrew

> randolph



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2004-05-07 20:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-05-04 15:24 [patch] fallback unwinder for hppa Randolph Chung
2004-05-07  1:19 ` Andrew Cagney
2004-05-07  2:38   ` Randolph Chung
2004-05-07 20:37     ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox