public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
@ 2011-02-22 18:35 Pedro Alves
  2011-02-28 15:42 ` Jan Kratochvil
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Pedro Alves @ 2011-02-22 18:35 UTC (permalink / raw)
  To: gdb-patches

This patch applies on top of the "unavailable regs/locals"
series, starting at:
<http://sourceware.org/ml/gdb-patches/2011-02/msg00581.html>.

This teaches GDB about terminating unwinding gracefully if
unwind further we would need registers/memory that haven't
been collected.

Here's the result:

 (gdb) bt
 #0  begin (a=<unavailable>) at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:182
 #1  0x00000000004008ad in main (argc=1, argv=0x7fff0e22cf28, envp=0x7fff0e22cf38)
     at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:210
 #2  <unavailable> in ?? ()
 Backtrace stopped: Not enough registers or memory available to unwind further

I think I've implemented this differently in about 10
different ways.  This is the design that I ended up with and
that I think is best.

 - when we sniff unwinders trying to find a matching unwinder,
   we catch NOT_AVAILABLE_ERRORS.  If the PC is unavailable, 
   it is impossible to determine if a given non-prologue parser unwinder
   would have been the best unwinder or not.  By catching
   NOT_AVAILABLE_ERRORS, we don't have too touch many sniffers.
   When sniffing, they just read whatever minimum data they
   require to determine they're the correct unwinder.  If
   any of that is unavailable, we'll hit an exception.  So what
   this means is that sniffer code does not try to check if a
   given _required_ value is available --- it just goes ahead and
   reads it.

 - adds a new frame_unwind method, to make it possible for an unwinder
   to tell the core frame code that it can't unwind further.  The
   concept here, is that if we are able to tell a given unwinder
   would be the best unwinder, select it, even if actually trying to
   unwind from it wouldn't work due to unavailable data.  E.g., if
   all we have available is the PC, we'll be able to tell that we
   have dwarf unwind info for that frame.  But if we then find out
   that we don't have enough registers/memory to compute the CFA, we know
   we aren't going to be able to unwind.  We _don't_ fallback to
   prologue parsing in such cases, since if we couldn't unwind with
   the precise unwind info missing, prologue parsing is surely not
   going to be able to unwind correctly.

 - this new method incidently allows cleanly reporting to the core
   frame machinery when a frame is the outermost, without resorting
   to hacks in the frame_id, which opens the door to fixing a
   corner case with stepping through the outermost frame when there's
   no debug info.  I won't be implementing that, it just paves the way.

 - the prologue parsers then need to be made aware that they may trip
   on necessary registers (e.g., PC / SP / FP) unavailable to unwine,
   and that they should return that they can't unwind further in
   the new frame_unwind method in that case.  I've taught the x86
   and x64_64 unwinders, but not all others.  I did do the mechanical
   work of adjusting all of them to the new interface, so that
   --enable-targets=all still builds, and so that they continue working
   as today.  Theaching other prologue unwinders how to terminate
   gracefully with UNWIND_UNAVAILABLE is only interesting when a
   corresponding target supports tracepoints on that architecture, so
   it can be enabled on a case by case basis.

-- 
Pedro Alves

2012-02-22  Pedro Alves  <pedro@codesourcery.com>

	gdb/
	* frame.c (frame_unwind_register): Throw an error if unwinding the
	register failed.
	* get_prev_frame_1 (get_prev_frame_1): Ask the unwinder if there's
	an unwind stop reason.
	(frame_stop_reason_string): Handle UNWIND_UNAVAILABLE.
	* frame.h (enum unwind_stop_reason) <UNWIND_OUTERMOST,
	UNWIND_UNAVAILABLE>: New.
	* inline-frame.c (inline_frame_unwind): Install
	default_frame_unwind_stop_reason.
	* frame-unwind.c: Include "exceptions.h".
	(frame_unwind_find_by_frame): Swallow NOT_AVAILABLE_ERROR errors.
	(default_frame_unwind_stop_reason): New.
	* frame-unwind.h (frame_unwind_stop_reason_ftype): New typedef.
	(default_frame_unwind_stop_reason): Declare.
	(struct frame_unwind) <stop_reason>: New function pointer.

	* dummy-frame.c: Install default_frame_unwind_stop_reason.
	* dwarf2-frame.c: Include exceptions.h.
	(struct dwarf2_frame_cache) <unavailable_retaddr>: New field.
	(dwarf2_frame_cache): Swallow NOT_AVAILABLE_ERROR errors when
	computing the CFA.  If such an error was thrown, set
	unavailable_retaddr.
	(dwarf2_frame_unwind_stop_reason): New.
	(dwarf2_frame_this_id): Don't build a frame id if the CFA was
	unavailable.
	(dwarf2_frame_unwind): Install dwarf2_frame_unwind_stop_reason.
	(dwarf2_signal_frame_unwind): Ditto.

	* amd64-tdep.c: Include "exceptions.h".
	(struct amd64_frame_cache): New field "base_p".
	(amd64_init_frame_cache): Clear it.
	(amd64_frame_cache_1): New, factored out from amd64_frame_cache.
	Avoid reading registers with functions that throw if the register
	is not necessary to compute the frame base.
	(amd64_frame_cache): Reimplement wrapping amd64_frame_cache_1, and
	swallowing NOT_AVAILABLE_ERROR.
	(amd64_frame_unwind_stop_reason): New.
	(amd64_frame_this_id): Don't build a frame id if the frame base
	was unavailable.
	(amd64_frame_unwind): Install amd64_frame_unwind_stop_reason.
	(amd64_sigtramp_frame_cache): Swallow NOT_AVAILABLE_ERROR, and set
	base_p if the frame base was computable.
	(amd64_sigtramp_frame_unwind_stop_reason): New.
	(amd64_sigtramp_frame_this_id): Don't build a frame id if the
	frame base was unavailable.
	(amd64_sigtramp_frame_unwind): Install
	amd64_sigtramp_frame_unwind_stop_reason.
	(amd64_epilogue_frame_cache): Swallow NOT_AVAILABLE_ERROR, and set
	base_p if the frame base was computable.
	(amd64_epilogue_frame_unwind_stop_reason): New.
	(amd64_epilogue_frame_this_id): Don't build a frame id if the
	frame base was unavailable.
	(amd64_epilogue_frame_unwind): Install
	amd64_epilogue_frame_unwind_stop_reason.
	* i386-tdep.c: Include "exceptions.h".
	(struct i386_frame_cache): New field "base_p".
	(i386_init_frame_cache): Clear it.
	(i386_frame_cache_1): New, factored out from amd64_frame_cache.
	Avoid reading registers with functions that throw if the register
	is not necessary to compute the frame base.
	(i386_frame_cache): Reimplement wrapping amd64_frame_cache_1, and
	swallowing NOT_AVAILABLE_ERROR.
	(i386_frame_unwind_stop_reason): New.
	(i386_frame_this_id): Don't build a frame id if the frame base was
	unavailable.
	(i386_frame_prev_register): Handle unavailable SP.
	(i386_frame_unwind): Install i386_frame_unwind_stop_reason.
	(i386_epilogue_frame_cache): Swallow NOT_AVAILABLE_ERROR, and set
	base_p if the frame base was computable.
	(i386_epilogue_frame_unwind_stop_reason): New.
	(i386_epilogue_frame_this_id): Don't build a frame id if the frame
	base was unavailable.
	(i386_epilogue_frame_unwind): Install
	i386_epilogue_frame_unwind_stop_reason.
	(i386_sigtramp_frame_cache): Swallow NOT_AVAILABLE_ERROR, and set
	base_p if the frame base was computable.
	(i386_sigtramp_frame_unwind_stop_reason): New.
	(i386_sigtramp_frame_this_id): Don't build a frame id if the frame
	base was unavailable.
	(i386_sigtramp_frame_unwind): Install
	i386_sigtramp_frame_unwind_stop_reason.
	* sentinel-frame.c (sentinel_frame_prev_register): Use the value
	type's size, not the register's.
	(sentinel_frame_unwind): Install default_frame_unwind_stop_reason.

	* alpha-mdebug-tdep.c (alpha_mdebug_frame_unwind): Install
	default_frame_unwind_stop_reason.
	* alpha-tdep.c (alpha_sigtramp_frame_unwind)
	(alpha_heuristic_frame_unwind): Ditto.
	* amd64obsd-tdep.c (amd64obsd_trapframe_unwind): Ditto.
	* arm-tdep.c (arm_prologue_unwind, arm_stub_unwind): Ditto.
	* avr-tdep.c (avr_frame_unwind): Ditto.
	* cris-tdep.c (cris_sigtramp_frame_unwind, cris_frame_unwind):
	Ditto.
	* frv-linux-tdep.c (frv_linux_sigtramp_frame_unwind): Ditto.
	* frv-tdep.c (frv_frame_unwind): Ditto.
	* h8300-tdep.c (h8300_frame_unwind): Ditto.
	* hppa-hpux-tdep.c (hppa_hpux_sigtramp_frame_unwind): Ditto.
	* hppa-linux-tdep.c (hppa_linux_sigtramp_frame_unwind): Ditto.
	* hppa-tdep.c (hppa_frame_unwind, hppa_fallback_frame_unwind)
	(hppa_stub_frame_unwind): Ditto.
	* i386obsd-tdep.c (i386obsd_trapframe_unwind): Ditto.
	* ia64-tdep.c (ia64_frame_unwind, ia64_sigtramp_frame_unwind)
	(ia64_libunwind_frame_unwind)
	(ia64_libunwind_sigtramp_frame_unwind): Ditto.
	* iq2000-tdep.c (iq2000_frame_unwind): Ditto.
	* lm32-tdep.c (lm32_frame_unwind): Ditto.
	* m32c-tdep.c (m32c_unwind): Ditto.
	* m32r-linux-tdep.c (m32r_linux_sigtramp_frame_unwind): Ditto.
	* m32r-tdep.c (m32r_frame_unwind): Ditto.
	* m68hc11-tdep.c (m68hc11_frame_unwind): Ditto.
	* m68k-tdep.c (m68k_frame_unwind): Ditto.
	* m68klinux-tdep.c (m68k_linux_sigtramp_frame_unwind): Ditto.
	* m88k-tdep.c (m88k_frame_unwind): Ditto.
	* mep-tdep.c (mep_frame_unwind): Ditto.
	* microblaze-tdep.c (microblaze_frame_unwind): Ditto.
	* mips-tdep.c (mips_insn16_frame_unwind, mips_insn32_frame_unwind)
	(mips_stub_frame_unwind): Ditto.
	* mn10300-tdep.c (mn10300_frame_unwind): Ditto.
	* moxie-tdep.c (moxie_frame_unwind): Ditto.
	* mt-tdep.c (mt_frame_unwind): Ditto.
	* ppc-linux-tdep.c (ppu2spu_unwind): Ditto.
	* ppcobsd-tdep.c (ppcobsd_sigtramp_frame_unwind): Ditto.
	* rs6000-tdep.c (rs6000_frame_unwind): Ditto.
	* s390-tdep.c (s390_frame_unwind, s390_stub_frame_unwind)
	(s390_sigtramp_frame_unwind): Ditto.
	* score-tdep.c (score_prologue_unwind): Ditto.
	* sh-tdep.c (sh_frame_unwind): Ditto.
	* sh64-tdep.c (sh64_frame_unwind): Ditto.
	* sparc-sol2-tdep.c (sparc32_sol2_sigtramp_frame_unwind): Ditto.
	* sparc-tdep.c (sparc32_frame_unwind): Ditto.
	* sparc64-sol2-tdep.c (sparc64_sol2_sigtramp_frame_unwind): Ditto.
	* sparc64-tdep.c (sparc64_frame_unwind): Ditto.
	* sparc64fbsd-tdep.c (sparc64fbsd_sigtramp_frame_unwind): Ditto.
	* sparc64nbsd-tdep.c (sparc64nbsd_sigcontext_frame_unwind): Ditto.
	* sparc64obsd-tdep.c (sparc64obsd_frame_unwind)
	(sparc64obsd_trapframe_unwind): Ditto.
	* sparcnbsd-tdep.c (sparc32nbsd_sigcontext_frame_unwind): Ditto.
	* sparcobsd-tdep.c (sparc32obsd_sigtramp_frame_unwind): Ditto.
	* spu-tdep.c (spu_frame_unwind, spu2ppu_unwind): Ditto.
	* v850-tdep.c (v850_frame_unwind): Ditto.
	* vax-tdep.c (vax_frame_unwind): Ditto.
	* vaxobsd-tdep.c (vaxobsd_sigtramp_frame_unwind): Ditto.
	* xstormy16-tdep.c (frame_unwind xstormy16_frame_unwind): Ditto.
	* xtensa-tdep.c (xtensa_unwind): Ditto.

---
 gdb/alpha-mdebug-tdep.c |    1 
 gdb/alpha-tdep.c        |    2 
 gdb/amd64-tdep.c        |  156 ++++++++++++++++++++++++++++++--------
 gdb/amd64obsd-tdep.c    |    1 
 gdb/arm-tdep.c          |    3 
 gdb/avr-tdep.c          |    1 
 gdb/bfin-tdep.c         |    1 
 gdb/cris-tdep.c         |    2 
 gdb/dummy-frame.c       |    1 
 gdb/dwarf2-frame.c      |   79 ++++++++++++++-----
 gdb/frame-unwind.c      |   37 +++++++--
 gdb/frame-unwind.h      |   11 ++
 gdb/frame.c             |   18 ++++
 gdb/frame.h             |    7 +
 gdb/frv-linux-tdep.c    |    1 
 gdb/frv-tdep.c          |    1 
 gdb/h8300-tdep.c        |    1 
 gdb/hppa-hpux-tdep.c    |    1 
 gdb/hppa-linux-tdep.c   |    1 
 gdb/hppa-tdep.c         |    3 
 gdb/i386-tdep.c         |  193 ++++++++++++++++++++++++++++++++++++------------
 gdb/i386obsd-tdep.c     |    1 
 gdb/ia64-tdep.c         |    4 
 gdb/inline-frame.c      |    1 
 gdb/iq2000-tdep.c       |    1 
 gdb/lm32-tdep.c         |    1 
 gdb/m32c-tdep.c         |    1 
 gdb/m32r-linux-tdep.c   |    1 
 gdb/m32r-tdep.c         |    1 
 gdb/m68hc11-tdep.c      |    1 
 gdb/m68k-tdep.c         |    1 
 gdb/m68klinux-tdep.c    |    1 
 gdb/m88k-tdep.c         |    1 
 gdb/mep-tdep.c          |    1 
 gdb/microblaze-tdep.c   |    1 
 gdb/mips-tdep.c         |    3 
 gdb/mn10300-tdep.c      |    1 
 gdb/moxie-tdep.c        |    1 
 gdb/mt-tdep.c           |    1 
 gdb/ppc-linux-tdep.c    |    1 
 gdb/ppcobsd-tdep.c      |    1 
 gdb/rs6000-tdep.c       |    1 
 gdb/s390-tdep.c         |    3 
 gdb/score-tdep.c        |    1 
 gdb/sentinel-frame.c    |    6 -
 gdb/sh-tdep.c           |    1 
 gdb/sh64-tdep.c         |    1 
 gdb/sparc-sol2-tdep.c   |    1 
 gdb/sparc-tdep.c        |    1 
 gdb/sparc64-sol2-tdep.c |    1 
 gdb/sparc64-tdep.c      |    1 
 gdb/sparc64fbsd-tdep.c  |    1 
 gdb/sparc64nbsd-tdep.c  |    1 
 gdb/sparc64obsd-tdep.c  |    2 
 gdb/sparcnbsd-tdep.c    |    1 
 gdb/sparcobsd-tdep.c    |    1 
 gdb/spu-tdep.c          |    2 
 gdb/v850-tdep.c         |    1 
 gdb/vax-tdep.c          |    1 
 gdb/vaxobsd-tdep.c      |    1 
 gdb/xstormy16-tdep.c    |    1 
 gdb/xtensa-tdep.c       |    1 
 62 files changed, 468 insertions(+), 108 deletions(-)

Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2011-02-22 17:57:50.000000000 +0000
+++ src/gdb/frame.c	2011-02-22 17:58:04.244708001 +0000
@@ -912,6 +912,12 @@ frame_unwind_register (struct frame_info
 
   frame_register_unwind (frame, regnum, &optimized, &unavailable,
 			 &lval, &addr, &realnum, buf);
+
+  if (optimized)
+    error (_("Register %d was optimized out"), regnum);
+  if (unavailable)
+    throw_error (NOT_AVAILABLE_ERROR,
+		 _("Register %d is not available"), regnum);
 }
 
 void
@@ -1599,6 +1605,15 @@ get_prev_frame_1 (struct frame_info *thi
   if (get_frame_type (this_frame) == INLINE_FRAME)
     return get_prev_frame_raw (this_frame);
 
+  /* Check that this frame is unwindable.  If it isn't, don't try to
+     unwind to the prev frame.  */
+  this_frame->stop_reason
+    = this_frame->unwind->stop_reason (this_frame,
+				       &this_frame->prologue_cache);
+
+  if (this_frame->stop_reason != UNWIND_NO_REASON)
+    return NULL;
+
   /* Check that this frame's ID was valid.  If it wasn't, don't try to
      unwind to the prev frame.  Be careful to not apply this test to
      the sentinel frame.  */
@@ -2323,6 +2338,9 @@ frame_stop_reason_string (enum unwind_st
     case UNWIND_NULL_ID:
       return _("unwinder did not report frame ID");
 
+    case UNWIND_UNAVAILABLE:
+      return _("Not enough registers or memory available to unwind further");
+
     case UNWIND_INNER_ID:
       return _("previous frame inner to this frame (corrupt stack?)");
 
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2011-02-22 17:57:50.000000000 +0000
+++ src/gdb/frame.h	2011-02-22 17:58:04.244708001 +0000
@@ -454,12 +454,19 @@ enum unwind_stop_reason
        error.  But that's a project for another day.  */
     UNWIND_NULL_ID,
 
+    /* This frame is the outermost.  */
+    UNWIND_OUTERMOST,
+
     /* All the conditions after this point are considered errors;
        abnormal stack termination.  If a backtrace stops for one
        of these reasons, we'll let the user know.  This marker
        is not a valid stop reason.  */
     UNWIND_FIRST_ERROR,
 
+    /* Can't unwind further, because that would require knowing the
+       values of registers or memory that haven't been collected.  */
+    UNWIND_UNAVAILABLE,
+
     /* This frame ID looks like it ought to belong to a NEXT frame,
        but we got it for a PREV frame.  Normally, this is a sign of
        unwinder failure.  It could also indicate stack corruption.  */
Index: src/gdb/inline-frame.c
===================================================================
--- src.orig/gdb/inline-frame.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/inline-frame.c	2011-02-22 17:58:04.244708001 +0000
@@ -260,6 +260,7 @@ inline_frame_sniffer (const struct frame
 
 const struct frame_unwind inline_frame_unwind = {
   INLINE_FRAME,
+  default_frame_unwind_stop_reason,
   inline_frame_this_id,
   inline_frame_prev_register,
   NULL,
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/frame-unwind.c	2011-02-22 17:58:04.244708001 +0000
@@ -25,7 +25,7 @@
 #include "inline-frame.h"
 #include "value.h"
 #include "regcache.h"
-
+#include "exceptions.h"
 #include "gdb_assert.h"
 #include "gdb_obstack.h"
 
@@ -103,14 +103,31 @@ frame_unwind_find_by_frame (struct frame
   for (entry = table->list; entry != NULL; entry = entry->next)
     {
       struct cleanup *old_cleanup;
+      volatile struct gdb_exception ex;
+      int res = 0;
 
       old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
-      if (entry->unwinder->sniffer (entry->unwinder, this_frame,
-				    this_cache))
+
+      TRY_CATCH (ex, RETURN_MASK_ERROR)
 	{
-	  discard_cleanups (old_cleanup);
-	  return;
+	  res = entry->unwinder->sniffer (entry->unwinder, this_frame,
+					  this_cache);
 	}
+      if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR)
+	{
+	  /* This usually means that not even the PC is available,
+	     thus most unwinders aren't able to determine if they're
+	     the best fit.  Keep trying.  Fallback prologue unwinders
+	     should always accept the frame.  */
+	}
+      else if (ex.reason < 0)
+	throw_exception (ex);
+      else if (res)
+        {
+          discard_cleanups (old_cleanup);
+          return;
+        }
+
       do_cleanups (old_cleanup);
     }
   internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
@@ -127,6 +144,16 @@ default_frame_sniffer (const struct fram
   return 1;
 }
 
+/* A default frame unwinder stop_reason callback that always claims
+   the frame is unwindable.  */
+
+enum unwind_stop_reason
+default_frame_unwind_stop_reason (struct frame_info *this_frame,
+				  void **this_cache)
+{
+  return UNWIND_NO_REASON;
+}
+
 /* Helper functions for value-based register unwinding.  These return
    a (possibly lazy) value of the appropriate type.  */
 
Index: src/gdb/dwarf2-frame.c
===================================================================
--- src.orig/gdb/dwarf2-frame.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/dwarf2-frame.c	2011-02-22 17:58:04.254708002 +0000
@@ -40,6 +40,7 @@
 #include "dwarf2-frame.h"
 #include "ax.h"
 #include "dwarf2loc.h"
+#include "exceptions.h"
 
 struct comp_unit;
 
@@ -986,6 +987,10 @@ struct dwarf2_frame_cache
   /* DWARF Call Frame Address.  */
   CORE_ADDR cfa;
 
+  /* Set if the return address column was marked as unavailable
+     (required non-collected memory or registers to compute).  */
+  int unavailable_retaddr;
+
   /* Set if the return address column was marked as undefined.  */
   int undefined_retaddr;
 
@@ -1013,6 +1018,7 @@ dwarf2_frame_cache (struct frame_info *t
   struct dwarf2_frame_cache *cache;
   struct dwarf2_frame_state *fs;
   struct dwarf2_fde *fde;
+  volatile struct gdb_exception ex;
 
   if (*this_cache)
     return *this_cache;
@@ -1020,10 +1026,10 @@ dwarf2_frame_cache (struct frame_info *t
   /* Allocate a new cache.  */
   cache = FRAME_OBSTACK_ZALLOC (struct dwarf2_frame_cache);
   cache->reg = FRAME_OBSTACK_CALLOC (num_regs, struct dwarf2_frame_state_reg);
+  *this_cache = cache;
 
   /* Allocate and initialize the frame state.  */
-  fs = XMALLOC (struct dwarf2_frame_state);
-  memset (fs, 0, sizeof (struct dwarf2_frame_state));
+  fs = XZALLOC (struct dwarf2_frame_state);
   old_chain = make_cleanup (dwarf2_frame_state_free, fs);
 
   /* Unwind the PC.
@@ -1068,26 +1074,39 @@ dwarf2_frame_cache (struct frame_info *t
   execute_cfa_program (fde, fde->instructions, fde->end, gdbarch,
 		       get_frame_pc (this_frame), fs);
 
-  /* Calculate the CFA.  */
-  switch (fs->regs.cfa_how)
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
     {
-    case CFA_REG_OFFSET:
-      cache->cfa = read_reg (this_frame, fs->regs.cfa_reg);
-      if (fs->armcc_cfa_offsets_reversed)
-	cache->cfa -= fs->regs.cfa_offset;
-      else
-	cache->cfa += fs->regs.cfa_offset;
-      break;
+      /* Calculate the CFA.  */
+      switch (fs->regs.cfa_how)
+	{
+	case CFA_REG_OFFSET:
+	  cache->cfa = read_reg (this_frame, fs->regs.cfa_reg);
+	  if (fs->armcc_cfa_offsets_reversed)
+	    cache->cfa -= fs->regs.cfa_offset;
+	  else
+	    cache->cfa += fs->regs.cfa_offset;
+	  break;
+
+	case CFA_EXP:
+	  cache->cfa =
+	    execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len,
+			      cache->addr_size, cache->text_offset,
+			      this_frame, 0, 0);
+	  break;
 
-    case CFA_EXP:
-      cache->cfa =
-	execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len,
-			  cache->addr_size, cache->text_offset,
-			  this_frame, 0, 0);
-      break;
+	default:
+	  internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+	}
+    }
+  if (ex.reason < 0)
+    {
+      if (ex.error == NOT_AVAILABLE_ERROR)
+	{
+	  cache->unavailable_retaddr = 1;
+	  return cache;
+	}
 
-    default:
-      internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
+      throw_exception (ex);
     }
 
   /* Initialize the register state.  */
@@ -1193,10 +1212,25 @@ incomplete CFI data; unspecified registe
 
   do_cleanups (old_chain);
 
-  *this_cache = cache;
   return cache;
 }
 
+static enum unwind_stop_reason
+dwarf2_frame_unwind_stop_reason (struct frame_info *this_frame,
+				 void **this_cache)
+{
+  struct dwarf2_frame_cache *cache
+    = dwarf2_frame_cache (this_frame, this_cache);
+
+  if (cache->unavailable_retaddr)
+    return UNWIND_UNAVAILABLE;
+
+  if (cache->undefined_retaddr)
+    return UNWIND_OUTERMOST;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
 		      struct frame_id *this_id)
@@ -1204,6 +1238,9 @@ dwarf2_frame_this_id (struct frame_info
   struct dwarf2_frame_cache *cache =
     dwarf2_frame_cache (this_frame, this_cache);
 
+  if (cache->unavailable_retaddr)
+    return;
+
   if (cache->undefined_retaddr)
     return;
 
@@ -1321,6 +1358,7 @@ dwarf2_frame_sniffer (const struct frame
 static const struct frame_unwind dwarf2_frame_unwind =
 {
   NORMAL_FRAME,
+  dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
   NULL,
@@ -1330,6 +1368,7 @@ static const struct frame_unwind dwarf2_
 static const struct frame_unwind dwarf2_signal_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  dwarf2_frame_unwind_stop_reason,
   dwarf2_frame_this_id,
   dwarf2_frame_prev_register,
   NULL,
Index: src/gdb/amd64-tdep.c
===================================================================
--- src.orig/gdb/amd64-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/amd64-tdep.c	2011-02-22 17:58:04.254708002 +0000
@@ -38,7 +38,7 @@
 #include "symfile.h"
 #include "disasm.h"
 #include "gdb_assert.h"
-
+#include "exceptions.h"
 #include "amd64-tdep.h"
 #include "i387-tdep.h"
 
@@ -1628,6 +1628,7 @@ struct amd64_frame_cache
 {
   /* Base address.  */
   CORE_ADDR base;
+  int base_p;
   CORE_ADDR sp_offset;
   CORE_ADDR pc;
 
@@ -1649,6 +1650,7 @@ amd64_init_frame_cache (struct amd64_fra
 
   /* Base address.  */
   cache->base = 0;
+  cache->base_p = 0;
   cache->sp_offset = -8;
   cache->pc = 0;
 
@@ -1906,33 +1908,20 @@ amd64_skip_prologue (struct gdbarch *gdb
 
 /* Normal frames.  */
 
-static struct amd64_frame_cache *
-amd64_frame_cache (struct frame_info *this_frame, void **this_cache)
+static void
+amd64_frame_cache_1 (struct frame_info *this_frame,
+		     struct amd64_frame_cache *cache)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  struct amd64_frame_cache *cache;
   gdb_byte buf[8];
   int i;
 
-  if (*this_cache)
-    return *this_cache;
-
-  cache = amd64_alloc_frame_cache ();
-  *this_cache = cache;
-
   cache->pc = get_frame_func (this_frame);
   if (cache->pc != 0)
     amd64_analyze_prologue (gdbarch, cache->pc, get_frame_pc (this_frame),
 			    cache);
 
-  if (cache->saved_sp_reg != -1)
-    {
-      /* Stack pointer has been saved.  */
-      get_frame_register (this_frame, cache->saved_sp_reg, buf);
-      cache->saved_sp = extract_unsigned_integer(buf, 8, byte_order);
-    }
-
   if (cache->frameless_p)
     {
       /* We didn't find a valid frame.  If we're at the start of a
@@ -1944,6 +1933,10 @@ amd64_frame_cache (struct frame_info *th
 
       if (cache->saved_sp_reg != -1)
 	{
+	  /* Stack pointer has been saved.  */
+	  get_frame_register (this_frame, cache->saved_sp_reg, buf);
+	  cache->saved_sp = extract_unsigned_integer (buf, 8, byte_order);
+
 	  /* We're halfway aligning the stack.  */
 	  cache->base = ((cache->saved_sp - 8) & 0xfffffffffffffff0LL) - 8;
 	  cache->saved_regs[AMD64_RIP_REGNUM] = cache->saved_sp - 8;
@@ -1981,9 +1974,48 @@ amd64_frame_cache (struct frame_info *th
     if (cache->saved_regs[i] != -1)
       cache->saved_regs[i] += cache->base;
 
+  cache->base_p = 1;
+}
+
+static struct amd64_frame_cache *
+amd64_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  volatile struct gdb_exception ex;
+  struct amd64_frame_cache *cache;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = amd64_alloc_frame_cache ();
+  *this_cache = cache;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      amd64_frame_cache_1 (this_frame, cache);
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
+
   return cache;
 }
 
+static enum unwind_stop_reason
+amd64_frame_unwind_stop_reason (struct frame_info *this_frame,
+				void **this_cache)
+{
+  struct amd64_frame_cache *cache =
+    amd64_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return UNWIND_OUTERMOST;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 amd64_frame_this_id (struct frame_info *this_frame, void **this_cache,
 		     struct frame_id *this_id)
@@ -1991,6 +2023,9 @@ amd64_frame_this_id (struct frame_info *
   struct amd64_frame_cache *cache =
     amd64_frame_cache (this_frame, this_cache);
 
+  if (!cache->base_p)
+    return;
+
   /* This marks the outermost frame.  */
   if (cache->base == 0)
     return;
@@ -2021,6 +2056,7 @@ amd64_frame_prev_register (struct frame_
 static const struct frame_unwind amd64_frame_unwind =
 {
   NORMAL_FRAME,
+  amd64_frame_unwind_stop_reason,
   amd64_frame_this_id,
   amd64_frame_prev_register,
   NULL,
@@ -2040,6 +2076,7 @@ amd64_sigtramp_frame_cache (struct frame
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct amd64_frame_cache *cache;
   CORE_ADDR addr;
   gdb_byte buf[8];
@@ -2050,20 +2087,40 @@ amd64_sigtramp_frame_cache (struct frame
 
   cache = amd64_alloc_frame_cache ();
 
-  get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 8, byte_order) - 8;
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 8, byte_order) - 8;
+
+      addr = tdep->sigcontext_addr (this_frame);
+      gdb_assert (tdep->sc_reg_offset);
+      gdb_assert (tdep->sc_num_regs <= AMD64_NUM_SAVED_REGS);
+      for (i = 0; i < tdep->sc_num_regs; i++)
+	if (tdep->sc_reg_offset[i] != -1)
+	  cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
 
-  addr = tdep->sigcontext_addr (this_frame);
-  gdb_assert (tdep->sc_reg_offset);
-  gdb_assert (tdep->sc_num_regs <= AMD64_NUM_SAVED_REGS);
-  for (i = 0; i < tdep->sc_num_regs; i++)
-    if (tdep->sc_reg_offset[i] != -1)
-      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+      cache->base_p = 1;
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   *this_cache = cache;
   return cache;
 }
 
+static enum unwind_stop_reason
+amd64_sigtramp_frame_unwind_stop_reason (struct frame_info *this_frame,
+					 void **this_cache)
+{
+  struct amd64_frame_cache *cache =
+    amd64_sigtramp_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 amd64_sigtramp_frame_this_id (struct frame_info *this_frame,
 			      void **this_cache, struct frame_id *this_id)
@@ -2071,6 +2128,9 @@ amd64_sigtramp_frame_this_id (struct fra
   struct amd64_frame_cache *cache =
     amd64_sigtramp_frame_cache (this_frame, this_cache);
 
+  if (!cache->base_p)
+    return;
+
   (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame));
 }
 
@@ -2117,6 +2177,7 @@ amd64_sigtramp_frame_sniffer (const stru
 static const struct frame_unwind amd64_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  amd64_sigtramp_frame_unwind_stop_reason,
   amd64_sigtramp_frame_this_id,
   amd64_sigtramp_frame_prev_register,
   NULL,
@@ -2178,6 +2239,7 @@ amd64_epilogue_frame_cache (struct frame
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct amd64_frame_cache *cache;
   gdb_byte buf[8];
 
@@ -2187,23 +2249,43 @@ amd64_epilogue_frame_cache (struct frame
   cache = amd64_alloc_frame_cache ();
   *this_cache = cache;
 
-  /* Cache base will be %esp plus cache->sp_offset (-8).  */
-  get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 8, 
-					  byte_order) + cache->sp_offset;
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Cache base will be %esp plus cache->sp_offset (-8).  */
+      get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 8,
+					      byte_order) + cache->sp_offset;
+
+      /* Cache pc will be the frame func.  */
+      cache->pc = get_frame_pc (this_frame);
 
-  /* Cache pc will be the frame func.  */
-  cache->pc = get_frame_pc (this_frame);
+      /* The saved %esp will be at cache->base plus 16.  */
+      cache->saved_sp = cache->base + 16;
 
-  /* The saved %esp will be at cache->base plus 16.  */
-  cache->saved_sp = cache->base + 16;
+      /* The saved %eip will be at cache->base plus 8.  */
+      cache->saved_regs[AMD64_RIP_REGNUM] = cache->base + 8;
 
-  /* The saved %eip will be at cache->base plus 8.  */
-  cache->saved_regs[AMD64_RIP_REGNUM] = cache->base + 8;
+      cache->base_p = 1;
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   return cache;
 }
 
+static enum unwind_stop_reason
+amd64_epilogue_frame_unwind_stop_reason (struct frame_info *this_frame,
+					 void **this_cache)
+{
+  struct amd64_frame_cache *cache
+    = amd64_epilogue_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 amd64_epilogue_frame_this_id (struct frame_info *this_frame,
 			      void **this_cache,
@@ -2212,12 +2294,16 @@ amd64_epilogue_frame_this_id (struct fra
   struct amd64_frame_cache *cache = amd64_epilogue_frame_cache (this_frame,
 							       this_cache);
 
+  if (!cache->base_p)
+    return;
+
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
 static const struct frame_unwind amd64_epilogue_frame_unwind =
 {
   NORMAL_FRAME,
+  amd64_epilogue_frame_unwind_stop_reason,
   amd64_epilogue_frame_this_id,
   amd64_frame_prev_register,
   NULL, 
Index: src/gdb/dummy-frame.c
===================================================================
--- src.orig/gdb/dummy-frame.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/dummy-frame.c	2011-02-22 17:58:04.254708002 +0000
@@ -278,6 +278,7 @@ dummy_frame_this_id (struct frame_info *
 const struct frame_unwind dummy_frame_unwind =
 {
   DUMMY_FRAME,
+  default_frame_unwind_stop_reason,
   dummy_frame_this_id,
   dummy_frame_prev_register,
   NULL,
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h	2011-02-22 17:45:30.000000000 +0000
+++ src/gdb/frame-unwind.h	2011-02-22 17:58:04.254708002 +0000
@@ -51,6 +51,9 @@ typedef int (frame_sniffer_ftype) (const
 				   struct frame_info *this_frame,
 				   void **this_prologue_cache);
 
+typedef enum unwind_stop_reason (frame_unwind_stop_reason_ftype)
+  (struct frame_info *this_frame, void **this_prologue_cache);
+
 /* A default frame sniffer which always accepts the frame.  Used by
    fallback prologue unwinders.  */
 
@@ -58,6 +61,13 @@ int default_frame_sniffer (const struct
 			   struct frame_info *this_frame,
 			   void **this_prologue_cache);
 
+/* A default stop_reason callback which always claims the frame is
+   unwindable.  */
+
+enum unwind_stop_reason
+  default_frame_unwind_stop_reason (struct frame_info *this_frame,
+				    void **this_cache);
+
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
    use THIS frame, and through it the NEXT frame's register unwind
    method, to determine the frame ID of THIS frame.
@@ -136,6 +146,7 @@ struct frame_unwind
   enum frame_type type;
   /* Should an attribute indicating the frame's address-in-block go
      here?  */
+  frame_unwind_stop_reason_ftype *stop_reason;
   frame_this_id_ftype *this_id;
   frame_prev_register_ftype *prev_register;
   const struct frame_data *unwind_data;
Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/i386-tdep.c	2011-02-22 17:58:04.254708002 +0000
@@ -45,7 +45,7 @@
 #include "dis-asm.h"
 #include "disasm.h"
 #include "remote.h"
-
+#include "exceptions.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
 
@@ -797,6 +797,7 @@ struct i386_frame_cache
 {
   /* Base address.  */
   CORE_ADDR base;
+  int base_p;
   LONGEST sp_offset;
   CORE_ADDR pc;
 
@@ -821,6 +822,7 @@ i386_alloc_frame_cache (void)
   cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
 
   /* Base address.  */
+  cache->base_p = 0;
   cache->base = 0;
   cache->sp_offset = -4;
   cache->pc = 0;
@@ -1577,20 +1579,16 @@ i386_unwind_pc (struct gdbarch *gdbarch,
 
 /* Normal frames.  */
 
-static struct i386_frame_cache *
-i386_frame_cache (struct frame_info *this_frame, void **this_cache)
+static void
+i386_frame_cache_1 (struct frame_info *this_frame,
+		    struct i386_frame_cache *cache)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  struct i386_frame_cache *cache;
   gdb_byte buf[4];
   int i;
 
-  if (*this_cache)
-    return *this_cache;
-
-  cache = i386_alloc_frame_cache ();
-  *this_cache = cache;
+  cache->pc = get_frame_func (this_frame);
 
   /* In principle, for normal frames, %ebp holds the frame pointer,
      which holds the base address for the current stack frame.
@@ -1604,23 +1602,15 @@ i386_frame_cache (struct frame_info *thi
   get_frame_register (this_frame, I386_EBP_REGNUM, buf);
   cache->base = extract_unsigned_integer (buf, 4, byte_order);
   if (cache->base == 0)
-    return cache;
+    return;
 
   /* For normal frames, %eip is stored at 4(%ebp).  */
   cache->saved_regs[I386_EIP_REGNUM] = 4;
 
-  cache->pc = get_frame_func (this_frame);
   if (cache->pc != 0)
     i386_analyze_prologue (gdbarch, cache->pc, get_frame_pc (this_frame),
 			   cache);
 
-  if (cache->saved_sp_reg != -1)
-    {
-      /* Saved stack pointer has been saved.  */
-      get_frame_register (this_frame, cache->saved_sp_reg, buf);
-      cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);
-    }
-
   if (cache->locals < 0)
     {
       /* We didn't find a valid frame, which means that CACHE->base
@@ -1633,6 +1623,10 @@ i386_frame_cache (struct frame_info *thi
 
       if (cache->saved_sp_reg != -1)
 	{
+	  /* Saved stack pointer has been saved.  */
+	  get_frame_register (this_frame, cache->saved_sp_reg, buf);
+	  cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);
+
 	  /* We're halfway aligning the stack.  */
 	  cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4;
 	  cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4;
@@ -1660,9 +1654,17 @@ i386_frame_cache (struct frame_info *thi
 	cache->saved_regs[I386_EBP_REGNUM] = 0;
     }
 
+  if (cache->saved_sp_reg != -1)
+    {
+      /* Saved stack pointer has been saved (but the SAVED_SP_REG
+	 register may be unavailable).  */
+      if (cache->saved_sp == 0
+	  && frame_register_read (this_frame, cache->saved_sp_reg, buf))
+	cache->saved_sp = extract_unsigned_integer (buf, 4, byte_order);
+    }
   /* Now that we have the base address for the stack frame we can
      calculate the value of %esp in the calling frame.  */
-  if (cache->saved_sp == 0)
+  else if (cache->saved_sp == 0)
     cache->saved_sp = cache->base + 8;
 
   /* Adjust all the saved registers such that they contain addresses
@@ -1671,6 +1673,28 @@ i386_frame_cache (struct frame_info *thi
     if (cache->saved_regs[i] != -1)
       cache->saved_regs[i] += cache->base;
 
+  cache->base_p = 1;
+}
+
+static struct i386_frame_cache *
+i386_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  volatile struct gdb_exception ex;
+  struct i386_frame_cache *cache;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = i386_alloc_frame_cache ();
+  *this_cache = cache;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      i386_frame_cache_1 (this_frame, cache);
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
+
   return cache;
 }
 
@@ -1688,6 +1712,22 @@ i386_frame_this_id (struct frame_info *t
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
+static enum unwind_stop_reason
+i386_frame_unwind_stop_reason (struct frame_info *this_frame,
+			       void **this_cache)
+{
+  struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return UNWIND_OUTERMOST;
+
+  return UNWIND_NO_REASON;
+}
+
 static struct value *
 i386_frame_prev_register (struct frame_info *this_frame, void **this_cache,
 			  int regnum)
@@ -1727,8 +1767,18 @@ i386_frame_prev_register (struct frame_i
   if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
     return frame_unwind_got_register (this_frame, regnum, I386_EAX_REGNUM);
 
-  if (regnum == I386_ESP_REGNUM && cache->saved_sp)
-    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
+  if (regnum == I386_ESP_REGNUM)
+    {
+      /* If the SP has been saved, but we don't know where, then this
+	 means that SAVED_SP_REG register was found unavailable back
+	 when we built the cache.  */
+      if (cache->saved_sp == 0 && cache->saved_sp_reg != -1)
+	return frame_unwind_got_register (this_frame, regnum,
+					  cache->saved_sp_reg);
+      else
+	return frame_unwind_got_constant (this_frame, regnum,
+					  cache->saved_sp);
+    }
 
   if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
     return frame_unwind_got_memory (this_frame, regnum,
@@ -1740,6 +1790,7 @@ i386_frame_prev_register (struct frame_i
 static const struct frame_unwind i386_frame_unwind =
 {
   NORMAL_FRAME,
+  i386_frame_unwind_stop_reason,
   i386_frame_this_id,
   i386_frame_prev_register,
   NULL,
@@ -1783,6 +1834,7 @@ i386_epilogue_frame_cache (struct frame_
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct i386_frame_cache *cache;
   gdb_byte buf[4];
 
@@ -1792,23 +1844,43 @@ i386_epilogue_frame_cache (struct frame_
   cache = i386_alloc_frame_cache ();
   *this_cache = cache;
 
-  /* Cache base will be %esp plus cache->sp_offset (-4).  */
-  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 4, 
-					  byte_order) + cache->sp_offset;
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* Cache base will be %esp plus cache->sp_offset (-4).  */
+      get_frame_register (this_frame, I386_ESP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 4,
+					      byte_order) + cache->sp_offset;
+
+      /* Cache pc will be the frame func.  */
+      cache->pc = get_frame_pc (this_frame);
 
-  /* Cache pc will be the frame func.  */
-  cache->pc = get_frame_pc (this_frame);
+      /* The saved %esp will be at cache->base plus 8.  */
+      cache->saved_sp = cache->base + 8;
 
-  /* The saved %esp will be at cache->base plus 8.  */
-  cache->saved_sp = cache->base + 8;
+      /* The saved %eip will be at cache->base plus 4.  */
+      cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
 
-  /* The saved %eip will be at cache->base plus 4.  */
-  cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+      cache->base_p = 1;
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   return cache;
 }
 
+static enum unwind_stop_reason
+i386_epilogue_frame_unwind_stop_reason (struct frame_info *this_frame,
+					void **this_cache)
+{
+  struct i386_frame_cache *cache
+    = i386_epilogue_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 i386_epilogue_frame_this_id (struct frame_info *this_frame,
 			     void **this_cache,
@@ -1817,12 +1889,16 @@ i386_epilogue_frame_this_id (struct fram
   struct i386_frame_cache *cache = i386_epilogue_frame_cache (this_frame,
 							      this_cache);
 
+  if (!cache->base_p)
+    return;
+
   (*this_id) = frame_id_build (cache->base + 8, cache->pc);
 }
 
 static const struct frame_unwind i386_epilogue_frame_unwind =
 {
   NORMAL_FRAME,
+  i386_epilogue_frame_unwind_stop_reason,
   i386_epilogue_frame_this_id,
   i386_frame_prev_register,
   NULL, 
@@ -1838,6 +1914,7 @@ i386_sigtramp_frame_cache (struct frame_
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  volatile struct gdb_exception ex;
   struct i386_frame_cache *cache;
   CORE_ADDR addr;
   gdb_byte buf[4];
@@ -1847,30 +1924,50 @@ i386_sigtramp_frame_cache (struct frame_
 
   cache = i386_alloc_frame_cache ();
 
-  get_frame_register (this_frame, I386_ESP_REGNUM, buf);
-  cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;
-
-  addr = tdep->sigcontext_addr (this_frame);
-  if (tdep->sc_reg_offset)
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
     {
-      int i;
+      get_frame_register (this_frame, I386_ESP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 4, byte_order) - 4;
 
-      gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
+      addr = tdep->sigcontext_addr (this_frame);
+      if (tdep->sc_reg_offset)
+	{
+	  int i;
 
-      for (i = 0; i < tdep->sc_num_regs; i++)
-	if (tdep->sc_reg_offset[i] != -1)
-	  cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
-    }
-  else
-    {
-      cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
-      cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+	  gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
+
+	  for (i = 0; i < tdep->sc_num_regs; i++)
+	    if (tdep->sc_reg_offset[i] != -1)
+	      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+	}
+      else
+	{
+	  cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
+	  cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+	}
+
+      cache->base_p = 1;
     }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   *this_cache = cache;
   return cache;
 }
 
+static enum unwind_stop_reason
+i386_sigtramp_frame_unwind_stop_reason (struct frame_info *this_frame,
+					void **this_cache)
+{
+  struct i386_frame_cache *cache =
+    i386_sigtramp_frame_cache (this_frame, this_cache);
+
+  if (!cache->base_p)
+    return UNWIND_UNAVAILABLE;
+
+  return UNWIND_NO_REASON;
+}
+
 static void
 i386_sigtramp_frame_this_id (struct frame_info *this_frame, void **this_cache,
 			     struct frame_id *this_id)
@@ -1878,6 +1975,9 @@ i386_sigtramp_frame_this_id (struct fram
   struct i386_frame_cache *cache =
     i386_sigtramp_frame_cache (this_frame, this_cache);
 
+  if (!cache->base_p)
+    return;
+
   /* See the end of i386_push_dummy_call.  */
   (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame));
 }
@@ -1925,6 +2025,7 @@ i386_sigtramp_frame_sniffer (const struc
 static const struct frame_unwind i386_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  i386_sigtramp_frame_unwind_stop_reason,
   i386_sigtramp_frame_this_id,
   i386_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c	2011-02-22 17:57:48.000000000 +0000
+++ src/gdb/sentinel-frame.c	2011-02-22 17:58:04.264708003 +0000
@@ -51,9 +51,10 @@ sentinel_frame_prev_register (struct fra
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_cache *cache = *this_prologue_cache;
   struct value *value;
+  struct type *regtype = register_type (gdbarch, regnum);
 
   /* Return the actual value.  */
-  value = allocate_value (register_type (gdbarch, regnum));
+  value = allocate_value (regtype);
   VALUE_LVAL (value) = lval_register;
   VALUE_REGNUM (value) = regnum;
   VALUE_FRAME_ID (value) = get_frame_id (this_frame);
@@ -64,7 +65,7 @@ sentinel_frame_prev_register (struct fra
   if (regcache_cooked_read (cache->regcache,
 			    regnum,
 			    value_contents_raw (value)) == REG_UNAVAILABLE)
-    mark_value_bytes_unavailable (value, 0, register_size (gdbarch, regnum));
+    mark_value_bytes_unavailable (value, 0, TYPE_LENGTH (regtype));
 
   return value;
 }
@@ -92,6 +93,7 @@ sentinel_frame_prev_arch (struct frame_i
 const struct frame_unwind sentinel_frame_unwind =
 {
   SENTINEL_FRAME,
+  default_frame_unwind_stop_reason,
   sentinel_frame_this_id,
   sentinel_frame_prev_register,
   NULL,
Index: src/gdb/alpha-mdebug-tdep.c
===================================================================
--- src.orig/gdb/alpha-mdebug-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/alpha-mdebug-tdep.c	2011-02-22 17:58:04.264708003 +0000
@@ -336,6 +336,7 @@ alpha_mdebug_frame_sniffer (const struct
 
 static const struct frame_unwind alpha_mdebug_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   alpha_mdebug_frame_this_id,
   alpha_mdebug_frame_prev_register,
   NULL,
Index: src/gdb/alpha-tdep.c
===================================================================
--- src.orig/gdb/alpha-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/alpha-tdep.c	2011-02-22 17:58:04.264708003 +0000
@@ -936,6 +936,7 @@ alpha_sigtramp_frame_sniffer (const stru
 
 static const struct frame_unwind alpha_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   alpha_sigtramp_frame_this_id,
   alpha_sigtramp_frame_prev_register,
   NULL,
@@ -1351,6 +1352,7 @@ alpha_heuristic_frame_prev_register (str
 
 static const struct frame_unwind alpha_heuristic_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   alpha_heuristic_frame_this_id,
   alpha_heuristic_frame_prev_register,
   NULL,
Index: src/gdb/amd64obsd-tdep.c
===================================================================
--- src.orig/gdb/amd64obsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/amd64obsd-tdep.c	2011-02-22 17:58:04.264708003 +0000
@@ -437,6 +437,7 @@ static const struct frame_unwind amd64ob
      frame, but SIGTRAMP_FRAME would print <signal handler called>,
      which really is not what we want here.  */
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   amd64obsd_trapframe_this_id,
   amd64obsd_trapframe_prev_register,
   NULL,
Index: src/gdb/arm-tdep.c
===================================================================
--- src.orig/gdb/arm-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/arm-tdep.c	2011-02-22 17:58:04.264708003 +0000
@@ -2146,6 +2146,7 @@ arm_prologue_prev_register (struct frame
 
 struct frame_unwind arm_prologue_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
   NULL,
@@ -2884,6 +2885,7 @@ arm_exidx_unwind_sniffer (const struct f
 
 struct frame_unwind arm_exidx_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_prologue_this_id,
   arm_prologue_prev_register,
   NULL,
@@ -2939,6 +2941,7 @@ arm_stub_unwind_sniffer (const struct fr
 
 struct frame_unwind arm_stub_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   arm_stub_this_id,
   arm_prologue_prev_register,
   NULL,
Index: src/gdb/avr-tdep.c
===================================================================
--- src.orig/gdb/avr-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/avr-tdep.c	2011-02-22 17:58:04.264708003 +0000
@@ -1131,6 +1131,7 @@ avr_frame_prev_register (struct frame_in
 
 static const struct frame_unwind avr_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   avr_frame_this_id,
   avr_frame_prev_register,
   NULL,
Index: src/gdb/cris-tdep.c
===================================================================
--- src.orig/gdb/cris-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/cris-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -448,6 +448,7 @@ cris_sigtramp_frame_sniffer (const struc
 static const struct frame_unwind cris_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   cris_sigtramp_frame_this_id,
   cris_sigtramp_frame_prev_register,
   NULL,
@@ -985,6 +986,7 @@ cris_push_dummy_call (struct gdbarch *gd
 static const struct frame_unwind cris_frame_unwind = 
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   cris_frame_this_id,
   cris_frame_prev_register,
   NULL,
Index: src/gdb/frv-linux-tdep.c
===================================================================
--- src.orig/gdb/frv-linux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/frv-linux-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -336,6 +336,7 @@ frv_linux_sigtramp_frame_sniffer (const
 static const struct frame_unwind frv_linux_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   frv_linux_sigtramp_frame_this_id,
   frv_linux_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/frv-tdep.c
===================================================================
--- src.orig/gdb/frv-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/frv-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -1494,6 +1494,7 @@ frv_frame_prev_register (struct frame_in
 
 static const struct frame_unwind frv_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   frv_frame_this_id,
   frv_frame_prev_register,
   NULL,
Index: src/gdb/h8300-tdep.c
===================================================================
--- src.orig/gdb/h8300-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/h8300-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -526,6 +526,7 @@ h8300_frame_prev_register (struct frame_
 
 static const struct frame_unwind h8300_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   h8300_frame_this_id,
   h8300_frame_prev_register,
   NULL,
Index: src/gdb/hppa-hpux-tdep.c
===================================================================
--- src.orig/gdb/hppa-hpux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/hppa-hpux-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -753,6 +753,7 @@ hppa_hpux_sigtramp_unwind_sniffer (const
 
 static const struct frame_unwind hppa_hpux_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   hppa_hpux_sigtramp_frame_this_id,
   hppa_hpux_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/hppa-linux-tdep.c
===================================================================
--- src.orig/gdb/hppa-linux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/hppa-linux-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -314,6 +314,7 @@ hppa_linux_sigtramp_frame_sniffer (const
 
 static const struct frame_unwind hppa_linux_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   hppa_linux_sigtramp_frame_this_id,
   hppa_linux_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/hppa-tdep.c
===================================================================
--- src.orig/gdb/hppa-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/hppa-tdep.c	2011-02-22 17:58:04.274708004 +0000
@@ -2225,6 +2225,7 @@ hppa_frame_unwind_sniffer (const struct
 static const struct frame_unwind hppa_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   hppa_frame_this_id,
   hppa_frame_prev_register,
   NULL,
@@ -2335,6 +2336,7 @@ hppa_fallback_frame_prev_register (struc
 static const struct frame_unwind hppa_fallback_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   hppa_fallback_frame_this_id,
   hppa_fallback_frame_prev_register,
   NULL,
@@ -2431,6 +2433,7 @@ hppa_stub_unwind_sniffer (const struct f
 
 static const struct frame_unwind hppa_stub_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   hppa_stub_frame_this_id,
   hppa_stub_frame_prev_register,
   NULL,
Index: src/gdb/i386obsd-tdep.c
===================================================================
--- src.orig/gdb/i386obsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/i386obsd-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -434,6 +434,7 @@ static const struct frame_unwind i386obs
      frame, but SIGTRAMP_FRAME would print <signal handler called>,
      which really is not what we want here.  */
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   i386obsd_trapframe_this_id,
   i386obsd_trapframe_prev_register,
   NULL,
Index: src/gdb/ia64-tdep.c
===================================================================
--- src.orig/gdb/ia64-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/ia64-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -2175,6 +2175,7 @@ ia64_frame_prev_register (struct frame_i
 static const struct frame_unwind ia64_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   &ia64_frame_this_id,
   &ia64_frame_prev_register,
   NULL,
@@ -2366,6 +2367,7 @@ ia64_sigtramp_frame_sniffer (const struc
 static const struct frame_unwind ia64_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_sigtramp_frame_this_id,
   ia64_sigtramp_frame_prev_register,
   NULL,
@@ -3051,6 +3053,7 @@ ia64_libunwind_frame_sniffer (const stru
 static const struct frame_unwind ia64_libunwind_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_libunwind_frame_this_id,
   ia64_libunwind_frame_prev_register,
   NULL,
@@ -3139,6 +3142,7 @@ ia64_libunwind_sigtramp_frame_sniffer (c
 static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   ia64_libunwind_sigtramp_frame_this_id,
   ia64_libunwind_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/iq2000-tdep.c
===================================================================
--- src.orig/gdb/iq2000-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/iq2000-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -436,6 +436,7 @@ iq2000_frame_this_id (struct frame_info
 
 static const struct frame_unwind iq2000_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   iq2000_frame_this_id,
   iq2000_frame_prev_register,
   NULL,
Index: src/gdb/lm32-tdep.c
===================================================================
--- src.orig/gdb/lm32-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/lm32-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -496,6 +496,7 @@ lm32_frame_prev_register (struct frame_i
 
 static const struct frame_unwind lm32_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   lm32_frame_this_id,
   lm32_frame_prev_register,
   NULL,
Index: src/gdb/m32c-tdep.c
===================================================================
--- src.orig/gdb/m32c-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/m32c-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -1960,6 +1960,7 @@ m32c_prev_register (struct frame_info *t
 
 static const struct frame_unwind m32c_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   m32c_this_id,
   m32c_prev_register,
   NULL,
Index: src/gdb/m32r-linux-tdep.c
===================================================================
--- src.orig/gdb/m32r-linux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/m32r-linux-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -305,6 +305,7 @@ m32r_linux_sigtramp_frame_sniffer (const
 
 static const struct frame_unwind m32r_linux_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   m32r_linux_sigtramp_frame_this_id,
   m32r_linux_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/m32r-tdep.c
===================================================================
--- src.orig/gdb/m32r-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/m32r-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -876,6 +876,7 @@ m32r_frame_prev_register (struct frame_i
 
 static const struct frame_unwind m32r_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   m32r_frame_this_id,
   m32r_frame_prev_register,
   NULL,
Index: src/gdb/m68hc11-tdep.c
===================================================================
--- src.orig/gdb/m68hc11-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/m68hc11-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -949,6 +949,7 @@ m68hc11_frame_prev_register (struct fram
 
 static const struct frame_unwind m68hc11_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   m68hc11_frame_this_id,
   m68hc11_frame_prev_register,
   NULL,
Index: src/gdb/m68k-tdep.c
===================================================================
--- src.orig/gdb/m68k-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/m68k-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -976,6 +976,7 @@ m68k_frame_prev_register (struct frame_i
 static const struct frame_unwind m68k_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   m68k_frame_this_id,
   m68k_frame_prev_register,
   NULL,
Index: src/gdb/m68klinux-tdep.c
===================================================================
--- src.orig/gdb/m68klinux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/m68klinux-tdep.c	2011-02-22 17:58:04.284708000 +0000
@@ -328,6 +328,7 @@ m68k_linux_sigtramp_frame_sniffer (const
 static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   m68k_linux_sigtramp_frame_this_id,
   m68k_linux_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/m88k-tdep.c
===================================================================
--- src.orig/gdb/m88k-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/m88k-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -749,6 +749,7 @@ m88k_frame_prev_register (struct frame_i
 static const struct frame_unwind m88k_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   m88k_frame_this_id,
   m88k_frame_prev_register,
   NULL,
Index: src/gdb/mep-tdep.c
===================================================================
--- src.orig/gdb/mep-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/mep-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -2094,6 +2094,7 @@ mep_frame_prev_register (struct frame_in
 
 static const struct frame_unwind mep_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mep_frame_this_id,
   mep_frame_prev_register,
   NULL,
Index: src/gdb/microblaze-tdep.c
===================================================================
--- src.orig/gdb/microblaze-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/microblaze-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -521,6 +521,7 @@ microblaze_frame_prev_register (struct f
 static const struct frame_unwind microblaze_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   microblaze_frame_this_id,
   microblaze_frame_prev_register,
   NULL,
Index: src/gdb/mips-tdep.c
===================================================================
--- src.orig/gdb/mips-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/mips-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -2028,6 +2028,7 @@ mips_insn16_frame_sniffer (const struct
 static const struct frame_unwind mips_insn16_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mips_insn16_frame_this_id,
   mips_insn16_frame_prev_register,
   NULL,
@@ -2381,6 +2382,7 @@ mips_insn32_frame_sniffer (const struct
 static const struct frame_unwind mips_insn32_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mips_insn32_frame_this_id,
   mips_insn32_frame_prev_register,
   NULL,
@@ -2505,6 +2507,7 @@ mips_stub_frame_sniffer (const struct fr
 static const struct frame_unwind mips_stub_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mips_stub_frame_this_id,
   mips_stub_frame_prev_register,
   NULL,
Index: src/gdb/mn10300-tdep.c
===================================================================
--- src.orig/gdb/mn10300-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/mn10300-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -1174,6 +1174,7 @@ mn10300_frame_prev_register (struct fram
 
 static const struct frame_unwind mn10300_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mn10300_frame_this_id, 
   mn10300_frame_prev_register,
   NULL,
Index: src/gdb/moxie-tdep.c
===================================================================
--- src.orig/gdb/moxie-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/moxie-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -461,6 +461,7 @@ moxie_frame_prev_register (struct frame_
 
 static const struct frame_unwind moxie_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   moxie_frame_this_id,
   moxie_frame_prev_register,
   NULL,
Index: src/gdb/mt-tdep.c
===================================================================
--- src.orig/gdb/mt-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/mt-tdep.c	2011-02-22 17:58:04.294708001 +0000
@@ -1115,6 +1115,7 @@ mt_frame_base_address (struct frame_info
 
 static const struct frame_unwind mt_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   mt_frame_this_id,
   mt_frame_prev_register,
   NULL,
Index: src/gdb/ppc-linux-tdep.c
===================================================================
--- src.orig/gdb/ppc-linux-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/ppc-linux-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -1472,6 +1472,7 @@ ppu2spu_dealloc_cache (struct frame_info
 
 static const struct frame_unwind ppu2spu_unwind = {
   ARCH_FRAME,
+  default_frame_unwind_stop_reason,
   ppu2spu_this_id,
   ppu2spu_prev_register,
   NULL,
Index: src/gdb/ppcobsd-tdep.c
===================================================================
--- src.orig/gdb/ppcobsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/ppcobsd-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -239,6 +239,7 @@ ppcobsd_sigtramp_frame_prev_register (st
 
 static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   ppcobsd_sigtramp_frame_this_id,
   ppcobsd_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/rs6000-tdep.c
===================================================================
--- src.orig/gdb/rs6000-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/rs6000-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -3319,6 +3319,7 @@ rs6000_frame_prev_register (struct frame
 static const struct frame_unwind rs6000_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   rs6000_frame_this_id,
   rs6000_frame_prev_register,
   NULL,
Index: src/gdb/s390-tdep.c
===================================================================
--- src.orig/gdb/s390-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/s390-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -1758,6 +1758,7 @@ s390_frame_prev_register (struct frame_i
 
 static const struct frame_unwind s390_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   s390_frame_this_id,
   s390_frame_prev_register,
   NULL,
@@ -1841,6 +1842,7 @@ s390_stub_frame_sniffer (const struct fr
 
 static const struct frame_unwind s390_stub_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   s390_stub_frame_this_id,
   s390_stub_frame_prev_register,
   NULL,
@@ -2032,6 +2034,7 @@ s390_sigtramp_frame_sniffer (const struc
 
 static const struct frame_unwind s390_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   s390_sigtramp_frame_this_id,
   s390_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/score-tdep.c
===================================================================
--- src.orig/gdb/score-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/score-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -1369,6 +1369,7 @@ score_prologue_prev_register (struct fra
 static const struct frame_unwind score_prologue_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   score_prologue_this_id,
   score_prologue_prev_register,
   NULL,
Index: src/gdb/sh-tdep.c
===================================================================
--- src.orig/gdb/sh-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/sh-tdep.c	2011-02-22 17:58:04.304708002 +0000
@@ -2635,6 +2635,7 @@ sh_frame_this_id (struct frame_info *thi
 
 static const struct frame_unwind sh_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sh_frame_this_id,
   sh_frame_prev_register,
   NULL,
Index: src/gdb/sh64-tdep.c
===================================================================
--- src.orig/gdb/sh64-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/sh64-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -2437,6 +2437,7 @@ sh64_frame_this_id (struct frame_info *t
 
 static const struct frame_unwind sh64_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sh64_frame_this_id,
   sh64_frame_prev_register,
   NULL,
Index: src/gdb/sparc-sol2-tdep.c
===================================================================
--- src.orig/gdb/sparc-sol2-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparc-sol2-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -164,6 +164,7 @@ sparc32_sol2_sigtramp_frame_sniffer (con
 static const struct frame_unwind sparc32_sol2_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc32_sol2_sigtramp_frame_this_id,
   sparc32_sol2_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/sparc-tdep.c
===================================================================
--- src.orig/gdb/sparc-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/sparc-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -1031,6 +1031,7 @@ sparc32_frame_prev_register (struct fram
 static const struct frame_unwind sparc32_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sparc32_frame_this_id,
   sparc32_frame_prev_register,
   NULL,
Index: src/gdb/sparc64-sol2-tdep.c
===================================================================
--- src.orig/gdb/sparc64-sol2-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparc64-sol2-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -141,6 +141,7 @@ sparc64_sol2_sigtramp_frame_sniffer (con
 static const struct frame_unwind sparc64_sol2_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64_sol2_sigtramp_frame_this_id,
   sparc64_sol2_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/sparc64-tdep.c
===================================================================
--- src.orig/gdb/sparc64-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/sparc64-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -562,6 +562,7 @@ sparc64_frame_prev_register (struct fram
 static const struct frame_unwind sparc64_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64_frame_this_id,
   sparc64_frame_prev_register,
   NULL,
Index: src/gdb/sparc64fbsd-tdep.c
===================================================================
--- src.orig/gdb/sparc64fbsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparc64fbsd-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -202,6 +202,7 @@ sparc64fbsd_sigtramp_frame_sniffer (cons
 static const struct frame_unwind sparc64fbsd_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64fbsd_sigtramp_frame_this_id,
   sparc64fbsd_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/sparc64nbsd-tdep.c
===================================================================
--- src.orig/gdb/sparc64nbsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparc64nbsd-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -230,6 +230,7 @@ sparc64nbsd_sigtramp_frame_sniffer (cons
 static const struct frame_unwind sparc64nbsd_sigcontext_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64nbsd_sigcontext_frame_this_id,
   sparc64nbsd_sigcontext_frame_prev_register,
   NULL,
Index: src/gdb/sparc64obsd-tdep.c
===================================================================
--- src.orig/gdb/sparc64obsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparc64obsd-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -195,6 +195,7 @@ sparc64obsd_sigtramp_frame_sniffer (cons
 static const struct frame_unwind sparc64obsd_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64obsd_frame_this_id,
   sparc64obsd_frame_prev_register,
   NULL,
@@ -277,6 +278,7 @@ sparc64obsd_trapframe_sniffer (const str
 static const struct frame_unwind sparc64obsd_trapframe_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   sparc64obsd_trapframe_this_id,
   sparc64obsd_trapframe_prev_register,
   NULL,
Index: src/gdb/sparcnbsd-tdep.c
===================================================================
--- src.orig/gdb/sparcnbsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparcnbsd-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -254,6 +254,7 @@ sparc32nbsd_sigcontext_frame_sniffer (co
 static const struct frame_unwind sparc32nbsd_sigcontext_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc32nbsd_sigcontext_frame_this_id,
   sparc32nbsd_sigcontext_frame_prev_register,
   NULL,
Index: src/gdb/sparcobsd-tdep.c
===================================================================
--- src.orig/gdb/sparcobsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/sparcobsd-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -139,6 +139,7 @@ sparc32obsd_sigtramp_frame_sniffer (cons
 static const struct frame_unwind sparc32obsd_sigtramp_frame_unwind =
 {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   sparc32obsd_sigtramp_frame_this_id,
   sparc32obsd_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/spu-tdep.c
===================================================================
--- src.orig/gdb/spu-tdep.c	2011-02-22 17:57:49.000000000 +0000
+++ src/gdb/spu-tdep.c	2011-02-22 17:58:04.314708003 +0000
@@ -1082,6 +1082,7 @@ spu_frame_prev_register (struct frame_in
 
 static const struct frame_unwind spu_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   spu_frame_this_id,
   spu_frame_prev_register,
   NULL,
@@ -1236,6 +1237,7 @@ spu2ppu_dealloc_cache (struct frame_info
 
 static const struct frame_unwind spu2ppu_unwind = {
   ARCH_FRAME,
+  default_frame_unwind_stop_reason,
   spu2ppu_this_id,
   spu2ppu_prev_register,
   NULL,
Index: src/gdb/v850-tdep.c
===================================================================
--- src.orig/gdb/v850-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/v850-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -935,6 +935,7 @@ v850_frame_this_id (struct frame_info *t
 
 static const struct frame_unwind v850_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   v850_frame_this_id,
   v850_frame_prev_register,
   NULL,
Index: src/gdb/vax-tdep.c
===================================================================
--- src.orig/gdb/vax-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/vax-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -402,6 +402,7 @@ vax_frame_prev_register (struct frame_in
 static const struct frame_unwind vax_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   vax_frame_this_id,
   vax_frame_prev_register,
   NULL,
Index: src/gdb/vaxobsd-tdep.c
===================================================================
--- src.orig/gdb/vaxobsd-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/vaxobsd-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -135,6 +135,7 @@ vaxobsd_sigtramp_frame_prev_register (st
 
 static const struct frame_unwind vaxobsd_sigtramp_frame_unwind = {
   SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
   vaxobsd_sigtramp_frame_this_id,
   vaxobsd_sigtramp_frame_prev_register,
   NULL,
Index: src/gdb/xstormy16-tdep.c
===================================================================
--- src.orig/gdb/xstormy16-tdep.c	2011-02-22 17:11:07.000000000 +0000
+++ src/gdb/xstormy16-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -742,6 +742,7 @@ xstormy16_frame_base_address (struct fra
 
 static const struct frame_unwind xstormy16_frame_unwind = {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   xstormy16_frame_this_id,
   xstormy16_frame_prev_register,
   NULL,
Index: src/gdb/xtensa-tdep.c
===================================================================
--- src.orig/gdb/xtensa-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/xtensa-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -1438,6 +1438,7 @@ static const struct frame_unwind
 xtensa_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   xtensa_frame_this_id,
   xtensa_frame_prev_register,
   NULL,
Index: src/gdb/bfin-tdep.c
===================================================================
--- src.orig/gdb/bfin-tdep.c	2011-02-22 17:57:47.000000000 +0000
+++ src/gdb/bfin-tdep.c	2011-02-22 17:58:04.324708004 +0000
@@ -374,6 +374,7 @@ bfin_frame_prev_register (struct frame_i
 static const struct frame_unwind bfin_frame_unwind =
 {
   NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
   bfin_frame_this_id,
   bfin_frame_prev_register,
   NULL,

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

* Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
@ 2011-02-28 15:42 ` Jan Kratochvil
  2011-02-28 15:56   ` Pedro Alves
  2011-03-18 20:21 ` Pedro Alves
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2011-02-28 15:42 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 22 Feb 2011 19:34:42 +0100, Pedro Alves wrote:
> This teaches GDB about terminating unwinding gracefully if
> unwind further we would need registers/memory that haven't
> been collected.
> 
> Here's the result:
> 
>  (gdb) bt
>  #0  begin (a=<unavailable>) at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:182
>  #1  0x00000000004008ad in main (argc=1, argv=0x7fff0e22cf28, envp=0x7fff0e22cf38)
>      at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:210
>  #2  <unavailable> in ?? ()
>  Backtrace stopped: Not enough registers or memory available to unwind further

In my case:

(gdb) tfind 0
Found trace frame 0, tracepoint 2
#0  f () at 1.c:11
11	    v++;
(gdb) bt
#0  f () at 1.c:11
Backtrace stopped: Not enough registers or memory available to unwind further
(gdb) 

That is without that <unavailable>.  I think it is a bug.


Thanks,
Jan


$ ./gdb -nx -x ~/.gdbinit -ex 'target remote localhost:1234' ./gdbserver/1 -ex 'tb main' -ex c
GNU gdb (GDB) 7.2.50.20110228-cvs
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/jkratoch/redhat/gdb-clean/gdb/gdbserver/1...done.
Remote debugging using localhost:1234
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug/lib64/ld-2.13.90.so.debug...done.
done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
0x00007fcc89596600 in _start () from /lib64/ld-linux-x86-64.so.2
Temporary breakpoint 1 at 0x4004aa: file 1.c, line 18.
Continuing.

Temporary breakpoint 1, main () at 1.c:18
18	  f ();
(gdb) trace 11
Tracepoint 2 at 0x400480: file 1.c, line 11.
(gdb) actions 
Enter actions for tracepoint 2, one per line.
End with a line saying just "end".
>collect v
>end
(gdb) tstart
(gdb) b b
Breakpoint 3 at 0x400478: file 1.c, line 6.
(gdb) c
Continuing.

Breakpoint 3, b () at 1.c:6
6	}
(gdb) tstop 
(gdb) tstatus
Trace stopped by a tstop command.
Collected 9 trace frames.
Trace buffer has 5242691 bytes of 5242880 bytes free (0% full).
Trace will stop if GDB disconnects.
Not looking at any trace frame.
(gdb) tfind 0
Found trace frame 0, tracepoint 2
#0  f () at 1.c:11
11	    v++;
(gdb) bt
#0  f () at 1.c:11
Backtrace stopped: Not enough registers or memory available to unwind further
(gdb) 

$ ./gdbserver :1234 ./1
Process ./1 created; pid = 20703
Listening on port 1234
Remote debugging from host 127.0.0.1

1:int v = 1;
2:int q = 1;
3:void
4:b (void)
5:{
6:}
7:int
8:f (void)
9:{
10:  while (v < 10)
11:    v++;
12:  b ();
13:  return 5;
14:}
15:int
16:main (void)
17:{
18:  f ();
19:  return 0;
20:}

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

* Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-02-28 15:42 ` Jan Kratochvil
@ 2011-02-28 15:56   ` Pedro Alves
  2011-02-28 18:50     ` Jan Kratochvil
  0 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2011-02-28 15:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

On Monday 28 February 2011 15:41:32, Jan Kratochvil wrote:
> In my case:
> 
> (gdb) tfind 0
> Found trace frame 0, tracepoint 2
> #0  f () at 1.c:11
> 11          v++;
> (gdb) bt
> #0  f () at 1.c:11
> Backtrace stopped: Not enough registers or memory available to unwind further
> (gdb) 
> 
> That is without that <unavailable>.  I think it is a bug.

That's expected.  In my example, the _PC_ was not
unwoundable in the outermost unwindable frame, but other
registers were.  In your example, it was, and I'm going
to guess that since you haven't collected any registers,
you're seeing the dwarf unwinder not being able to compute
the CFA.

In my example, notice info registers in the outermost
frame:

(gdb) bt
#0  begin () at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:180
#1  0x0000000000400b69 in main (argc=1, argv=0x7fffa180ace8, envp=0x7fffa180acf8) at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:329
#2  <unavailable> in ?? ()
Backtrace stopped: Not enough registers or memory available to unwind further
(gdb) up
#1  0x0000000000400b69 in main (argc=1, argv=0x7fffa180ace8, envp=0x7fffa180acf8) at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:329
329       begin ();
(gdb) 
#2  <unavailable> in ?? ()
(gdb) info registers 
rax            0x7fa45460eec8   140343767002824
rbx            0x0      0
rcx            0x5      5
rdx            0x7fffa180acf8   140735902952696
rsi            0x7fffa180ace8   140735902952680
rdi            0x1      1
rbp            *value not available*
rsp            0x7fffa180ac10   0x7fffa180ac10
r8             0x7fa45460d300   140343766995712
r9             0x7fa454dc05c0   140343775069632
r10            0x7fffa180a8f0   140735902951664
r11            0x7fa4542c8770   140343763568496
r12            0x4006b0 4196016
r13            0x7fffa180ace0   140735902952672
r14            0x0      0
r15            0x0      0
rip            *value not available*
eflags         0x203    [ CF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

-- 
Pedro Alves

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

* Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-02-28 15:56   ` Pedro Alves
@ 2011-02-28 18:50     ` Jan Kratochvil
  0 siblings, 0 replies; 15+ messages in thread
From: Jan Kratochvil @ 2011-02-28 18:50 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 28 Feb 2011 16:55:56 +0100, Pedro Alves wrote:
> That's expected.  In my example, the _PC_ was not
> unwoundable in the outermost unwindable frame, but other
> registers were.  In your example, it was, and I'm going
> to guess that since you haven't collected any registers,
> you're seeing the dwarf unwinder not being able to compute
> the CFA.

OK, I see now that explains it.


Thanks,
Jan

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

* Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
  2011-02-28 15:42 ` Jan Kratochvil
@ 2011-03-18 20:21 ` Pedro Alves
  2011-03-21 10:09 ` Regression: " Jan Kratochvil
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2011-03-18 20:21 UTC (permalink / raw)
  To: gdb-patches

I've checked this one in as well.

On Tuesday 22 February 2011 18:34:42, Pedro Alves wrote:
> This patch applies on top of the "unavailable regs/locals"
> series, starting at:
> <http://sourceware.org/ml/gdb-patches/2011-02/msg00581.html>.
> 
> This teaches GDB about terminating unwinding gracefully if
> unwind further we would need registers/memory that haven't
> been collected.
> 
> Here's the result:
> 
>  (gdb) bt
>  #0  begin (a=<unavailable>) at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:182
>  #1  0x00000000004008ad in main (argc=1, argv=0x7fff0e22cf28, envp=0x7fff0e22cf38)
>      at ../../../src/gdb/testsuite/gdb.trace/unavailable.cc:210
>  #2  <unavailable> in ?? ()
>  Backtrace stopped: Not enough registers or memory available to unwind further
> 
> I think I've implemented this differently in about 10
> different ways.  This is the design that I ended up with and
> that I think is best.
> 
>  - when we sniff unwinders trying to find a matching unwinder,
>    we catch NOT_AVAILABLE_ERRORS.  If the PC is unavailable, 
>    it is impossible to determine if a given non-prologue parser unwinder
>    would have been the best unwinder or not.  By catching
>    NOT_AVAILABLE_ERRORS, we don't have too touch many sniffers.
>    When sniffing, they just read whatever minimum data they
>    require to determine they're the correct unwinder.  If
>    any of that is unavailable, we'll hit an exception.  So what
>    this means is that sniffer code does not try to check if a
>    given _required_ value is available --- it just goes ahead and
>    reads it.
> 
>  - adds a new frame_unwind method, to make it possible for an unwinder
>    to tell the core frame code that it can't unwind further.  The
>    concept here, is that if we are able to tell a given unwinder
>    would be the best unwinder, select it, even if actually trying to
>    unwind from it wouldn't work due to unavailable data.  E.g., if
>    all we have available is the PC, we'll be able to tell that we
>    have dwarf unwind info for that frame.  But if we then find out
>    that we don't have enough registers/memory to compute the CFA, we know
>    we aren't going to be able to unwind.  We _don't_ fallback to
>    prologue parsing in such cases, since if we couldn't unwind with
>    the precise unwind info missing, prologue parsing is surely not
>    going to be able to unwind correctly.
> 
>  - this new method incidently allows cleanly reporting to the core
>    frame machinery when a frame is the outermost, without resorting
>    to hacks in the frame_id, which opens the door to fixing a
>    corner case with stepping through the outermost frame when there's
>    no debug info.  I won't be implementing that, it just paves the way.
> 
>  - the prologue parsers then need to be made aware that they may trip
>    on necessary registers (e.g., PC / SP / FP) unavailable to unwine,
>    and that they should return that they can't unwind further in
>    the new frame_unwind method in that case.  I've taught the x86
>    and x64_64 unwinders, but not all others.  I did do the mechanical
>    work of adjusting all of them to the new interface, so that
>    --enable-targets=all still builds, and so that they continue working
>    as today.  Theaching other prologue unwinders how to terminate
>    gracefully with UNWIND_UNAVAILABLE is only interesting when a
>    corresponding target supports tracepoints on that architecture, so
>    it can be enabled on a case by case basis.

-- 
Pedro Alves

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

* Regression: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
  2011-02-28 15:42 ` Jan Kratochvil
  2011-03-18 20:21 ` Pedro Alves
@ 2011-03-21 10:09 ` Jan Kratochvil
  2011-03-21 20:46   ` Pedro Alves
  2011-03-22 14:40   ` Pedro Alves
  2011-03-21 17:46 ` [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further) Ulrich Weigand
  2011-03-31 14:43 ` [rfc] Fix broken i386 signal unwinding " Ulrich Weigand
  4 siblings, 2 replies; 15+ messages in thread
From: Jan Kratochvil @ 2011-03-21 10:09 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Hi Pedro,

on a testfile from the Fedora patchset there is a regression, IMO a valid one:

e67dca4a095f4db1022fd0753ef0bda3873dc1bc is the first bad commit
commit e67dca4a095f4db1022fd0753ef0bda3873dc1bc
Author: Pedro Alves <pedro@codesourcery.com>
Date:   Fri Mar 18 18:52:28 2011 +0000

    	gdb/
    	* frame.c (frame_unwind_register): Throw an error if unwinding the
    	register failed.
[...]
:040000 040000 6bdd3071cc91073d64ffd2a1030c44ce2b1956b9 a4487e736a1087aee5d5b5207cee5a56ae936f42 M	gdb
bisect run success

http://pkgs.fedoraproject.org/gitweb/?p=gdb.git;a=blob_plain;f=gdb-6.8-bz457187-largefile-test.patch;hb=f15/master
 = This file is included in this mail.

(gdb) x/i 0x400078
   0x400078:    hlt    
PASS: gdb.arch/i386-biarch-core.exp: .text is readable
->
(gdb) x/i 0x400078
PC not available
FAIL: gdb.arch/i386-biarch-core.exp: .text is readable

The core file does not have accessible registers.  It was not a goal of the
testcase, it tests something else.  But it has found this unrelated
regression.  I believe one should be able to evaluate PC-indepenent
expressions even if PC is not available.


Even the first part is regressing (although it stays PASS->PASS):
(gdb) core-file gdb.arch/i386-biarch-core.core
[New LWP 6901]
warning: Couldn't recognize general-purpose registers in core file.
Core was generated by `./bad'.
Program terminated with signal 11, Segmentation fault.
warning: Couldn't recognize general-purpose registers in core file.
#0  0x00000000 in ?? ()
->
(gdb) core-file gdb.arch/i386-biarch-core.core
[New LWP 6901]
warning: Couldn't recognize general-purpose registers in core file.
PC register is not available

The core file reason is not displayed while it could be, I have tried the
following patch does not help in this case:
	[patch 3/3] Display core reasons even during thread error
	http://sourceware.org/ml/gdb-patches/2011-02/msg00675.html


Thanks,
Jan


--- /dev/null	2009-04-19 14:49:00.974648389 +0200
+++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.exp	2009-04-19 16:30:12.000000000 +0200
@@ -0,0 +1,61 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Test ability to load an elf64-i386 core file.  The provided core file was
+# elf64-x8664 one but it got binary patched to i386:
+# Elf32_Ehdr.e_machine @0x12..0x13
+# Elf64_Ehdr.e_machine @0x12..0x13
+# #define EM_386           3              /* Intel 80386 */
+# #define EM_X86_64       62              /* AMD x86-64 architecture */
+# patch @0x12: 0x3E -> 0x03
+
+if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then {
+    verbose "Skipping i386-biarch-core test."
+    return
+}
+
+set testfile "i386-biarch-core"
+set corebz2uufile ${srcdir}/${subdir}/${testfile}.core.bz2.uu
+set corefile ${objdir}/${subdir}/${testfile}.core
+# Entry point of the original executable.
+set address 0x400078
+
+if {[catch "system \"uudecode -o - ${corebz2uufile} | bzip2 -dc >${corefile}\""] != 0} {
+    untested "failed uudecode or bzip2"
+    return -1
+}
+file stat ${corefile} corestat
+if {$corestat(size) != 102400} {
+    untested "uudecode or bzip2 produce invalid result"
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+# Wrongly built GDB complains by:
+# "..." is not a core dump: File format not recognized
+# As the provided test core has 64bit PRSTATUS i386 built GDB cannot parse it.
+# This is just a problem of the test care, real-world elf64-i386 file will have
+# 32bit PRSTATUS.  One cannot prepare elf64-i386 core file from elf32-i386 by
+# objcopy as it corrupts the core file beyond all recognition.
+# "\r\nCore was generated by `\[^\r\n\]*'\\.\r\nProgram terminated with signal 11, Segmentation fault\\.\r\n.*"
+gdb_test "core-file ${corefile}"
+
+gdb_test "x/i $address" "\r\n\[ \t\]*$address:\[ \t\]*hlt\[ \t\]*" ".text is readable"
--- /dev/null	2009-04-19 14:49:00.974648389 +0200
+++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.S	2009-04-19 14:52:28.000000000 +0200
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2009 Free Software Foundation, Inc.
+  
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+  
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+  
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+	.globl _start
+_start:
+	hlt
--- /dev/null	2009-04-19 14:49:00.974648389 +0200
+++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.core.bz2.uu	2009-04-19 15:02:12.000000000 +0200
@@ -0,0 +1,13 @@
+begin 600 i386-biarch-core.core.bz2
+M0EIH.3%!629361`P1\P`!)?_____\9'@"8Q)6P380'9@'&#`0D@``"``%(``
+M@`#`"!<(L`%F"(:$GH13::F-)M&D&U,AD:`--#)M0&FT0XR9--,)D9`P(Q-&
+M",(-&F``02)%38HT]0T`&AH```'H@``T^>9T*(,("&)SE`>`9@+GP=[,N)KB
+M'I8BL(L]N5TCY\%V]/?DB.BN*UZ'U@]TN7-]UJ5\_%0QTT<*086#%MHT7XVJ
+M9D"+C!"2*L:8D1XPD!`--M@*XT1H5RFYN&)(!0P0#:`I:;2;$5M&\*9"0@%:
+MK@X[T()M)9N7`D$VA!^63)%,;@8LT`(7\K&[7G;U:"B6'!GG+46ALOZF.2F-
+M!@>C*%86X$-]C2`KE;HG)UL(913VR2G]0BD:J=Z_`G@S,`W%.8RMS-#5P:J0
+MAJ2\8&X?@DE;UF68QHM<,D`('::J65/S:PAG*R-09["8DBI)'V]Y.[(/AM*L
+M"X_O^V;%FY.S6Q]FM=D37>5F,%4-F1ZF#,CFJVU;H*^IT<(%<V`.32$`JU["
+/G`68?\7<D4X4)`0,$?,`
+`
+end

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

* [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further)
  2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
                   ` (2 preceding siblings ...)
  2011-03-21 10:09 ` Regression: " Jan Kratochvil
@ 2011-03-21 17:46 ` Ulrich Weigand
  2011-03-21 20:52   ` Pedro Alves
  2011-03-31 14:43 ` [rfc] Fix broken i386 signal unwinding " Ulrich Weigand
  4 siblings, 1 reply; 15+ messages in thread
From: Ulrich Weigand @ 2011-03-21 17:46 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves wrote:

> 	(struct frame_unwind) <stop_reason>: New function pointer.

It seems you initialized this field in all statically allocated frame_unwind
structures, but not in those dynamically allocated and returned from the
tramp_frame_prepend_unwinder routine.  This causes crashes on all platforms
that use the tramp-frame.c framework ...

Fixed by the following patch.

Tested on powerpc64-linux, committed to mainline.

Bye,
Ulrich

ChangeLog:

	* tramp-frame.c (tramp_frame_prepend_unwinder): Set stop_reason
	field in returned unwinder.

Index: gdb/tramp-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/tramp-frame.c,v
retrieving revision 1.21
diff -u -p -r1.21 tramp-frame.c
--- gdb/tramp-frame.c	1 Jan 2011 15:33:18 -0000	1.21
+++ gdb/tramp-frame.c	21 Mar 2011 17:14:17 -0000
@@ -163,6 +163,7 @@ tramp_frame_prepend_unwinder (struct gdb
   unwinder->type = tramp_frame->frame_type;
   unwinder->unwind_data = data;
   unwinder->sniffer = tramp_frame_sniffer;
+  unwinder->stop_reason = default_frame_unwind_stop_reason;
   unwinder->this_id = tramp_frame_this_id;
   unwinder->prev_register = tramp_frame_prev_register;
   frame_unwind_prepend_unwinder (gdbarch, unwinder);

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

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

* Re: Regression: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-03-21 10:09 ` Regression: " Jan Kratochvil
@ 2011-03-21 20:46   ` Pedro Alves
  2011-03-22 14:40   ` Pedro Alves
  1 sibling, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2011-03-21 20:46 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Thanks Jan.  I'll take a look as soon as possible.

-- 
Pedro Alves

On Sunday 20 March 2011 18:48:45, Jan Kratochvil wrote:
> Hi Pedro,
> 
> on a testfile from the Fedora patchset there is a regression, IMO a valid one:
> 
> e67dca4a095f4db1022fd0753ef0bda3873dc1bc is the first bad commit
> commit e67dca4a095f4db1022fd0753ef0bda3873dc1bc
> Author: Pedro Alves <pedro@codesourcery.com>
> Date:   Fri Mar 18 18:52:28 2011 +0000
> 
>     	gdb/
>     	* frame.c (frame_unwind_register): Throw an error if unwinding the
>     	register failed.
> [...]
> :040000 040000 6bdd3071cc91073d64ffd2a1030c44ce2b1956b9 a4487e736a1087aee5d5b5207cee5a56ae936f42 M	gdb
> bisect run success
> 
> http://pkgs.fedoraproject.org/gitweb/?p=gdb.git;a=blob_plain;f=gdb-6.8-bz457187-largefile-test.patch;hb=f15/master
>  = This file is included in this mail.
> 
> (gdb) x/i 0x400078
>    0x400078:    hlt    
> PASS: gdb.arch/i386-biarch-core.exp: .text is readable
> ->
> (gdb) x/i 0x400078
> PC not available
> FAIL: gdb.arch/i386-biarch-core.exp: .text is readable
> 
> The core file does not have accessible registers.  It was not a goal of the
> testcase, it tests something else.  But it has found this unrelated
> regression.  I believe one should be able to evaluate PC-indepenent
> expressions even if PC is not available.
> 
> 
> Even the first part is regressing (although it stays PASS->PASS):
> (gdb) core-file gdb.arch/i386-biarch-core.core
> [New LWP 6901]
> warning: Couldn't recognize general-purpose registers in core file.
> Core was generated by `./bad'.
> Program terminated with signal 11, Segmentation fault.
> warning: Couldn't recognize general-purpose registers in core file.
> #0  0x00000000 in ?? ()
> ->
> (gdb) core-file gdb.arch/i386-biarch-core.core
> [New LWP 6901]
> warning: Couldn't recognize general-purpose registers in core file.
> PC register is not available
> 
> The core file reason is not displayed while it could be, I have tried the
> following patch does not help in this case:
> 	[patch 3/3] Display core reasons even during thread error
> 	http://sourceware.org/ml/gdb-patches/2011-02/msg00675.html
> 
> 
> Thanks,
> Jan
> 
> 
> --- /dev/null	2009-04-19 14:49:00.974648389 +0200
> +++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.exp	2009-04-19 16:30:12.000000000 +0200
> @@ -0,0 +1,61 @@
> +# This testcase is part of GDB, the GNU debugger.
> +
> +# Copyright 2009 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
> +
> +# Test ability to load an elf64-i386 core file.  The provided core file was
> +# elf64-x8664 one but it got binary patched to i386:
> +# Elf32_Ehdr.e_machine @0x12..0x13
> +# Elf64_Ehdr.e_machine @0x12..0x13
> +# #define EM_386           3              /* Intel 80386 */
> +# #define EM_X86_64       62              /* AMD x86-64 architecture */
> +# patch @0x12: 0x3E -> 0x03
> +
> +if { ![istarget "i?86-*-*"] && ![istarget "x86_64-*-*"] } then {
> +    verbose "Skipping i386-biarch-core test."
> +    return
> +}
> +
> +set testfile "i386-biarch-core"
> +set corebz2uufile ${srcdir}/${subdir}/${testfile}.core.bz2.uu
> +set corefile ${objdir}/${subdir}/${testfile}.core
> +# Entry point of the original executable.
> +set address 0x400078
> +
> +if {[catch "system \"uudecode -o - ${corebz2uufile} | bzip2 -dc >${corefile}\""] != 0} {
> +    untested "failed uudecode or bzip2"
> +    return -1
> +}
> +file stat ${corefile} corestat
> +if {$corestat(size) != 102400} {
> +    untested "uudecode or bzip2 produce invalid result"
> +    return -1
> +}
> +
> +gdb_exit
> +gdb_start
> +gdb_reinitialize_dir $srcdir/$subdir
> +
> +# Wrongly built GDB complains by:
> +# "..." is not a core dump: File format not recognized
> +# As the provided test core has 64bit PRSTATUS i386 built GDB cannot parse it.
> +# This is just a problem of the test care, real-world elf64-i386 file will have
> +# 32bit PRSTATUS.  One cannot prepare elf64-i386 core file from elf32-i386 by
> +# objcopy as it corrupts the core file beyond all recognition.
> +# "\r\nCore was generated by `\[^\r\n\]*'\\.\r\nProgram terminated with signal 11, Segmentation fault\\.\r\n.*"
> +gdb_test "core-file ${corefile}"
> +
> +gdb_test "x/i $address" "\r\n\[ \t\]*$address:\[ \t\]*hlt\[ \t\]*" ".text is readable"
> --- /dev/null	2009-04-19 14:49:00.974648389 +0200
> +++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.S	2009-04-19 14:52:28.000000000 +0200
> @@ -0,0 +1,22 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> +   Copyright 2009 Free Software Foundation, Inc.
> +  
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 2 of the License, or
> +   (at your option) any later version.
> +  
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +  
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +	.globl _start
> +_start:
> +	hlt
> --- /dev/null	2009-04-19 14:49:00.974648389 +0200
> +++ gdb-6.8/gdb/testsuite/gdb.arch/i386-biarch-core.core.bz2.uu	2009-04-19 15:02:12.000000000 +0200
> @@ -0,0 +1,13 @@
> +begin 600 i386-biarch-core.core.bz2
> +M0EIH.3%!629361`P1\P`!)?_____\9'@"8Q)6P380'9@'&#`0D@``"``%(``
> +M@`#`"!<(L`%F"(:$GH13::F-)M&D&U,AD:`--#)M0&FT0XR9--,)D9`P(Q-&
> +M",(-&F``02)%38HT]0T`&AH```'H@``T^>9T*(,("&)SE`>`9@+GP=[,N)KB
> +M'I8BL(L]N5TCY\%V]/?DB.BN*UZ'U@]TN7-]UJ5\_%0QTT<*086#%MHT7XVJ
> +M9D"+C!"2*L:8D1XPD!`--M@*XT1H5RFYN&)(!0P0#:`I:;2;$5M&\*9"0@%:
> +MK@X[T()M)9N7`D$VA!^63)%,;@8LT`(7\K&[7G;U:"B6'!GG+46ALOZF.2F-
> +M!@>C*%86X$-]C2`KE;HG)UL(913VR2G]0BD:J=Z_`G@S,`W%.8RMS-#5P:J0
> +MAJ2\8&X?@DE;UF68QHM<,D`('::J65/S:PAG*R-09["8DBI)'V]Y.[(/AM*L
> +M"X_O^V;%FY.S6Q]FM=D37>5F,%4-F1ZF#,CFJVU;H*^IT<(%<V`.32$`JU["
> +/G`68?\7<D4X4)`0,$?,`
> +`
> +end
> 

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

* Re: [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further)
  2011-03-21 17:46 ` [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further) Ulrich Weigand
@ 2011-03-21 20:52   ` Pedro Alves
  0 siblings, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2011-03-21 20:52 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On Monday 21 March 2011 17:24:45, Ulrich Weigand wrote:
> Pedro Alves wrote:
> 
> > 	(struct frame_unwind) <stop_reason>: New function pointer.
> 
> It seems you initialized this field in all statically allocated frame_unwind
> structures, but not in those dynamically allocated and returned from the
> tramp_frame_prepend_unwinder routine.  This causes crashes on all platforms
> that use the tramp-frame.c framework ...

Whoops, sorry about that.

> Fixed by the following patch.

Thanks!

-- 
Pedro Alves

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

* Re: Regression: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-03-21 10:09 ` Regression: " Jan Kratochvil
  2011-03-21 20:46   ` Pedro Alves
@ 2011-03-22 14:40   ` Pedro Alves
  2011-03-22 15:36     ` Jan Kratochvil
  1 sibling, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2011-03-22 14:40 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

On Sunday 20 March 2011 18:48:45, Jan Kratochvil wrote:
> Hi Pedro,
> 
> on a testfile from the Fedora patchset there is a regression, IMO a valid one:

Agreed.

> http://pkgs.fedoraproject.org/gitweb/?p=gdb.git;a=blob_plain;f=gdb-6.8-bz457187-largefile-test.patch;hb=f15/master
>  = This file is included in this mail.

Thanks!

> The core file does not have accessible registers.  It was not a goal of the
> testcase, it tests something else.  But it has found this unrelated
> regression.  

Yeah, nice test.

> (gdb) x/i 0x400078
>    0x400078:    hlt    
> PASS: gdb.arch/i386-biarch-core.exp: .text is readable
> ->
> (gdb) x/i 0x400078
> PC not available
> FAIL: gdb.arch/i386-biarch-core.exp: .text is readable

> I believe one should be able to evaluate PC-indepenent
> expressions even if PC is not available.

Yep, and you can.  The quirk is x/i / disassemble specific.  The
error is thrown while trying to decide whether to print the "==>" that
indicates the current PC.

> Even the first part is regressing (although it stays PASS->PASS):
> (gdb) core-file gdb.arch/i386-biarch-core.core
> [New LWP 6901]
> warning: Couldn't recognize general-purpose registers in core file.
> Core was generated by `./bad'.
> Program terminated with signal 11, Segmentation fault.
> warning: Couldn't recognize general-purpose registers in core file.
> #0  0x00000000 in ?? ()
> ->
> (gdb) core-file gdb.arch/i386-biarch-core.core
> [New LWP 6901]
> warning: Couldn't recognize general-purpose registers in core file.
> PC register is not available

Fixed as well.  After the patch:

(...)
warning: Couldn't recognize general-purpose registers in core file.
Core was generated by `./bad'.
Program terminated with signal 11, Segmentation fault.

warning: Couldn't recognize general-purpose registers in core file.
#0  <unavailable> in ?? ()
(gdb) 

and:

(gdb)  x/i 0x400078
   0x400078:    hlt  

Below's the patch.  Doesn't cause regressions for me.
Did you see any other regression?

Thanks,

Pedro Alves

2011-03-27  Pedro Alves  <pedro@codesourcery.com>

	* infcmd.c (post_create_inferior): Ignore NOT_AVAILABLE_ERROR
	errors when reading the `stop_pc'.
	* printcmd.c (pc_prefix): Use get_frame_pc_if_available instead of
	get_frame_pc.

---
 gdb/infcmd.c   |   14 ++++++++++++--
 gdb/printcmd.c |    4 +---
 2 files changed, 13 insertions(+), 5 deletions(-)

Index: src/gdb/infcmd.c
===================================================================
--- src.orig/gdb/infcmd.c	2011-03-15 20:15:05.000000000 +0000
+++ src/gdb/infcmd.c	2011-03-22 10:22:17.729088002 +0000
@@ -395,6 +395,8 @@ strip_bg_char (char **args)
 void
 post_create_inferior (struct target_ops *target, int from_tty)
 {
+  volatile struct gdb_exception ex;
+
   /* Be sure we own the terminal in case write operations are performed.  */ 
   target_terminal_ours ();
 
@@ -404,8 +406,16 @@ post_create_inferior (struct target_ops
      don't need to.  */
   target_find_description ();
 
-  /* Now that we know the register layout, retrieve current PC.  */
-  stop_pc = regcache_read_pc (get_current_regcache ());
+  /* Now that we know the register layout, retrieve current PC.  But
+     if the PC is unavailable (e.g., we're opening a core file with
+     missing registers info), ignore it.  */
+  stop_pc = 0;
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      stop_pc = regcache_read_pc (get_current_regcache ());
+    }
+  if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+    throw_exception (ex);
 
   if (exec_bfd)
     {
Index: src/gdb/printcmd.c
===================================================================
--- src.orig/gdb/printcmd.c	2011-03-15 20:15:34.000000000 +0000
+++ src/gdb/printcmd.c	2011-03-22 10:21:41.829088002 +0000
@@ -759,9 +759,7 @@ pc_prefix (CORE_ADDR addr)
       CORE_ADDR pc;
 
       frame = get_selected_frame (NULL);
-      pc = get_frame_pc (frame);
-
-      if (pc == addr)
+      if (get_frame_pc_if_available (frame, &pc) && pc == addr)
 	return "=> ";
     }
   return "   ";

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

* Re: Regression: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-03-22 14:40   ` Pedro Alves
@ 2011-03-22 15:36     ` Jan Kratochvil
  2011-03-22 16:19       ` Pedro Alves
  0 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2011-03-22 15:36 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 22 Mar 2011 12:13:16 +0100, Pedro Alves wrote:
> Yep, and you can.  The quirk is x/i / disassemble specific.  The
> error is thrown while trying to decide whether to print the "==>" that
> indicates the current PC.

Aha.

> Below's the patch.  Doesn't cause regressions for me.

I can confirm it works here as proclaimed.  Please check it in.

> Did you see any other regression?

No.


Thanks,
Jan

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

* Re: Regression: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further
  2011-03-22 15:36     ` Jan Kratochvil
@ 2011-03-22 16:19       ` Pedro Alves
  0 siblings, 0 replies; 15+ messages in thread
From: Pedro Alves @ 2011-03-22 16:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

On Tuesday 22 March 2011 13:21:59, Jan Kratochvil wrote:
> On Tue, 22 Mar 2011 12:13:16 +0100, Pedro Alves wrote:
> > Below's the patch.  Doesn't cause regressions for me.
> 
> I can confirm it works here as proclaimed.  Please check it in.

Great, done.

Thanks.

-- 
Pedro Alves

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

* [rfc] Fix broken i386 signal unwinding (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further)
  2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
                   ` (3 preceding siblings ...)
  2011-03-21 17:46 ` [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further) Ulrich Weigand
@ 2011-03-31 14:43 ` Ulrich Weigand
  2011-03-31 16:20   ` Pedro Alves
  4 siblings, 1 reply; 15+ messages in thread
From: Ulrich Weigand @ 2011-03-31 14:43 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

Pedro Alves wrote:

> 	(i386_frame_prev_register): Handle unavailable SP.

> -  if (regnum == I386_ESP_REGNUM && cache->saved_sp)
> -    return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
> +  if (regnum == I386_ESP_REGNUM)
> +    {
> +      /* If the SP has been saved, but we don't know where, then this
> +	 means that SAVED_SP_REG register was found unavailable back
> +	 when we built the cache.  */
> +      if (cache->saved_sp == 0 && cache->saved_sp_reg != -1)
> +	return frame_unwind_got_register (this_frame, regnum,
> +					  cache->saved_sp_reg);
> +      else
> +	return frame_unwind_got_constant (this_frame, regnum,
> +					  cache->saved_sp);
> +    }
>  
>    if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
>      return frame_unwind_got_memory (this_frame, regnum,

It seems this change broke unwinding out of signal trampoline
frames on i386 for me.  In this case, neither SAVED_SP nor
SAVED_SP_REG is set; instead, SP is supposed to be unwound
from memory (the trampoline stack frame) via SAVED_REGS.

However, after your change, we now fall into the _got_constant
case and SP is always unwound as 0.

The following patch fixes this for me, and gets about 50 test
cases back to PASS.

Does this look right to you?

Tested on i386-linux (Ubuntu Lucid).

Bye,
Ulrich

ChangeLog:

	* i386-tdep.c (i386_frame_prev_register): Unwind SP from memory
	if neither saved value nor register available (e.g. signal frame).


Index: gdb/i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.330
diff -u -p -r1.330 i386-tdep.c
--- gdb/i386-tdep.c	18 Mar 2011 18:52:30 -0000	1.330
+++ gdb/i386-tdep.c	31 Mar 2011 13:50:07 -0000
@@ -1798,12 +1798,13 @@ i386_frame_prev_register (struct frame_i
   if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
     return frame_unwind_got_register (this_frame, regnum, I386_EAX_REGNUM);
 
-  if (regnum == I386_ESP_REGNUM)
+  if (regnum == I386_ESP_REGNUM
+      && (cache->saved_sp != 0 || cache->saved_sp_reg != -1))
     {
       /* If the SP has been saved, but we don't know where, then this
 	 means that SAVED_SP_REG register was found unavailable back
 	 when we built the cache.  */
-      if (cache->saved_sp == 0 && cache->saved_sp_reg != -1)
+      if (cache->saved_sp == 0)
 	return frame_unwind_got_register (this_frame, regnum,
 					  cache->saved_sp_reg);
       else

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

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

* Re: [rfc] Fix broken i386 signal unwinding (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further)
  2011-03-31 14:43 ` [rfc] Fix broken i386 signal unwinding " Ulrich Weigand
@ 2011-03-31 16:20   ` Pedro Alves
  2011-03-31 16:23     ` [rfc] Fix broken i386 signal unwinding (Re: graceful unwind termination when we'd need unavailable/uncollect memory or regis Ulrich Weigand
  0 siblings, 1 reply; 15+ messages in thread
From: Pedro Alves @ 2011-03-31 16:20 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On Thursday 31 March 2011 14:57:51, Ulrich Weigand wrote:
> It seems this change broke unwinding out of signal trampoline
> frames on i386 for me.  In this case, neither SAVED_SP nor
> SAVED_SP_REG is set; instead, SP is supposed to be unwound
> from memory (the trampoline stack frame) via SAVED_REGS.
> 
> However, after your change, we now fall into the _got_constant
> case and SP is always unwound as 0.
> 
> The following patch fixes this for me, and gets about 50 test
> cases back to PASS.
> 
> Does this look right to you?

Yes it does.  Thanks much for tracking and fixing it.

-- 
Pedro Alves

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

* Re: [rfc] Fix broken i386 signal unwinding (Re: graceful unwind termination when we'd need unavailable/uncollect memory or regis
  2011-03-31 16:20   ` Pedro Alves
@ 2011-03-31 16:23     ` Ulrich Weigand
  0 siblings, 0 replies; 15+ messages in thread
From: Ulrich Weigand @ 2011-03-31 16:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, patches

Pedro Alves wrote:
> On Thursday 31 March 2011 14:57:51, Ulrich Weigand wrote:
> > It seems this change broke unwinding out of signal trampoline
> > frames on i386 for me.  In this case, neither SAVED_SP nor
> > SAVED_SP_REG is set; instead, SP is supposed to be unwound
> > from memory (the trampoline stack frame) via SAVED_REGS.
> > 
> > However, after your change, we now fall into the _got_constant
> > case and SP is always unwound as 0.
> > 
> > The following patch fixes this for me, and gets about 50 test
> > cases back to PASS.
> > 
> > Does this look right to you?
> 
> Yes it does.  Thanks much for tracking and fixing it.

OK, I've checked this in now.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

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

end of thread, other threads:[~2011-03-31 16:19 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-22 18:35 graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further Pedro Alves
2011-02-28 15:42 ` Jan Kratochvil
2011-02-28 15:56   ` Pedro Alves
2011-02-28 18:50     ` Jan Kratochvil
2011-03-18 20:21 ` Pedro Alves
2011-03-21 10:09 ` Regression: " Jan Kratochvil
2011-03-21 20:46   ` Pedro Alves
2011-03-22 14:40   ` Pedro Alves
2011-03-22 15:36     ` Jan Kratochvil
2011-03-22 16:19       ` Pedro Alves
2011-03-21 17:46 ` [commit] Fix tramp-frame.c crash (Re: graceful unwind termination when we'd need unavailable/uncollect memory or registers to unwind further) Ulrich Weigand
2011-03-21 20:52   ` Pedro Alves
2011-03-31 14:43 ` [rfc] Fix broken i386 signal unwinding " Ulrich Weigand
2011-03-31 16:20   ` Pedro Alves
2011-03-31 16:23     ` [rfc] Fix broken i386 signal unwinding (Re: graceful unwind termination when we'd need unavailable/uncollect memory or regis Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).