Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC 2/5] Frame unwinding using struct value
@ 2008-03-31 22:12 Daniel Jacobowitz
  2008-04-01 13:23 ` Eli Zaretskii
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-03-31 22:12 UTC (permalink / raw)
  To: gdb-patches

Ref:
  http://sourceware.org/ml/gdb/2008-03/msg00282.html

The meat of the conversion.  This patch converts frame.c, all the
related frame-unwind and frame-base code, and the dummy and sentinel
unwinders.  It also includes helpers for writing new prev_register
methods and a gdbint chapter.

prev_register methods written with the new interface are nicely more
compact.  And simpler, because there's less off-by-one juggling
involved.  This kills nearly all places we use the next frame that
aren't strictly necessary.

-- 
Daniel Jacobowitz
CodeSourcery

2008-03-31  Daniel Jacobowitz  <dan@codesourcery.com>

	Convert frame unwinders to use the current frame and
	"struct value".

	* frame.c (frame_debug): Make global.
	(get_frame_id): Pass this frame to unwinder routines.
	(frame_pc_unwind): Remove unused unwind->prev_pc support.
	(do_frame_register_read): Do not discard the return value of
	frame_register_read.
	(frame_register_unwind): Remove debug messages.  Use
	frame_unwind_register_value.
	(frame_unwind_register_value, get_frame_register_value): New
	functions.
	(create_new_frame, get_frame_base_address, get_frame_locals_address)
	(get_frame_args_address, get_frame_type): Pass this frame to
	unwinder routines.
	(frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New
	functions.
	* frame.h: Update comments.
	(frame_debug, frame_unwind_register_value, get_frame_register_value)
	(frame_prepare_for_sniffer): Declare.
	* frame-unwind.h: Update comments and parameter names.
	(default_frame_sniffer): Declare.
	(frame_prev_register_ftype): Return a struct value *.
	(struct frame_unwind): Remove prev_pc member.
	(frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): Declare.
	* frame-base.h: Update comments and parameter names.
	* valops.c (value_fetch_lazy): Use get_frame_register_value.  Iterate
	if necessary.  Add debugging output.
	* sentinel-frame.c (sentinel_frame_prev_register)
	(sentinel_frame_this_id): Update for new signature.
	(sentinel_frame_prev_pc): Delete.
	(sentinel_frame_unwinder): Remove prev_pc.
	* ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize
	prev_pc.
	* libunwind-frame.c (libunwind_frame_unwind): Likewise.
	* frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer.
	(frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder): New function.
	(frame_unwind_find_by_frame): Take this frame.  Only use sniffers
	from unwinders.  Use frame_prepare_for_sniffer.
	(default_frame_sniffer, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): New functions.
	* dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id.
	(dummy_frame_prev_register, dummy_frame_this_id): Update for new
	signature.
	* gdbarch.sh: Replace unwind_dummy_id with dummy_id.
	* gdbarch.c, gdbarch.c: Regenerated.
	* frame-base.c (default_frame_base_address)
	(default_frame_locals_address, default_frame_args_address): Update
	for new signature.
	(frame_base_find_by_frame): Pass this frame to unwinder routines.
	* infcall.c (call_function_by_hand): Update comments.
	* Makefile.in (frame-unwind.o): Update dependencies.

2008-03-31  Daniel Jacobowitz  <dan@codesourcery.com>

	* gdbint.texinfo (Stack Frames): New chapter.
	(Algorithms): Move Frames text to the new chapter.
	(Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS.  Document
	gdbarch_dummy_id instead of gdbarch_unwind_dummy_id.

---
 gdb/Makefile.in        |    3 
 gdb/doc/gdbint.texinfo |  156 +++++++++++++++++++++++++-----------
 gdb/dummy-frame.c      |   53 +++++-------
 gdb/frame-base.c       |   17 +--
 gdb/frame-base.h       |   18 ++--
 gdb/frame-unwind.c     |  136 +++++++++++++++++++++++++------
 gdb/frame-unwind.h     |  109 ++++++++++++++-----------
 gdb/frame.c            |  210 ++++++++++++++++++++++++++++++++-----------------
 gdb/frame.h            |   18 +++-
 gdb/gdbarch.c          |   36 ++++----
 gdb/gdbarch.h          |   10 +-
 gdb/gdbarch.sh         |    4 
 gdb/ia64-tdep.c        |    1 
 gdb/infcall.c          |    6 -
 gdb/libunwind-frame.c  |    1 
 gdb/sentinel-frame.c   |   54 ++++--------
 gdb/valops.c           |   92 ++++++++++++++++++---
 17 files changed, 604 insertions(+), 320 deletions(-)

Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame.c	2008-03-31 13:39:07.000000000 -0400
@@ -113,7 +113,7 @@ struct frame_info
 
 /* Flag to control debugging.  */
 
-static int frame_debug;
+int frame_debug;
 static void
 show_frame_debug (struct ui_file *file, int from_tty,
 		  struct cmd_list_element *c, const char *value)
@@ -255,10 +255,9 @@ get_frame_id (struct frame_info *fi)
 			    fi->level);
       /* Find the unwinder.  */
       if (fi->unwind == NULL)
-	fi->unwind = frame_unwind_find_by_frame (fi->next,
-						 &fi->prologue_cache);
+	fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
       /* Find THIS frame's ID.  */
-      fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
+      fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
       fi->this_id.p = 1;
       if (frame_debug)
 	{
@@ -427,15 +426,7 @@ frame_pc_unwind (struct frame_info *this
   if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
-      if (this_frame->unwind == NULL)
-	this_frame->unwind
-	  = frame_unwind_find_by_frame (this_frame->next,
-					&this_frame->prologue_cache);
-      if (this_frame->unwind->prev_pc != NULL)
-	/* A per-frame unwinder, prefer it.  */
-	pc = this_frame->unwind->prev_pc (this_frame->next,
-					  &this_frame->prologue_cache);
-      else if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+      if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
 	{
 	  /* The right way.  The `pure' way.  The one true way.  This
 	     method depends solely on the register-unwind code to
@@ -495,8 +486,7 @@ get_frame_func (struct frame_info *fi)
 static int
 do_frame_register_read (void *src, int regnum, gdb_byte *buf)
 {
-  frame_register_read (src, regnum, buf);
-  return 1;
+  return frame_register_read (src, regnum, buf);
 }
 
 struct regcache *
@@ -552,15 +542,7 @@ frame_register_unwind (struct frame_info
 		       int *optimizedp, enum lval_type *lvalp,
 		       CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
 {
-  struct frame_unwind_cache *cache;
-
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "\
-{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
-			  frame->level, regnum,
-			  frame_map_regnum_to_name (frame, regnum));
-    }
+  struct value *value;
 
   /* Require all but BUFFERP to be valid.  A NULL BUFFERP indicates
      that the value proper does not need to be fetched.  */
@@ -570,43 +552,23 @@ frame_register_unwind (struct frame_info
   gdb_assert (realnump != NULL);
   /* gdb_assert (bufferp != NULL); */
 
-  /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
-     is broken.  There is always a frame.  If there, for some reason,
-     isn't a frame, there is some pretty busted code as it should have
-     detected the problem before calling here.  */
-  gdb_assert (frame != NULL);
-
-  /* Find the unwinder.  */
-  if (frame->unwind == NULL)
-    frame->unwind = frame_unwind_find_by_frame (frame->next,
-						&frame->prologue_cache);
+  value = frame_unwind_register_value (frame, regnum);
 
-  /* Ask this frame to unwind its register.  See comment in
-     "frame-unwind.h" for why NEXT frame and this unwind cache are
-     passed in.  */
-  frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
-				optimizedp, lvalp, addrp, realnump, bufferp);
+  gdb_assert (value != NULL);
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "->");
-      fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
-      fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
-      fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
-      fprintf_unfiltered (gdb_stdlog, " *bufferp=");
-      if (bufferp == NULL)
-	fprintf_unfiltered (gdb_stdlog, "<NULL>");
-      else
-	{
-	  int i;
-	  const unsigned char *buf = bufferp;
-	  fprintf_unfiltered (gdb_stdlog, "[");
-	  for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
-	    fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
-	  fprintf_unfiltered (gdb_stdlog, "]");
-	}
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+  *optimizedp = value_optimized_out (value);
+  *lvalp = VALUE_LVAL (value);
+  *addrp = VALUE_ADDRESS (value);
+  *realnump = VALUE_REGNUM (value);
+
+  if (bufferp)
+    memcpy (bufferp, value_contents_all (value),
+	    TYPE_LENGTH (value_type (value)));
+
+  /* Dispose of the new value.  This prevents watchpoints from
+     trying to watch the saved frame pointer.  */
+  release_value (value);
+  value_free (value);
 }
 
 void
@@ -647,6 +609,71 @@ get_frame_register (struct frame_info *f
   frame_unwind_register (frame->next, regnum, buf);
 }
 
+struct value *
+frame_unwind_register_value (struct frame_info *frame, int regnum)
+{
+  struct value *value;
+
+  if (frame_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "\
+{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
+			  frame->level, regnum,
+			  frame_map_regnum_to_name (frame, regnum));
+    }
+
+  gdb_assert (frame != NULL);
+
+  /* Find the unwinder.  */
+  if (frame->unwind == NULL)
+    frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+
+  /* Ask this frame to unwind its register.  */
+  value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+
+  if (frame_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "->");
+      if (value_optimized_out (value))
+	fprintf_unfiltered (gdb_stdlog, " optimized out");
+      else
+	{
+	  if (VALUE_LVAL (value) == lval_register)
+	    fprintf_unfiltered (gdb_stdlog, " register=%d",
+				VALUE_REGNUM (value));
+	  else if (VALUE_LVAL (value) == lval_memory)
+	    fprintf_unfiltered (gdb_stdlog, " address=0x%s",
+				paddr_nz (VALUE_ADDRESS (value)));
+	  else
+	    fprintf_unfiltered (gdb_stdlog, " computed");
+
+	  if (value_lazy (value))
+	    fprintf_unfiltered (gdb_stdlog, " lazy");
+	  else
+	    {
+	      int i;
+	      const gdb_byte *buf = value_contents (value);
+
+	      fprintf_unfiltered (gdb_stdlog, " bytes=");
+	      fprintf_unfiltered (gdb_stdlog, "[");
+	      for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+	      fprintf_unfiltered (gdb_stdlog, "]");
+	    }
+	}
+
+      fprintf_unfiltered (gdb_stdlog, " }\n");
+    }
+
+  return value;
+}
+
+struct value *
+get_frame_register_value (struct frame_info *frame, int regnum)
+{
+  return frame_unwind_register_value (frame->next, regnum);
+}
+
 LONGEST
 frame_unwind_register_signed (struct frame_info *frame, int regnum)
 {
@@ -1022,7 +1049,7 @@ create_new_frame (CORE_ADDR addr, CORE_A
 
   /* Select/initialize both the unwind function and the frame's type
      based on the PC.  */
-  fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache);
+  fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
 
   fi->this_id.p = 1;
   deprecated_update_frame_base_hack (fi, addr);
@@ -1569,8 +1596,8 @@ get_frame_base_address (struct frame_inf
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    return fi->base->this_base (fi->next, &fi->prologue_cache);
-  return fi->base->this_base (fi->next, &fi->base_cache);
+    return fi->base->this_base (fi, &fi->prologue_cache);
+  return fi->base->this_base (fi, &fi->base_cache);
 }
 
 CORE_ADDR
@@ -1585,10 +1612,8 @@ get_frame_locals_address (struct frame_i
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    cache = &fi->prologue_cache;
-  else
-    cache = &fi->base_cache;
-  return fi->base->this_locals (fi->next, cache);
+    return fi->base->this_locals (fi, &fi->prologue_cache);
+  return fi->base->this_locals (fi, &fi->base_cache);
 }
 
 CORE_ADDR
@@ -1603,10 +1628,8 @@ get_frame_args_address (struct frame_inf
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    cache = &fi->prologue_cache;
-  else
-    cache = &fi->base_cache;
-  return fi->base->this_args (fi->next, cache);
+    return fi->base->this_args (fi, &fi->prologue_cache);
+  return fi->base->this_args (fi, &fi->base_cache);
 }
 
 /* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@@ -1627,8 +1650,7 @@ get_frame_type (struct frame_info *frame
   if (frame->unwind == NULL)
     /* Initialize the frame's unwinder because that's what
        provides the frame's type.  */
-    frame->unwind = frame_unwind_find_by_frame (frame->next, 
-						&frame->prologue_cache);
+    frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
   return frame->unwind->type;
 }
 
@@ -1769,6 +1791,50 @@ frame_stop_reason_string (enum unwind_st
     }
 }
 
+/* Clean up after a failed (wrong unwinder) attempt to unwind past
+   FRAME.  */
+
+static void
+frame_cleanup_after_sniffer (void *arg)
+{
+  struct frame_info *frame = arg;
+
+  /* The sniffer should not allocate a prologue cache if it did not
+     match this frame.  */
+  gdb_assert (frame->prologue_cache == NULL);
+
+  /* No sniffer should extend the frame chain; sniff based on what is
+     already certain.  */
+  gdb_assert (!frame->prev_p);
+
+  /* The sniffer should not check the frame's ID; that's circular.  */
+  gdb_assert (!frame->this_id.p);
+
+  /* Clear cached fields dependent on the unwinder.
+
+     The previous PC is independent of the unwinder, but the previous
+     function is not (see frame_unwind_address_in_block).  */
+  frame->prev_func.p = 0;
+  frame->prev_func.addr = 0;
+
+  /* Discard the unwinder last, so that we can easily find it if an assertion
+     in this function triggers.  */
+  frame->unwind = NULL;
+}
+
+/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
+   Return a cleanup which should be called if unwinding fails, and
+   discarded if it succeeds.  */
+
+struct cleanup *
+frame_prepare_for_sniffer (struct frame_info *frame,
+			   const struct frame_unwind *unwind)
+{
+  gdb_assert (frame->unwind == NULL);
+  frame->unwind = unwind;
+  return make_cleanup (frame_cleanup_after_sniffer, frame);
+}
+
 extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
 
 static struct cmd_list_element *set_backtrace_cmdlist;
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame.h	2008-03-31 13:39:07.000000000 -0400
@@ -144,6 +144,10 @@ struct frame_id
 /* For convenience.  All fields are zero.  */
 extern const struct frame_id null_frame_id;
 
+/* Flag to control debugging.  */
+
+extern int frame_debug;
+
 /* Construct a frame ID.  The first parameter is the frame's constant
    stack address (typically the outer-bound), and the second the
    frame's constant code address (typically the entry point).
@@ -460,13 +464,19 @@ extern void frame_register_unwind (struc
 /* Fetch a register from this, or unwind a register from the next
    frame.  Note that the get_frame methods are wrappers to
    frame->next->unwind.  They all [potentially] throw an error if the
-   fetch fails.  */
+   fetch fails.  The value methods never return NULL, but usually
+   do return a lazy value.  */
 
 extern void frame_unwind_register (struct frame_info *frame,
 				   int regnum, gdb_byte *buf);
 extern void get_frame_register (struct frame_info *frame,
 				int regnum, gdb_byte *buf);
 
+struct value *frame_unwind_register_value (struct frame_info *frame,
+					   int regnum);
+struct value *get_frame_register_value (struct frame_info *frame,
+					int regnum);
+
 extern LONGEST frame_unwind_register_signed (struct frame_info *frame,
 					     int regnum);
 extern LONGEST get_frame_register_signed (struct frame_info *frame,
@@ -666,6 +676,12 @@ extern void (*deprecated_selected_frame_
 
 extern void return_command (char *, int);
 
+/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
+   Return a cleanup which should be called if unwinding fails, and
+   discarded if it succeeds.  */
+
+struct cleanup *frame_prepare_for_sniffer (struct frame_info *frame,
+					   const struct frame_unwind *unwind);
 
 /* Notes (cagney/2002-11-27, drow/2003-09-06):
 
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-unwind.h	2008-03-31 14:43:29.000000000 -0400
@@ -26,6 +26,7 @@ struct frame_id;
 struct frame_unwind;
 struct gdbarch;
 struct regcache;
+struct value;
 
 #include "frame.h"		/* For enum frame_type.  */
 
@@ -41,17 +42,24 @@ struct regcache;
    as where this frame's prologue stores the previous frame's
    registers.  */
 
-/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
+/* Given THIS frame, take a whiff of its registers (namely
    the PC and attributes) and if SELF is the applicable unwinder,
    return non-zero.  Possibly also initialize THIS_PROLOGUE_CACHE.  */
 
 typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
-				   struct frame_info *next_frame,
+				   struct frame_info *this_frame,
 				   void **this_prologue_cache);
 
+/* A default frame sniffer which always accepts the frame.  Used by
+   fallback prologue unwinders.  */
+
+int default_frame_sniffer (const struct frame_unwind *self,
+			   struct frame_info *this_frame,
+			   void **this_prologue_cache);
+
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to determine
-   the frame ID of THIS frame.
+   use THIS frame, and through it the NEXT frame's register unwind
+   method, to determine the frame ID of THIS frame.
 
    A frame ID provides an invariant that can be used to re-identify an
    instance of a frame.  It is a combination of the frame's `base' and
@@ -72,14 +80,14 @@ typedef int (frame_sniffer_ftype) (const
    with the other unwind methods.  Memory for that cache should be
    allocated using FRAME_OBSTACK_ZALLOC().  */
 
-typedef void (frame_this_id_ftype) (struct frame_info *next_frame,
+typedef void (frame_this_id_ftype) (struct frame_info *this_frame,
 				    void **this_prologue_cache,
 				    struct frame_id *this_id);
 
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to unwind THIS
-   frame's registers (returning the value of the specified register
-   REGNUM in the previous frame).
+   use THIS frame, and implicitly the NEXT frame's register unwind
+   method, to unwind THIS frame's registers (returning the value of
+   the specified register REGNUM in the previous frame).
 
    Traditionally, THIS frame's registers were unwound by examining
    THIS frame's function's prologue and identifying which registers
@@ -91,37 +99,22 @@ typedef void (frame_this_id_ftype) (stru
    register in the previous frame is found in memory at SP+12, and
    THIS frame's SP can be obtained by unwinding the NEXT frame's SP.
 
-   Why not pass in THIS_FRAME?  By passing in NEXT frame and THIS
-   cache, the supplied parameters are consistent with the sibling
-   function THIS_ID.
-
-   Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''?
-   Won't the call frame_register (THIS_FRAME) be faster?  Well,
-   ignoring the possability that the previous frame does not yet
-   exist, the ``frame_register (FRAME)'' function is expanded to
-   ``frame_register_unwind (get_next_frame (FRAME)'' and hence that
-   call will expand to ``frame_register_unwind (get_next_frame
-   (get_prev_frame (NEXT_FRAME)))''.  Might as well call
-   ``frame_register_unwind (NEXT_FRAME)'' directly.
+   This function takes THIS_FRAME as an argument.  It can find the
+   values of registers in THIS frame by calling get_frame_register
+   (THIS_FRAME), and reinvoke itself to find other registers in the
+   PREVIOUS frame by calling frame_unwind_register (THIS_FRAME).
+
+   The result is a GDB value object describing the register value.  It
+   may be a lazy reference to memory, a lazy reference to the value of
+   a register in THIS frame, or a non-lvalue.
 
    THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
    with the other unwind methods.  Memory for that cache should be
    allocated using FRAME_OBSTACK_ZALLOC().  */
 
-typedef void (frame_prev_register_ftype) (struct frame_info *next_frame,
-					  void **this_prologue_cache,
-					  int prev_regnum,
-					  int *optimized,
-					  enum lval_type * lvalp,
-					  CORE_ADDR *addrp,
-					  int *realnump, gdb_byte *valuep);
-
-/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to return the PREV
-   frame's program-counter.  */
-
-typedef CORE_ADDR (frame_prev_pc_ftype) (struct frame_info *next_frame,
-					 void **this_prologue_cache);
+typedef struct value * (frame_prev_register_ftype)
+  (struct frame_info *this_frame, void **this_prologue_cache,
+   int regnum);
 
 /* Deallocate extra memory associated with the frame cache if any.  */
 
@@ -139,7 +132,6 @@ struct frame_unwind
   frame_prev_register_ftype *prev_register;
   const struct frame_data *unwind_data;
   frame_sniffer_ftype *sniffer;
-  frame_prev_pc_ftype *prev_pc;
   frame_dealloc_cache_ftype *dealloc_cache;
 };
 
@@ -152,23 +144,50 @@ struct frame_unwind
 extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
 					   const struct frame_unwind *unwinder);
 
-/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
-   the PC and attributes) and if it is the applicable unwinder return
-   the unwind methods, or NULL if it is not.  */
-
-typedef const struct frame_unwind *(frame_unwind_sniffer_ftype) (struct frame_info *next_frame);
-
 /* Add a frame sniffer to the list.  The predicates are polled in the
    order that they are appended.  The initial list contains the dummy
    frame sniffer.  */
 
-extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch,
-					 frame_unwind_sniffer_ftype *sniffer);
+extern void frame_unwind_append_unwinder (struct gdbarch *gdbarch,
+					  const struct frame_unwind *unwinder);
 
-/* Iterate through the next frame's sniffers until one returns with an
+/* Iterate through sniffers for THIS frame until one returns with an
    unwinder implementation.  Possibly initialize THIS_CACHE.  */
 
-extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame,
+extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *this_frame,
 							      void **this_cache);
 
+/* Helper functions for value-based register unwinding.  These return
+   a (possibly lazy) value of the appropriate type.  */
+
+/* Return a value which indicates that FRAME did not save REGNUM.  */
+
+struct value *frame_unwind_got_optimized (struct frame_info *frame,
+					  int regnum);
+
+/* Return a value which indicates that FRAME copied REGNUM into
+   register NEW_REGNUM.  */
+
+struct value *frame_unwind_got_register (struct frame_info *frame, int regnum,
+					 int new_regnum);
+
+/* Return a value which indicates that FRAME saved REGNUM in memory at
+   ADDR.  */
+
+struct value *frame_unwind_got_memory (struct frame_info *frame, int regnum,
+				       CORE_ADDR addr);
+
+/* Return a value which indicates that FRAME's saved version of
+   REGNUM has a known constant (computed) value of VAL.  */
+
+struct value *frame_unwind_got_constant (struct frame_info *frame, int regnum,
+					 ULONGEST val);
+
+/* Return a value which indicates that FRAME's saved version of REGNUM
+   has a known constant (computed) value of ADDR.  Convert the
+   CORE_ADDR to a target address if necessary.  */
+
+struct value *frame_unwind_got_address (struct frame_info *frame, int regnum,
+					CORE_ADDR addr);
+
 #endif
Index: src/gdb/frame-base.h
===================================================================
--- src.orig/gdb/frame-base.h	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-base.h	2008-03-31 15:23:52.000000000 -0400
@@ -28,9 +28,9 @@ struct gdbarch;
 struct regcache;
 
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   and that this is a `normal frame'; use the NEXT frame, and its
-   register unwind method, to determine the address of THIS frame's
-   `base'.
+   and that this is a `normal frame'; use THIS frame, and implicitly
+   the NEXT frame's register unwind method, to determine the address
+   of THIS frame's `base'.
 
    The exact meaning of `base' is highly dependant on the type of the
    debug info.  It is assumed that dwarf2, stabs, ... will each
@@ -42,17 +42,17 @@ struct regcache;
 
 /* A generic base address.  */
 
-typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *this_frame,
 					   void **this_base_cache);
 
 /* The base address of the frame's local variables.  */
 
-typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *this_frame,
 					     void **this_base_cache);
 
 /* The base address of the frame's arguments / parameters.  */
 
-typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *this_frame,
 					   void **this_base_cache);
 
 struct frame_base
@@ -65,10 +65,10 @@ struct frame_base
   frame_this_args_ftype *this_args;
 };
 
-/* Given the NEXT frame, return the frame base methods for THIS frame,
+/* Given THIS frame, return the frame base methods for THIS frame,
    or NULL if it can't handle THIS frame.  */
 
-typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *next_frame);
+typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *this_frame);
 
 /* Append a frame base sniffer to the list.  The sniffers are polled
    in the order that they are appended.  */
@@ -86,6 +86,6 @@ extern void frame_base_set_default (stru
 /* Iterate through the list of frame base handlers until one returns
    an implementation.  */
 
-extern const struct frame_base *frame_base_find_by_frame (struct frame_info *next_frame);
+extern const struct frame_base *frame_base_find_by_frame (struct frame_info *this_frame);
 
 #endif
Index: src/gdb/valops.c
===================================================================
--- src.orig/gdb/valops.c	2008-03-31 13:34:22.000000000 -0400
+++ src/gdb/valops.c	2008-03-31 13:39:07.000000000 -0400
@@ -582,24 +582,88 @@ value_fetch_lazy (struct value *val)
     }
   else if (VALUE_LVAL (val) == lval_register)
     {
-      struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (val));
-      int regnum = VALUE_REGNUM (val);
+      struct frame_info *frame;
+      int regnum;
       struct type *type = check_typedef (value_type (val));
+      struct value *new_val = val, *mark = value_mark ();
 
-      gdb_assert (frame != NULL);
+      /* Offsets are not supported here; lazy register values must
+	 refer to the entire register.  */
+      gdb_assert (value_offset (val) == 0);
 
-      /* Convertible register routines are used for multi-register
-	 values and for interpretation in different types (e.g. float
-	 or int from a double register).  Lazy register values should
-	 have the register's natural type, so they do not apply.  */
-      gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), regnum,
-					       type));
-
-      /* Get the data.  */
-      if (!get_frame_register_bytes (frame, regnum, value_offset (val),
-				     TYPE_LENGTH (value_type (val)),
-				     value_contents_raw (val)))
+      while (VALUE_LVAL (new_val) == lval_register
+	     && value_lazy (new_val))
+	{
+	  frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
+	  regnum = VALUE_REGNUM (new_val);
+
+	  gdb_assert (frame != NULL);
+
+	  /* Convertible register routines are used for multi-register
+	     values and for interpretation in different types
+	     (e.g. float or int from a double register).  Lazy
+	     register values should have the register's natural type,
+	     so they do not apply.  */
+	  gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
+						   regnum, type));
+
+	  new_val = get_frame_register_value (frame, regnum);
+	}
+
+      /* If it's still lazy (for instance, a saved register on the
+	 stack), fetch it.  */
+      if (value_lazy (new_val))
+	value_fetch_lazy (new_val);
+
+      /* If the register was not saved, mark it unavailable.  */
+      if (value_optimized_out (new_val))
 	set_value_optimized_out (val, 1);
+      else
+	memcpy (value_contents_raw (val), value_contents (new_val),
+		TYPE_LENGTH (type));
+
+      if (frame_debug)
+	{
+	  frame = frame_find_by_id (VALUE_FRAME_ID (val));
+	  regnum = VALUE_REGNUM (val);
+
+	  fprintf_unfiltered (gdb_stdlog, "\
+{ value_fetch_lazy (frame=%d,regnum=%d(%s),...) ",
+			      frame_relative_level (frame), regnum,
+			      frame_map_regnum_to_name (frame, regnum));
+
+	  fprintf_unfiltered (gdb_stdlog, "->");
+	  if (value_optimized_out (new_val))
+	    fprintf_unfiltered (gdb_stdlog, " optimized out");
+	  else
+	    {
+	      int i;
+	      const gdb_byte *buf = value_contents (new_val);
+
+	      if (VALUE_LVAL (new_val) == lval_register)
+		fprintf_unfiltered (gdb_stdlog, " register=%d",
+				    VALUE_REGNUM (new_val));
+	      else if (VALUE_LVAL (new_val) == lval_memory)
+		fprintf_unfiltered (gdb_stdlog, " address=0x%s",
+				    paddr_nz (VALUE_ADDRESS (new_val)));
+	      else
+		fprintf_unfiltered (gdb_stdlog, " computed");
+
+	      fprintf_unfiltered (gdb_stdlog, " bytes=");
+	      fprintf_unfiltered (gdb_stdlog, "[");
+	      for (i = 0;
+		   i < register_size (get_frame_arch (frame), regnum);
+		   i++)
+		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+	      fprintf_unfiltered (gdb_stdlog, "]");
+	    }
+
+	  fprintf_unfiltered (gdb_stdlog, " }\n");
+	}
+
+      /* Dispose of the intermediate values.  This prevents
+	 watchpoints from trying to watch the saved frame pointer.  */
+      value_free_to_mark (mark);
     }
   else
     internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/sentinel-frame.c	2008-03-31 13:39:07.000000000 -0400
@@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *r
 
 /* Here the register value is taken direct from the register cache.  */
 
-static void
-sentinel_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+sentinel_frame_prev_register (struct frame_info *this_frame,
 			      void **this_prologue_cache,
-			      int regnum, int *optimized,
-			      enum lval_type *lvalp, CORE_ADDR *addrp,
-			      int *realnum, gdb_byte *bufferp)
+			      int regnum)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_cache *cache = *this_prologue_cache;
-  /* Describe the register's location.  A reg-frame maps all registers
-     onto the corresponding hardware register.  */
-  *optimized = 0;
-  *lvalp = lval_register;
-  *addrp = 0;
-  *realnum = regnum;
-
-  /* If needed, find and return the value of the register.  */
-  if (bufferp != NULL)
-    {
-      /* Return the actual value.  */
-      /* Use the regcache_cooked_read() method so that it, on the fly,
-         constructs either a raw or pseudo register from the raw
-         register cache.  */
-      regcache_cooked_read (cache->regcache, regnum, bufferp);
-    }
+  struct value *value;
+
+  /* Return the actual value.  */
+  value = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (value) = lval_register;
+  VALUE_REGNUM (value) = regnum;
+  VALUE_FRAME_ID (value) = get_frame_id (this_frame);
+
+  /* Use the regcache_cooked_read() method so that it, on the fly,
+     constructs either a raw or pseudo register from the raw
+     register cache.  */
+  regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
+
+  return value;
 }
 
 static void
-sentinel_frame_this_id (struct frame_info *next_frame,
+sentinel_frame_this_id (struct frame_info *this_frame,
 			void **this_prologue_cache,
 			struct frame_id *this_id)
 {
@@ -79,22 +76,11 @@ sentinel_frame_this_id (struct frame_inf
   internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
 }
 
-static CORE_ADDR
-sentinel_frame_prev_pc (struct frame_info *next_frame,
-			void **this_prologue_cache)
-{
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  return gdbarch_unwind_pc (gdbarch, next_frame);
-}
-
 const struct frame_unwind sentinel_frame_unwinder =
 {
   SENTINEL_FRAME,
   sentinel_frame_this_id,
-  sentinel_frame_prev_register,
-  NULL, /* unwind_data */
-  NULL, /* sniffer */
-  sentinel_frame_prev_pc,
+  sentinel_frame_prev_register
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
Index: src/gdb/ia64-tdep.c
===================================================================
--- src.orig/gdb/ia64-tdep.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/ia64-tdep.c	2008-03-31 13:39:07.000000000 -0400
@@ -2796,7 +2796,6 @@ static const struct frame_unwind ia64_li
   ia64_libunwind_frame_prev_register,
   NULL,
   NULL,
-  NULL,
   libunwind_frame_dealloc_cache
 };
 
Index: src/gdb/libunwind-frame.c
===================================================================
--- src.orig/gdb/libunwind-frame.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/libunwind-frame.c	2008-03-31 13:39:07.000000000 -0400
@@ -214,7 +214,6 @@ static const struct frame_unwind libunwi
   libunwind_frame_prev_register,
   NULL,
   NULL,
-  NULL,
   libunwind_frame_dealloc_cache
 };
 
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-unwind.c	2008-03-31 14:45:50.000000000 -0400
@@ -20,15 +20,17 @@
 #include "defs.h"
 #include "frame.h"
 #include "frame-unwind.h"
-#include "gdb_assert.h"
 #include "dummy-frame.h"
+#include "value.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
 #include "gdb_obstack.h"
 
 static struct gdbarch_data *frame_unwind_data;
 
 struct frame_unwind_table_entry
 {
-  frame_unwind_sniffer_ftype *sniffer;
   const struct frame_unwind *unwinder;
   struct frame_unwind_table_entry *next;
 };
@@ -55,19 +57,6 @@ frame_unwind_init (struct obstack *obsta
 }
 
 void
-frame_unwind_append_sniffer (struct gdbarch *gdbarch,
-			     frame_unwind_sniffer_ftype *sniffer)
-{
-  struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
-  struct frame_unwind_table_entry **ip;
-
-  /* Find the end of the list and insert the new entry there.  */
-  for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
-  (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
-  (*ip)->sniffer = sniffer;
-}
-
-void
 frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
 				const struct frame_unwind *unwinder)
 {
@@ -81,32 +70,123 @@ frame_unwind_prepend_unwinder (struct gd
   (*table->osabi_head) = entry;
 }
 
+void
+frame_unwind_append_unwinder (struct gdbarch *gdbarch,
+			      const struct frame_unwind *unwinder)
+{
+  struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+  struct frame_unwind_table_entry **ip;
+
+  /* Find the end of the list and insert the new entry there.  */
+  for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
+  (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
+  (*ip)->unwinder = unwinder;
+}
+
 const struct frame_unwind *
-frame_unwind_find_by_frame (struct frame_info *next_frame, void **this_cache)
+frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
 {
   int i;
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
   struct frame_unwind_table_entry *entry;
+  struct cleanup *old_cleanup;
   for (entry = table->list; entry != NULL; entry = entry->next)
     {
-      if (entry->sniffer != NULL)
-	{
-	  const struct frame_unwind *desc = NULL;
-	  desc = entry->sniffer (next_frame);
-	  if (desc != NULL)
-	    return desc;
-	}
-      if (entry->unwinder != NULL)
+      struct cleanup *old_cleanup;
+
+      old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
+      if (entry->unwinder->sniffer (entry->unwinder, this_frame,
+				    this_cache))
 	{
-	  if (entry->unwinder->sniffer (entry->unwinder, next_frame,
-					this_cache))
-	    return entry->unwinder;
+	  discard_cleanups (old_cleanup);
+	  return entry->unwinder;
 	}
+      do_cleanups (old_cleanup);
     }
   internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
 }
 
+/* A default frame sniffer which always accepts the frame.  Used by
+   fallback prologue unwinders.  */
+
+int
+default_frame_sniffer (const struct frame_unwind *self,
+		       struct frame_info *this_frame,
+		       void **this_prologue_cache)
+{
+  return 1;
+}
+
+/* Helper functions for value-based register unwinding.  These return
+   a (possibly lazy) value of the appropriate type.  */
+
+/* Return a value which indicates that FRAME did not save REGNUM.  */
+
+struct value *
+frame_unwind_got_optimized (struct frame_info *frame, int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  set_value_optimized_out (reg_val, 1);
+  return reg_val;
+}
+
+/* Return a value which indicates that FRAME copied REGNUM into
+   register NEW_REGNUM.  */
+
+struct value *
+frame_unwind_got_register (struct frame_info *frame, int regnum, int new_regnum)
+{
+  return value_of_register_lazy (frame, new_regnum);
+}
+
+/* Return a value which indicates that FRAME saved REGNUM in memory at
+   ADDR.  */
+
+struct value *
+frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  return value_at_lazy (register_type (gdbarch, regnum), addr);
+}
+
+/* Return a value which indicates that FRAME's saved version of
+   REGNUM has a known constant (computed) value of VAL.  */
+
+struct value *
+frame_unwind_got_constant (struct frame_info *frame, int regnum,
+			   ULONGEST val)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  store_unsigned_integer (value_contents_writeable (reg_val),
+			  register_size (gdbarch, regnum), val);
+  return reg_val;
+}
+
+/* Return a value which indicates that FRAME's saved version of REGNUM
+   has a known constant (computed) value of ADDR.  Convert the
+   CORE_ADDR to a target address if necessary.  */
+
+struct value *
+frame_unwind_got_address (struct frame_info *frame, int regnum,
+			  CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  pack_long (value_contents_writeable (reg_val),
+	     register_type (gdbarch, regnum), addr);
+  return reg_val;
+}
+
 extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */
 
 void
Index: src/gdb/dummy-frame.c
===================================================================
--- src.orig/gdb/dummy-frame.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/dummy-frame.c	2008-03-31 13:49:41.000000000 -0400
@@ -39,7 +39,7 @@ struct dummy_frame
 {
   struct dummy_frame *next;
   /* This frame's ID.  Must match the value returned by
-     gdbarch_unwind_dummy_id.  */
+     gdbarch_dummy_id.  */
   struct frame_id id;
   /* The caller's regcache.  */
   struct regcache *regcache;
@@ -124,7 +124,7 @@ struct dummy_frame_cache
 
 int
 dummy_frame_sniffer (const struct frame_unwind *self,
-		     struct frame_info *next_frame,
+		     struct frame_info *this_frame,
 		     void **this_prologue_cache)
 {
   struct dummy_frame *dummyframe;
@@ -141,12 +141,9 @@ dummy_frame_sniffer (const struct frame_
   /* Don't bother unles there is at least one dummy frame.  */
   if (dummy_frame_stack != NULL)
     {
-      /* Use an architecture specific method to extract the prev's
-	 dummy ID from the next frame.  Note that this method uses
-	 frame_register_unwind to obtain the register values needed to
-	 determine the dummy frame's ID.  */
-      this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame), 
-					 next_frame);
+      /* Use an architecture specific method to extract the this frame's
+	 dummy ID, assuming it is a dummy frame.  */
+      this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);
 
       /* Use that ID to find the corresponding cache entry.  */
       for (dummyframe = dummy_frame_stack;
@@ -170,43 +167,37 @@ dummy_frame_sniffer (const struct frame_
 /* Given a call-dummy dummy-frame, return the registers.  Here the
    register value is taken from the local copy of the register buffer.  */
 
-static void
-dummy_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+dummy_frame_prev_register (struct frame_info *this_frame,
 			   void **this_prologue_cache,
-			   int regnum, int *optimized,
-			   enum lval_type *lvalp, CORE_ADDR *addrp,
-			   int *realnum, gdb_byte *bufferp)
+			   int regnum)
 {
-  /* The dummy-frame sniffer always fills in the cache.  */
   struct dummy_frame_cache *cache = (*this_prologue_cache);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct value *reg_val;
+
+  /* The dummy-frame sniffer always fills in the cache.  */
   gdb_assert (cache != NULL);
 
   /* Describe the register's location.  Generic dummy frames always
      have the register value in an ``expression''.  */
-  *optimized = 0;
-  *lvalp = not_lval;
-  *addrp = 0;
-  *realnum = -1;
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
 
-  /* If needed, find and return the value of the register.  */
-  if (bufferp != NULL)
-    {
-      /* Return the actual value.  */
-      /* Use the regcache_cooked_read() method so that it, on the fly,
-         constructs either a raw or pseudo register from the raw
-         register cache.  */
-      regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
-    }
+  /* Use the regcache_cooked_read() method so that it, on the fly,
+     constructs either a raw or pseudo register from the raw
+     register cache.  */
+  regcache_cooked_read (cache->prev_regcache, regnum,
+			value_contents_writeable (reg_val));
+  return reg_val;
 }
 
-/* Assuming that THIS frame is a dummy (remember, the NEXT and not
-   THIS frame is passed in), return the ID of THIS frame.  That ID is
+/* Assuming that THIS frame is a dummy, return the ID of THIS frame.  That ID is
    determined by examining the NEXT frame's unwound registers using
-   the method unwind_dummy_id().  As a side effect, THIS dummy frame's
+   the method dummy_id().  As a side effect, THIS dummy frame's
    dummy cache is located and and saved in THIS_PROLOGUE_CACHE.  */
 
 static void
-dummy_frame_this_id (struct frame_info *next_frame,
+dummy_frame_this_id (struct frame_info *this_frame,
 		     void **this_prologue_cache,
 		     struct frame_id *this_id)
 {
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.c	2008-03-31 13:39:07.000000000 -0400
@@ -162,7 +162,7 @@ struct gdbarch
   gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
   gdbarch_register_name_ftype *register_name;
   gdbarch_register_type_ftype *register_type;
-  gdbarch_unwind_dummy_id_ftype *unwind_dummy_id;
+  gdbarch_dummy_id_ftype *dummy_id;
   int deprecated_fp_regnum;
   gdbarch_push_dummy_call_ftype *push_dummy_call;
   int call_dummy_location;
@@ -284,7 +284,7 @@ struct gdbarch startup_gdbarch =
   no_op_reg_to_regnum,  /* dwarf2_reg_to_regnum */
   0,  /* register_name */
   0,  /* register_type */
-  0,  /* unwind_dummy_id */
+  0,  /* dummy_id */
   -1,  /* deprecated_fp_regnum */
   0,  /* push_dummy_call */
   0,  /* call_dummy_location */
@@ -522,7 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   if (gdbarch->register_name == 0)
     fprintf_unfiltered (log, "\n\tregister_name");
   /* Skip verify of register_type, has predicate */
-  /* Skip verify of unwind_dummy_id, has predicate */
+  /* Skip verify of dummy_id, has predicate */
   /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
   /* Skip verify of push_dummy_call, has predicate */
   /* Skip verify of call_dummy_location, invalid_p == 0 */
@@ -715,6 +715,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: double_format = %s\n",
                       pformat (gdbarch->double_format));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
+                      gdbarch_dummy_id_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dummy_id = <0x%lx>\n",
+                      (long) gdbarch->dummy_id);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
                       (long) gdbarch->dwarf2_reg_to_regnum);
   fprintf_unfiltered (file,
@@ -979,12 +985,6 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: target_desc = %s\n",
                       paddr_d ((long) gdbarch->target_desc));
   fprintf_unfiltered (file,
-                      "gdbarch_dump: gdbarch_unwind_dummy_id_p() = %d\n",
-                      gdbarch_unwind_dummy_id_p (gdbarch));
-  fprintf_unfiltered (file,
-                      "gdbarch_dump: unwind_dummy_id = <0x%lx>\n",
-                      (long) gdbarch->unwind_dummy_id);
-  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
                       gdbarch_unwind_pc_p (gdbarch));
   fprintf_unfiltered (file,
@@ -1646,27 +1646,27 @@ set_gdbarch_register_type (struct gdbarc
 }
 
 int
-gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch)
+gdbarch_dummy_id_p (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
-  return gdbarch->unwind_dummy_id != NULL;
+  return gdbarch->dummy_id != NULL;
 }
 
 struct frame_id
-gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info)
+gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
   gdb_assert (gdbarch != NULL);
-  gdb_assert (gdbarch->unwind_dummy_id != NULL);
+  gdb_assert (gdbarch->dummy_id != NULL);
   if (gdbarch_debug >= 2)
-    fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n");
-  return gdbarch->unwind_dummy_id (gdbarch, info);
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dummy_id called\n");
+  return gdbarch->dummy_id (gdbarch, this_frame);
 }
 
 void
-set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch,
-                             gdbarch_unwind_dummy_id_ftype unwind_dummy_id)
+set_gdbarch_dummy_id (struct gdbarch *gdbarch,
+                      gdbarch_dummy_id_ftype dummy_id)
 {
-  gdbarch->unwind_dummy_id = unwind_dummy_id;
+  gdbarch->dummy_id = dummy_id;
 }
 
 int
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.h	2008-03-31 13:39:07.000000000 -0400
@@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (s
 
 /* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
 
-extern int gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch);
+extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
 
-typedef struct frame_id (gdbarch_unwind_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *info);
-extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info);
-extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id);
+typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
+extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame);
+extern void set_gdbarch_dummy_id (struct gdbarch *gdbarch, gdbarch_dummy_id_ftype *dummy_id);
 
-/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+/* Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
    deprecated_fp_regnum. */
 
 extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch);
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.sh	2008-03-31 13:39:07.000000000 -0400
@@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:r
 M:struct type *:register_type:int reg_nr:reg_nr
 
 # See gdbint.texinfo, and PUSH_DUMMY_CALL.
-M:struct frame_id:unwind_dummy_id:struct frame_info *info:info
-# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
+# Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
 # deprecated_fp_regnum.
 v:int:deprecated_fp_regnum:::-1:-1::0
 
Index: src/gdb/frame-base.c
===================================================================
--- src.orig/gdb/frame-base.c	2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-base.c	2008-03-31 13:39:07.000000000 -0400
@@ -28,22 +28,21 @@
    really need to override this.  */
 
 static CORE_ADDR
-default_frame_base_address (struct frame_info *next_frame, void **this_cache)
+default_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
-  struct frame_info *this_frame = get_prev_frame (next_frame);
   return get_frame_base (this_frame); /* sigh! */
 }
 
 static CORE_ADDR
-default_frame_locals_address (struct frame_info *next_frame, void **this_cache)
+default_frame_locals_address (struct frame_info *this_frame, void **this_cache)
 {
-  return default_frame_base_address (next_frame, this_cache);
+  return default_frame_base_address (this_frame, this_cache);
 }
 
 static CORE_ADDR
-default_frame_args_address (struct frame_info *next_frame, void **this_cache)
+default_frame_args_address (struct frame_info *this_frame, void **this_cache)
 {
-  return default_frame_base_address (next_frame, this_cache);
+  return default_frame_base_address (this_frame, this_cache);
 }
 
 const struct frame_base default_frame_base = {
@@ -97,16 +96,16 @@ frame_base_set_default (struct gdbarch *
 }
 
 const struct frame_base *
-frame_base_find_by_frame (struct frame_info *next_frame)
+frame_base_find_by_frame (struct frame_info *this_frame)
 {
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data);
   struct frame_base_table_entry *entry;
 
   for (entry = table->head; entry != NULL; entry = entry->next)
     {
       const struct frame_base *desc = NULL;
-      desc = entry->sniffer (next_frame);
+      desc = entry->sniffer (this_frame);
       if (desc != NULL)
 	return desc;
     }
Index: src/gdb/doc/gdbint.texinfo
===================================================================
--- src.orig/gdb/doc/gdbint.texinfo	2008-03-31 13:45:54.000000000 -0400
+++ src/gdb/doc/gdbint.texinfo	2008-03-31 15:15:37.000000000 -0400
@@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN
 * Algorithms::
 * User Interface::
 * libgdb::
+* Stack Frames::
 * Symbol Handling::
 * Language Support::
 * Host Definition::
@@ -273,39 +274,6 @@ cases and real-world issues.  This chapt
 algorithms and mentions some of the specific target definitions that
 they use.
 
-@section Frames
-
-@cindex frame
-@cindex call stack frame
-A frame is a construct that @value{GDBN} uses to keep track of calling
-and called functions.
-
-@cindex frame, unwind
-@value{GDBN}'s frame model, a fresh design, was implemented with the
-need to support @sc{dwarf}'s Call Frame Information in mind.  In fact,
-the term ``unwind'' is taken directly from that specification.
-Developers wishing to learn more about unwinders, are encouraged to
-read the @sc{dwarf} specification.
-
-@findex frame_register_unwind
-@findex get_frame_register
-@value{GDBN}'s model is that you find a frame's registers by
-``unwinding'' them from the next younger frame.  That is,
-@samp{get_frame_register} which returns the value of a register in
-frame #1 (the next-to-youngest frame), is implemented by calling frame
-#0's @code{frame_register_unwind} (the youngest frame).  But then the
-obvious question is: how do you access the registers of the youngest
-frame itself?
-
-@cindex sentinel frame
-@findex get_frame_type
-@vindex SENTINEL_FRAME
-To answer this question, GDB has the @dfn{sentinel} frame, the
-``-1st'' frame.  Unwinding registers from the sentinel frame gives you
-the current values of the youngest real frame's registers.  If @var{f}
-is a sentinel frame, then @code{get_frame_type (@var{f}) ==
-SENTINEL_FRAME}.
-
 @section Prologue Analysis
 
 @cindex prologue analysis
@@ -1853,6 +1821,111 @@ the query interface.  Each function is p
 builder.  The result of the query is constructed using that builder
 before the query function returns.
 
+@node Stack Frames
+@chapter Stack Frames
+
+@cindex frame
+@cindex call stack frame
+A frame is a construct that @value{GDBN} uses to keep track of calling
+and called functions.
+
+@cindex frame, unwind
+@value{GDBN}'s frame model, a fresh design, was implemented with the
+need to support @sc{dwarf}'s Call Frame Information in mind.  In fact,
+the term ``unwind'' is taken directly from that specification.
+Developers wishing to learn more about unwinders, are encouraged to
+read the @sc{dwarf} specification.
+
+@findex frame_register_unwind
+@findex get_frame_register
+@value{GDBN}'s model is that you find a frame's registers by
+``unwinding'' them from the next younger frame.  That is,
+@samp{get_frame_register} which returns the value of a register in
+frame #1 (the next-to-youngest frame), is implemented by calling frame
+#0's @code{frame_register_unwind} (the youngest frame).  But then the
+obvious question is: how do you access the registers of the youngest
+frame itself?
+
+@cindex sentinel frame
+@findex get_frame_type
+@vindex SENTINEL_FRAME
+To answer this question, GDB has the @dfn{sentinel} frame, the
+``-1st'' frame.  Unwinding registers from the sentinel frame gives you
+the current values of the youngest real frame's registers.  If @var{f}
+is a sentinel frame, then @code{get_frame_type (@var{f}) ==
+SENTINEL_FRAME}.
+
+@section Selecting an Unwinder
+
+The architecture registers a list of frame unwinders (@code{struct
+frame_unwind}), using the functions
+@code{frame_unwind_prepend_unwinder} and
+@code{frame_unwind_append_unwinder}.  Each unwinder includes a
+sniffer.  Whenever @value{GDBN} needs to unwind a frame (to fetch the
+previous frame's registers or the current frame's ID), it calls
+registered sniffers in order to find one which recognizes the frame.
+The first time a sniffer returns non-zero, the corresponding unwinder
+is assigned to the frame.
+
+@section Unwinding the Frame ID
+
+Every frame has an associated ID, of type @code{struct frame_id}.
+The ID includes the stack base and function start address for
+the frame.  The ID persists through the entire life of the frame,
+including while other called frames are running; it is used to
+locate an appropriate @code{struct frame_info} from the cache.
+
+The frame's unwinder's @code{this_id} method is called to find the ID.
+Note that this is different from register unwinding, where the next
+frame's @code{prev_register} is called to unwind this frame's
+registers.
+
+Both stack base and function address are required to identify the
+frame, because a recursive function has the same function address for
+two consecutive frames and a leaf function may have the same stack
+address as its caller.  On some platforms, a third address is part of
+the ID to further disambiguate frames---for instance, on IA-64
+the separate register stack address is included in the ID.
+
+An invalid frame ID (@code{null_frame_id}) returned from the
+@code{this_id} method means to stop unwinding after this frame.
+
+@section Unwinding Registers
+
+Each unwinder includes a @code{prev_register} method.  This method
+takes a frame, an associated cache pointer, and a register number.
+It returns a @code{struct value *} describing the requested register,
+as saved by this frame.  This is the value of the register that is
+current in this frame's caller.
+
+The returned value must have the same type as the register.  It may
+have any lval type.  In most circumstances one of these routines
+will generate the appropriate value:
+
+@table @code
+@item frame_unwind_got_optimized
+This register was not saved.
+
+@item frame_unwind_got_register
+This register was copied into another register in this frame.  This
+is also used for unchanged registers; they are ``copied'' into the
+same register.
+
+@item frame_unwind_got_memory
+This register was saved in memory.
+
+@item frame_unwind_got_constant
+This register was not saved, but the unwinder can compute the previous
+value some other way.
+
+@item frame_unwind_got_address
+Same as @code{frame_unwind_got_constant}, excep that the value is a target
+address.  This is frequently used for the stack pointer, which is not
+explicitly saved but has a known offset from this frame's stack
+pointer.  For architectures with a flat unified address space, this is
+generally the same as @code{frame_unwind_got_constant}.
+@end table
+
 @node Symbol Handling
 
 @chapter Symbol Handling
@@ -3920,14 +3993,6 @@ This method replaces @w{@code{gdbarch_ca
 Return the name of register @var{regnr} as a string.  May return @code{NULL}
 to indicate that @var{regnr} is not a valid register.
 
-@item SAVE_DUMMY_FRAME_TOS (@var{sp})
-@findex SAVE_DUMMY_FRAME_TOS
-@anchor{SAVE_DUMMY_FRAME_TOS} Used in @samp{call_function_by_hand} to
-notify the target dependent code of the top-of-stack value that will be
-passed to the inferior code.  This is the value of the @code{SP}
-after both the dummy frame and space for parameters/results have been
-allocated on the stack.  @xref{gdbarch_unwind_dummy_id}.
-
 @item int gdbarch_sdb_reg_to_regnum (@var{gdbarch}, @var{sdb_regnr})
 @findex gdbarch_sdb_reg_to_regnum
 Use this function to convert sdb register @var{sdb_regnr} into @value{GDBN}
@@ -4109,13 +4174,12 @@ the @code{opcodes} library (@pxref{Suppo
 @file{include/dis-asm.h} used to pass information to the instruction
 decoding routine.
 
-@item frame_id gdbarch_unwind_dummy_id (@var{gdbarch}, @var{frame})
-@findex gdbarch_unwind_dummy_id
-@anchor{gdbarch_unwind_dummy_id} Given @var{frame} return a @w{@code{struct
+@item frame_id gdbarch_dummy_id (@var{gdbarch}, @var{frame})
+@findex gdbarch_dummy_id
+@anchor{gdbarch_dummy_id} Given @var{frame} return a @w{@code{struct
 frame_id}} that uniquely identifies an inferior function call's dummy
 frame.  The value returned must match the dummy frame stack value
-previously saved using @code{SAVE_DUMMY_FRAME_TOS}.
-@xref{SAVE_DUMMY_FRAME_TOS}.
+previously saved by @code{call_function_by_hand}.
 
 @item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
 @findex DEPRECATED_USE_STRUCT_CONVENTION
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c	2008-03-31 13:47:54.000000000 -0400
+++ src/gdb/infcall.c	2008-03-31 13:48:20.000000000 -0400
@@ -462,7 +462,7 @@ call_function_by_hand (struct value *fun
 	 pushed) GDB won't be able to correctly perform back traces.
 	 If a target is having trouble with backtraces, first thing to
 	 do is add FRAME_ALIGN() to the architecture vector. If that
-	 fails, try unwind_dummy_id().
+	 fails, try dummy_id().
 
          If the ABI specifies a "Red Zone" (see the doco) the code
          below will quietly trash it.  */
@@ -656,7 +656,7 @@ call_function_by_hand (struct value *fun
      ID so that the breakpoint code can correctly re-identify the
      dummy breakpoint.  */
   /* Sanity.  The exact same SP value is returned by PUSH_DUMMY_CALL,
-     saved as the dummy-frame TOS, and used by unwind_dummy_id to form
+     saved as the dummy-frame TOS, and used by dummy_id to form
      the frame ID's stack address.  */
   dummy_id = frame_id_build (sp, bp_addr);
 
@@ -671,7 +671,7 @@ call_function_by_hand (struct value *fun
     sal.section = find_pc_overlay (sal.pc);
     /* Sanity.  The exact same SP value is returned by
        PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
-       unwind_dummy_id to form the frame ID's stack address.  */
+       dummy_id to form the frame ID's stack address.  */
     bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy);
     bpt->disposition = disp_del;
   }
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2008-03-31 14:36:27.000000000 -0400
+++ src/gdb/Makefile.in	2008-03-31 15:16:00.000000000 -0400
@@ -2119,7 +2119,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(
 	$(annotate_h) $(language_h) $(frame_unwind_h) $(frame_base_h) \
 	$(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h)
 frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
-	$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h)
+	$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h) $(value_h) \
+	$(regcache_h)
 frv-linux-tdep.o: frv-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \
 	$(frame_h) $(osabi_h) $(regcache_h) $(elf_bfd_h) $(elf_frv_h) \
 	$(frv_tdep_h) $(trad_frame_h) $(frame_unwind_h) $(regset_h) \


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
@ 2008-04-01 13:23 ` Eli Zaretskii
  2008-04-17 15:30   ` Daniel Jacobowitz
  2008-04-04 19:10 ` Joel Brobecker
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Eli Zaretskii @ 2008-04-01 13:23 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches

> Date: Mon, 31 Mar 2008 18:10:24 -0400
> From: Daniel Jacobowitz <drow@false.org>
> 
> 2008-03-31  Daniel Jacobowitz  <dan@codesourcery.com>
> 
> 	* gdbint.texinfo (Stack Frames): New chapter.
> 	(Algorithms): Move Frames text to the new chapter.
> 	(Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS.  Document
> 	gdbarch_dummy_id instead of gdbarch_unwind_dummy_id.

Thanks, this part is approved, but I have some comments:

> +@node Stack Frames
> +@chapter Stack Frames
> +
> +@cindex frame
> +@cindex call stack frame
> +A frame is a construct that @value{GDBN} uses to keep track of calling
> +and called functions.
> +
> +@cindex frame, unwind

It is not useful to have several index entries that begin with the
same string and point to the same page.  So I suggest to replace the
last one with "@cindex unwind frame".

> +Developers wishing to learn more about unwinders, are encouraged to
> +read the @sc{dwarf} specification.

How about a pointer to the DWARF Spec here?

> +is a sentinel frame, then @code{get_frame_type (@var{f}) ==
> +SENTINEL_FRAME}.

I would use @equiv{} here, of even @expansion{}, instead of a literal
"==".

> +@section Selecting an Unwinder

Is it a good idea to have a section without a node?

> +The architecture registers a list of frame unwinders (@code{struct
> +frame_unwind}), using the functions
> +@code{frame_unwind_prepend_unwinder} and
> +@code{frame_unwind_append_unwinder}.  Each unwinder includes a

Please add an @findex entry for each function you mention.

> +The returned value must have the same type as the register.  It may
> +have any lval type.

I think we should say "lvalue" here, not "lval".

> +Same as @code{frame_unwind_got_constant}, excep that the value is a target
                                             ^^^^^
A typo.


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
  2008-04-01 13:23 ` Eli Zaretskii
@ 2008-04-04 19:10 ` Joel Brobecker
  2008-04-17 15:59   ` Daniel Jacobowitz
  2008-04-04 19:16 ` Joel Brobecker
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 10+ messages in thread
From: Joel Brobecker @ 2008-04-04 19:10 UTC (permalink / raw)
  To: gdb-patches

> +struct value *
> +frame_unwind_register_value (struct frame_info *frame, int regnum)
> +{
> +  struct value *value;
> +
> +  if (frame_debug)
> +    {
> +      fprintf_unfiltered (gdb_stdlog, "\
> +{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
> +			  frame->level, regnum,
> +			  frame_map_regnum_to_name (frame, regnum));
> +    }
> +
> +  gdb_assert (frame != NULL);

The gdb_assert should be moved up before the "if (frame_debug)" block.
Otherwise, we'll bomb while dereferencing FRAME before we trip the
assertion. (I realize that this code was already like this before)

Other than that, I tried to read it as carefully as possible and
grasp as much of the big picture as I could, and it looked good
to me.

I can help with the conversion of some of the targets: hppa, ia64,
mips (but it would be better if someone having access to mips-linux
did it for me, mips-irix results are not stellar right now), powerpc,
and sparc. I can't test alpha anymore, for some reason dejagnu no
longer works on our Tru64 machines :-(.

-- 
Joel


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
  2008-04-01 13:23 ` Eli Zaretskii
  2008-04-04 19:10 ` Joel Brobecker
@ 2008-04-04 19:16 ` Joel Brobecker
  2008-04-07 19:34 ` Thiago Jung Bauermann
  2008-04-30 23:31 ` Daniel Jacobowitz
  4 siblings, 0 replies; 10+ messages in thread
From: Joel Brobecker @ 2008-04-04 19:16 UTC (permalink / raw)
  To: gdb-patches

> 	(frame_register_unwind): Remove debug messages.  Use
> 	frame_unwind_register_value.

It looks like we'll also be able to get rid of this function
at some point soon. As far as I can tell, I can only find 2 places
where it's being used:

  - mep-tdep.c: But this will disappear as soon as we convert
    the function using it;

  - stack.c:frame_info() I think we can adjust the code to use
    frame_unwind_register_value instead. The code looks like this:

        /* Find out the location of the saved stack pointer with out
           actually evaluating it.  */
        frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch),
                               &optimized, &lval, &addr,
                               &realnum, NULL);
        if (!optimized && lval == not_lval)
          {
            gdb_byte value[MAX_REGISTER_SIZE];
            CORE_ADDR sp;
            frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch),
                                   &optimized, &lval, &addr,
                                   &realnum, value);
            /* NOTE: cagney/2003-05-22: This is assuming that the
               stack pointer was packed as an unsigned integer.  That
               may or may not be valid.  */
            sp = extract_unsigned_integer (value,
                                           register_size (gdbarch,
                                           gdbarch_sp_regnum (gdbarch)));
            printf_filtered (" Previous frame's sp is ");
            fputs_filtered (paddress (sp), gdb_stdout);
            printf_filtered ("\n");
            need_nl = 0;
          }
        else if (!optimized && lval == lval_memory)
          {
            printf_filtered (" Previous frame's sp at ");
            fputs_filtered (paddress (addr), gdb_stdout);
            printf_filtered ("\n");
            need_nl = 0;
          }
        else if (!optimized && lval == lval_register)
          {
            printf_filtered (" Previous frame's sp in %s\n",
                             gdbarch_register_name (gdbarch, realnum));
            need_nl = 0;


-- 
Joel


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
                   ` (2 preceding siblings ...)
  2008-04-04 19:16 ` Joel Brobecker
@ 2008-04-07 19:34 ` Thiago Jung Bauermann
  2008-04-17 16:02   ` Daniel Jacobowitz
  2008-04-30 23:31 ` Daniel Jacobowitz
  4 siblings, 1 reply; 10+ messages in thread
From: Thiago Jung Bauermann @ 2008-04-07 19:34 UTC (permalink / raw)
  To: Daniel Jacobowitz; +Cc: gdb-patches

On Mon, 2008-03-31 at 18:10 -0400, Daniel Jacobowitz wrote:
> 2008-03-31  Daniel Jacobowitz  <dan@codesourcery.com>
> 
> 	Convert frame unwinders to use the current frame and
> 	"struct value".

My two cents.

> +      /* Offsets are not supported here; lazy register values must
> +	 refer to the entire register.  */
> +      gdb_assert (value_offset (val) == 0);

Is this a limitation of the current implementation or is there an
underlying reason for it?

> +      while (VALUE_LVAL (new_val) == lval_register
> +	     && value_lazy (new_val))
> +	{

The conditions in the while loop above fit in one line.

> +	  frame = frame_find_by_id (VALUE_FRAME_ID (new_val));

I thought it was strange that VALUE_FRAME_ID expands to a deprecated
function, since it plays such an important role in the new world
order... Do you know why it is deprecated?

> +struct value *
> +frame_unwind_got_address (struct frame_info *frame, int regnum,
> +			  CORE_ADDR addr)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  struct value *reg_val;
> +
> +  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
> +  pack_long (value_contents_writeable (reg_val),
> +	     register_type (gdbarch, regnum), addr);

This code assumes the register type is TYPE_CODE_PTR, right?
Does it make sense to put an assertion here?

> +      /* Use an architecture specific method to extract the this frame's
> +	 dummy ID, assuming it is a dummy frame.  */
> +      this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);

s/the this/this/

> +@section Selecting an Unwinder
> +
> +The architecture registers a list of frame unwinders (@code{struct
> +frame_unwind}), using the functions
> +@code{frame_unwind_prepend_unwinder} and
> +@code{frame_unwind_append_unwinder}.  Each unwinder includes a
> +sniffer.  Whenever @value{GDBN} needs to unwind a frame (to fetch the
> +previous frame's registers or the current frame's ID), it calls
> +registered sniffers in order to find one which recognizes the frame.
> +The first time a sniffer returns non-zero, the corresponding unwinder
> +is assigned to the frame.

What about changing the last sentence to "The first sniffer returning
non-zero will have its corresponding unwinder assigned to the frame."?

> +@section Unwinding the Frame ID
> +
> +Every frame has an associated ID, of type @code{struct frame_id}.
> +The ID includes the stack base and function start address for
> +the frame.  The ID persists through the entire life of the frame,
> +including while other called frames are running; it is used to
> +locate an appropriate @code{struct frame_info} from the cache.

This looks like a good place to explain the motivation behind frame IDs.
What about the following?

Every time the inferior stops, the frame cache is flushed. Because of
this, parts of @value{GDBN} which need to keep track of individual
frames cannot use pointers to @code{struct frame_info}. This is why
frame IDs are necessary, they provide a stable reference to a frame,
even when the unwinder needs to find it again and generate a new
@code{struct frame_info} for it.

> +The frame's unwinder's @code{this_id} method is called to find the ID.
> +Note that this is different from register unwinding, where the next
> +frame's @code{prev_register} is called to unwind this frame's
> +registers.
> +
> +Both stack base and function address are required to identify the
> +frame, because a recursive function has the same function address for
> +two consecutive frames and a leaf function may have the same stack
> +address as its caller.  On some platforms, a third address is part of
> +the ID to further disambiguate frames---for instance, on IA-64
> +the separate register stack address is included in the ID.
> +
> +An invalid frame ID (@code{null_frame_id}) returned from the
> +@code{this_id} method means to stop unwinding after this frame.

Is this a good place to list the other reasons to stop frame unwinding?
E.g.:

In addition, @value{GDBN} will stop unwinding after this frame if its ID
is inner to the next younger frame (i.e, the unwind is going backwards
in the stack frame), if its ID is equal to the ID of the next younger
frame, or if the unwinder was not able to find a saved program counter.
-- 
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-04-01 13:23 ` Eli Zaretskii
@ 2008-04-17 15:30   ` Daniel Jacobowitz
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-04-17 15:30 UTC (permalink / raw)
  To: gdb-patches

As usual, thank you for the comments.

On Tue, Apr 01, 2008 at 06:27:58AM +0300, Eli Zaretskii wrote:
> Thanks, this part is approved, but I have some comments:
> 
> > +@node Stack Frames
> > +@chapter Stack Frames
> > +
> > +@cindex frame
> > +@cindex call stack frame
> > +A frame is a construct that @value{GDBN} uses to keep track of calling
> > +and called functions.
> > +
> > +@cindex frame, unwind
> 
> It is not useful to have several index entries that begin with the
> same string and point to the same page.  So I suggest to replace the
> last one with "@cindex unwind frame".

Sure; I was just moving these, but let's take the opportunity to
improve it further.

> > +Developers wishing to learn more about unwinders, are encouraged to
> > +read the @sc{dwarf} specification.
> 
> How about a pointer to the DWARF Spec here?

Sounds good.  I expect it will stay on dwarfstd.org for a while; it's
had several homes in the last few years.

> > +is a sentinel frame, then @code{get_frame_type (@var{f}) ==
> > +SENTINEL_FRAME}.
> 
> I would use @equiv{} here, of even @expansion{}, instead of a literal
> "==".

Interesting, I didn't know about those.  I like the block
of C code -- if you want to check whether something is a sentinel
frame in GDB, you type get_frame_type (f) == SENTINEL_FRAME -- but
@equiv will do nicely too so I'll use that.

> > +@section Selecting an Unwinder
> 
> Is it a good idea to have a section without a node?

That's how most of the gdbint manual is currently arranged - one node
per chapter, except for a few more substantial ones.  I can move the
new sections into nodes if you think that's better.

> Please add an @findex entry for each function you mention.

Done.

> I think we should say "lvalue" here, not "lval".

Fixed.

> > +Same as @code{frame_unwind_got_constant}, excep that the value is a target
>                                              ^^^^^
> A typo.

Also fixed.

I'll repost the final patch in a little while.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-04-04 19:10 ` Joel Brobecker
@ 2008-04-17 15:59   ` Daniel Jacobowitz
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-04-17 15:59 UTC (permalink / raw)
  To: gdb-patches

On Fri, Apr 04, 2008 at 10:22:14AM -0700, Joel Brobecker wrote:
> The gdb_assert should be moved up before the "if (frame_debug)" block.
> Otherwise, we'll bomb while dereferencing FRAME before we trip the
> assertion. (I realize that this code was already like this before)

Thanks, fixed.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-04-07 19:34 ` Thiago Jung Bauermann
@ 2008-04-17 16:02   ` Daniel Jacobowitz
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-04-17 16:02 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches

On Mon, Apr 07, 2008 at 10:58:26AM -0300, Thiago Jung Bauermann wrote:
> My two cents.

Much appreciated.

> > +      /* Offsets are not supported here; lazy register values must
> > +	 refer to the entire register.  */
> > +      gdb_assert (value_offset (val) == 0);
> 
> Is this a limitation of the current implementation or is there an
> underlying reason for it?

You could call it either one.  I didn't add support for lazy registers
containing offsets because I don't think it's useful; lazy registers
are currently aimed to support unwinding, not to generally suppress
target fetches the way lazy memory values do.  And it keeps things
simpler if we know we've got the whole register.  So I've disallowed
it, and that way it will be clear where to start from if we want this
later.

> The conditions in the while loop above fit in one line.

So it does.

> > +	  frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
> 
> I thought it was strange that VALUE_FRAME_ID expands to a deprecated
> function, since it plays such an important role in the new world
> order... Do you know why it is deprecated?

It's deprecated because it's writable.  If it returned a read-only
copy of the frame ID, then there'd be no need to deprecate it; this
was added when struct value was moved from value.h to value.c.
Things like:

findvar.c:  VALUE_FRAME_ID (reg_val) = get_frame_id (frame);

Perhaps we need some new constructors.

> > +struct value *
> > +frame_unwind_got_address (struct frame_info *frame, int regnum,
> > +			  CORE_ADDR addr)
> > +{
> > +  struct gdbarch *gdbarch = get_frame_arch (frame);
> > +  struct value *reg_val;
> > +
> > +  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
> > +  pack_long (value_contents_writeable (reg_val),
> > +	     register_type (gdbarch, regnum), addr);
> 
> This code assumes the register type is TYPE_CODE_PTR, right?
> Does it make sense to put an assertion here?

No, I don't think so.  It will work OK for integers, too, and the
assertion could be triggered by bad debug information.  I don't like
to add asserts where a corrupt file could trigger them, unless the
alternative is crashing.

> s/the this/this/

Fixed.

> > +The first time a sniffer returns non-zero, the corresponding unwinder
> > +is assigned to the frame.
> 
> What about changing the last sentence to "The first sniffer returning
> non-zero will have its corresponding unwinder assigned to the frame."?

I don't think either is particularly clearer.

> This looks like a good place to explain the motivation behind frame IDs.
> What about the following?

Thanks.  I changed the wording a little, but basically used this.

> Is this a good place to list the other reasons to stop frame unwinding?

I'm not sure, so I've left it out for now.

-- 
Daniel Jacobowitz
CodeSourcery


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

* Re: [RFC 2/5] Frame unwinding using struct value
  2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
                   ` (3 preceding siblings ...)
  2008-04-07 19:34 ` Thiago Jung Bauermann
@ 2008-04-30 23:31 ` Daniel Jacobowitz
       [not found]   ` <20080430230012.GB3801@adacore.com>
  4 siblings, 1 reply; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-04-30 23:31 UTC (permalink / raw)
  To: gdb-patches

On Mon, Mar 31, 2008 at 06:10:24PM -0400, Daniel Jacobowitz wrote:
> The meat of the conversion.  This patch converts frame.c, all the
> related frame-unwind and frame-base code, and the dummy and sentinel
> unwinders.  It also includes helpers for writing new prev_register
> methods and a gdbint chapter.

I have now checked in the five patches I posted.  This was the only
one to be revised since posting, so here it is again.  I've tested
on i386, amd64, arm (patch coming), and mips (patch coming).

I am not planning to immediately convert the remaining targets myself.
But I'm glad to help anyone that has questions, and I've set up a Wiki
page with some additional notes and the list of remaining targets:

  http://sourceware.org/gdb/wiki/ValueBasedUnwinder

Any that are still left before the next release, I will do
mechanically.

-- 
Daniel Jacobowitz
CodeSourcery

2008-04-30  Daniel Jacobowitz  <dan@codesourcery.com>

	Convert frame unwinders to use the current frame and
	"struct value".

	* frame.c (frame_debug): Make global.
	(get_frame_id): Pass this frame to unwinder routines.
	(frame_pc_unwind): Remove unused unwind->prev_pc support.
	(do_frame_register_read): Do not discard the return value of
	frame_register_read.
	(frame_register_unwind): Remove debug messages.  Use
	frame_unwind_register_value.
	(frame_unwind_register_value, get_frame_register_value): New
	functions.
	(create_new_frame, get_frame_base_address, get_frame_locals_address)
	(get_frame_args_address, get_frame_type): Pass this frame to
	unwinder routines.
	(frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New
	functions.
	* frame.h: Update comments.
	(frame_debug, frame_unwind_register_value, get_frame_register_value)
	(frame_prepare_for_sniffer): Declare.
	* frame-unwind.h: Update comments and parameter names.
	(default_frame_sniffer): Declare.
	(frame_prev_register_ftype): Return a struct value *.
	(struct frame_unwind): Remove prev_pc member.
	(frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): Declare.
	* frame-base.h: Update comments and parameter names.
	* valops.c (value_fetch_lazy): Use get_frame_register_value.  Iterate
	if necessary.  Add debugging output.
	* sentinel-frame.c (sentinel_frame_prev_register)
	(sentinel_frame_this_id): Update for new signature.
	(sentinel_frame_prev_pc): Delete.
	(sentinel_frame_unwinder): Remove prev_pc.
	* ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize
	prev_pc.
	* libunwind-frame.c (libunwind_frame_unwind): Likewise.
	* frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer.
	(frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder): New function.
	(frame_unwind_find_by_frame): Take this frame.  Only use sniffers
	from unwinders.  Use frame_prepare_for_sniffer.
	(default_frame_sniffer, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): New functions.
	* dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id.
	(dummy_frame_prev_register, dummy_frame_this_id): Update for new
	signature.
	* gdbarch.sh: Replace unwind_dummy_id with dummy_id.
	* gdbarch.c, gdbarch.c: Regenerated.
	* frame-base.c (default_frame_base_address)
	(default_frame_locals_address, default_frame_args_address): Update
	for new signature.
	(frame_base_find_by_frame): Pass this frame to unwinder routines.
	* infcall.c (call_function_by_hand): Update comments.
	* Makefile.in (frame-unwind.o): Update dependencies.

2008-04-30  Daniel Jacobowitz  <dan@codesourcery.com>

	* gdbint.texinfo (Stack Frames): New chapter.
	(Algorithms): Move Frames text to the new chapter.
	(Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS.  Document
	gdbarch_dummy_id instead of gdbarch_unwind_dummy_id.

---
 gdb/Makefile.in        |    3 
 gdb/doc/gdbint.texinfo |  172 +++++++++++++++++++++++++++++-----------
 gdb/dummy-frame.c      |   53 +++++-------
 gdb/frame-base.c       |   17 +--
 gdb/frame-base.h       |   18 ++--
 gdb/frame-unwind.c     |  136 +++++++++++++++++++++++++------
 gdb/frame-unwind.h     |  109 ++++++++++++++-----------
 gdb/frame.c            |  210 ++++++++++++++++++++++++++++++++-----------------
 gdb/frame.h            |   18 +++-
 gdb/gdbarch.c          |   36 ++++----
 gdb/gdbarch.h          |   10 +-
 gdb/gdbarch.sh         |    4 
 gdb/ia64-tdep.c        |    1 
 gdb/infcall.c          |    6 -
 gdb/libunwind-frame.c  |    1 
 gdb/sentinel-frame.c   |   54 ++++--------
 gdb/valops.c           |   91 +++++++++++++++++----
 17 files changed, 619 insertions(+), 320 deletions(-)

Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame.c	2008-04-17 11:29:36.000000000 -0400
@@ -113,7 +113,7 @@ struct frame_info
 
 /* Flag to control debugging.  */
 
-static int frame_debug;
+int frame_debug;
 static void
 show_frame_debug (struct ui_file *file, int from_tty,
 		  struct cmd_list_element *c, const char *value)
@@ -255,10 +255,9 @@ get_frame_id (struct frame_info *fi)
 			    fi->level);
       /* Find the unwinder.  */
       if (fi->unwind == NULL)
-	fi->unwind = frame_unwind_find_by_frame (fi->next,
-						 &fi->prologue_cache);
+	fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
       /* Find THIS frame's ID.  */
-      fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
+      fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
       fi->this_id.p = 1;
       if (frame_debug)
 	{
@@ -427,15 +426,7 @@ frame_pc_unwind (struct frame_info *this
   if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
-      if (this_frame->unwind == NULL)
-	this_frame->unwind
-	  = frame_unwind_find_by_frame (this_frame->next,
-					&this_frame->prologue_cache);
-      if (this_frame->unwind->prev_pc != NULL)
-	/* A per-frame unwinder, prefer it.  */
-	pc = this_frame->unwind->prev_pc (this_frame->next,
-					  &this_frame->prologue_cache);
-      else if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
+      if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
 	{
 	  /* The right way.  The `pure' way.  The one true way.  This
 	     method depends solely on the register-unwind code to
@@ -495,8 +486,7 @@ get_frame_func (struct frame_info *fi)
 static int
 do_frame_register_read (void *src, int regnum, gdb_byte *buf)
 {
-  frame_register_read (src, regnum, buf);
-  return 1;
+  return frame_register_read (src, regnum, buf);
 }
 
 struct regcache *
@@ -552,15 +542,7 @@ frame_register_unwind (struct frame_info
 		       int *optimizedp, enum lval_type *lvalp,
 		       CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
 {
-  struct frame_unwind_cache *cache;
-
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "\
-{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
-			  frame->level, regnum,
-			  frame_map_regnum_to_name (frame, regnum));
-    }
+  struct value *value;
 
   /* Require all but BUFFERP to be valid.  A NULL BUFFERP indicates
      that the value proper does not need to be fetched.  */
@@ -570,43 +552,23 @@ frame_register_unwind (struct frame_info
   gdb_assert (realnump != NULL);
   /* gdb_assert (bufferp != NULL); */
 
-  /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
-     is broken.  There is always a frame.  If there, for some reason,
-     isn't a frame, there is some pretty busted code as it should have
-     detected the problem before calling here.  */
-  gdb_assert (frame != NULL);
-
-  /* Find the unwinder.  */
-  if (frame->unwind == NULL)
-    frame->unwind = frame_unwind_find_by_frame (frame->next,
-						&frame->prologue_cache);
+  value = frame_unwind_register_value (frame, regnum);
 
-  /* Ask this frame to unwind its register.  See comment in
-     "frame-unwind.h" for why NEXT frame and this unwind cache are
-     passed in.  */
-  frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
-				optimizedp, lvalp, addrp, realnump, bufferp);
+  gdb_assert (value != NULL);
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "->");
-      fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
-      fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
-      fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
-      fprintf_unfiltered (gdb_stdlog, " *bufferp=");
-      if (bufferp == NULL)
-	fprintf_unfiltered (gdb_stdlog, "<NULL>");
-      else
-	{
-	  int i;
-	  const unsigned char *buf = bufferp;
-	  fprintf_unfiltered (gdb_stdlog, "[");
-	  for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
-	    fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
-	  fprintf_unfiltered (gdb_stdlog, "]");
-	}
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+  *optimizedp = value_optimized_out (value);
+  *lvalp = VALUE_LVAL (value);
+  *addrp = VALUE_ADDRESS (value);
+  *realnump = VALUE_REGNUM (value);
+
+  if (bufferp)
+    memcpy (bufferp, value_contents_all (value),
+	    TYPE_LENGTH (value_type (value)));
+
+  /* Dispose of the new value.  This prevents watchpoints from
+     trying to watch the saved frame pointer.  */
+  release_value (value);
+  value_free (value);
 }
 
 void
@@ -647,6 +609,71 @@ get_frame_register (struct frame_info *f
   frame_unwind_register (frame->next, regnum, buf);
 }
 
+struct value *
+frame_unwind_register_value (struct frame_info *frame, int regnum)
+{
+  struct value *value;
+
+  gdb_assert (frame != NULL);
+
+  if (frame_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "\
+{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
+			  frame->level, regnum,
+			  frame_map_regnum_to_name (frame, regnum));
+    }
+
+  /* Find the unwinder.  */
+  if (frame->unwind == NULL)
+    frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
+
+  /* Ask this frame to unwind its register.  */
+  value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
+
+  if (frame_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "->");
+      if (value_optimized_out (value))
+	fprintf_unfiltered (gdb_stdlog, " optimized out");
+      else
+	{
+	  if (VALUE_LVAL (value) == lval_register)
+	    fprintf_unfiltered (gdb_stdlog, " register=%d",
+				VALUE_REGNUM (value));
+	  else if (VALUE_LVAL (value) == lval_memory)
+	    fprintf_unfiltered (gdb_stdlog, " address=0x%s",
+				paddr_nz (VALUE_ADDRESS (value)));
+	  else
+	    fprintf_unfiltered (gdb_stdlog, " computed");
+
+	  if (value_lazy (value))
+	    fprintf_unfiltered (gdb_stdlog, " lazy");
+	  else
+	    {
+	      int i;
+	      const gdb_byte *buf = value_contents (value);
+
+	      fprintf_unfiltered (gdb_stdlog, " bytes=");
+	      fprintf_unfiltered (gdb_stdlog, "[");
+	      for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
+		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+	      fprintf_unfiltered (gdb_stdlog, "]");
+	    }
+	}
+
+      fprintf_unfiltered (gdb_stdlog, " }\n");
+    }
+
+  return value;
+}
+
+struct value *
+get_frame_register_value (struct frame_info *frame, int regnum)
+{
+  return frame_unwind_register_value (frame->next, regnum);
+}
+
 LONGEST
 frame_unwind_register_signed (struct frame_info *frame, int regnum)
 {
@@ -1022,7 +1049,7 @@ create_new_frame (CORE_ADDR addr, CORE_A
 
   /* Select/initialize both the unwind function and the frame's type
      based on the PC.  */
-  fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache);
+  fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
 
   fi->this_id.p = 1;
   deprecated_update_frame_base_hack (fi, addr);
@@ -1569,8 +1596,8 @@ get_frame_base_address (struct frame_inf
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    return fi->base->this_base (fi->next, &fi->prologue_cache);
-  return fi->base->this_base (fi->next, &fi->base_cache);
+    return fi->base->this_base (fi, &fi->prologue_cache);
+  return fi->base->this_base (fi, &fi->base_cache);
 }
 
 CORE_ADDR
@@ -1585,10 +1612,8 @@ get_frame_locals_address (struct frame_i
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    cache = &fi->prologue_cache;
-  else
-    cache = &fi->base_cache;
-  return fi->base->this_locals (fi->next, cache);
+    return fi->base->this_locals (fi, &fi->prologue_cache);
+  return fi->base->this_locals (fi, &fi->base_cache);
 }
 
 CORE_ADDR
@@ -1603,10 +1628,8 @@ get_frame_args_address (struct frame_inf
   /* Sneaky: If the low-level unwind and high-level base code share a
      common unwinder, let them share the prologue cache.  */
   if (fi->base->unwind == fi->unwind)
-    cache = &fi->prologue_cache;
-  else
-    cache = &fi->base_cache;
-  return fi->base->this_args (fi->next, cache);
+    return fi->base->this_args (fi, &fi->prologue_cache);
+  return fi->base->this_args (fi, &fi->base_cache);
 }
 
 /* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@@ -1627,8 +1650,7 @@ get_frame_type (struct frame_info *frame
   if (frame->unwind == NULL)
     /* Initialize the frame's unwinder because that's what
        provides the frame's type.  */
-    frame->unwind = frame_unwind_find_by_frame (frame->next, 
-						&frame->prologue_cache);
+    frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
   return frame->unwind->type;
 }
 
@@ -1769,6 +1791,50 @@ frame_stop_reason_string (enum unwind_st
     }
 }
 
+/* Clean up after a failed (wrong unwinder) attempt to unwind past
+   FRAME.  */
+
+static void
+frame_cleanup_after_sniffer (void *arg)
+{
+  struct frame_info *frame = arg;
+
+  /* The sniffer should not allocate a prologue cache if it did not
+     match this frame.  */
+  gdb_assert (frame->prologue_cache == NULL);
+
+  /* No sniffer should extend the frame chain; sniff based on what is
+     already certain.  */
+  gdb_assert (!frame->prev_p);
+
+  /* The sniffer should not check the frame's ID; that's circular.  */
+  gdb_assert (!frame->this_id.p);
+
+  /* Clear cached fields dependent on the unwinder.
+
+     The previous PC is independent of the unwinder, but the previous
+     function is not (see frame_unwind_address_in_block).  */
+  frame->prev_func.p = 0;
+  frame->prev_func.addr = 0;
+
+  /* Discard the unwinder last, so that we can easily find it if an assertion
+     in this function triggers.  */
+  frame->unwind = NULL;
+}
+
+/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
+   Return a cleanup which should be called if unwinding fails, and
+   discarded if it succeeds.  */
+
+struct cleanup *
+frame_prepare_for_sniffer (struct frame_info *frame,
+			   const struct frame_unwind *unwind)
+{
+  gdb_assert (frame->unwind == NULL);
+  frame->unwind = unwind;
+  return make_cleanup (frame_cleanup_after_sniffer, frame);
+}
+
 extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
 
 static struct cmd_list_element *set_backtrace_cmdlist;
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame.h	2008-04-17 11:16:19.000000000 -0400
@@ -144,6 +144,10 @@ struct frame_id
 /* For convenience.  All fields are zero.  */
 extern const struct frame_id null_frame_id;
 
+/* Flag to control debugging.  */
+
+extern int frame_debug;
+
 /* Construct a frame ID.  The first parameter is the frame's constant
    stack address (typically the outer-bound), and the second the
    frame's constant code address (typically the entry point).
@@ -460,13 +464,19 @@ extern void frame_register_unwind (struc
 /* Fetch a register from this, or unwind a register from the next
    frame.  Note that the get_frame methods are wrappers to
    frame->next->unwind.  They all [potentially] throw an error if the
-   fetch fails.  */
+   fetch fails.  The value methods never return NULL, but usually
+   do return a lazy value.  */
 
 extern void frame_unwind_register (struct frame_info *frame,
 				   int regnum, gdb_byte *buf);
 extern void get_frame_register (struct frame_info *frame,
 				int regnum, gdb_byte *buf);
 
+struct value *frame_unwind_register_value (struct frame_info *frame,
+					   int regnum);
+struct value *get_frame_register_value (struct frame_info *frame,
+					int regnum);
+
 extern LONGEST frame_unwind_register_signed (struct frame_info *frame,
 					     int regnum);
 extern LONGEST get_frame_register_signed (struct frame_info *frame,
@@ -666,6 +676,12 @@ extern void (*deprecated_selected_frame_
 
 extern void return_command (char *, int);
 
+/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
+   Return a cleanup which should be called if unwinding fails, and
+   discarded if it succeeds.  */
+
+struct cleanup *frame_prepare_for_sniffer (struct frame_info *frame,
+					   const struct frame_unwind *unwind);
 
 /* Notes (cagney/2002-11-27, drow/2003-09-06):
 
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame-unwind.h	2008-04-17 11:16:19.000000000 -0400
@@ -26,6 +26,7 @@ struct frame_id;
 struct frame_unwind;
 struct gdbarch;
 struct regcache;
+struct value;
 
 #include "frame.h"		/* For enum frame_type.  */
 
@@ -41,17 +42,24 @@ struct regcache;
    as where this frame's prologue stores the previous frame's
    registers.  */
 
-/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
+/* Given THIS frame, take a whiff of its registers (namely
    the PC and attributes) and if SELF is the applicable unwinder,
    return non-zero.  Possibly also initialize THIS_PROLOGUE_CACHE.  */
 
 typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
-				   struct frame_info *next_frame,
+				   struct frame_info *this_frame,
 				   void **this_prologue_cache);
 
+/* A default frame sniffer which always accepts the frame.  Used by
+   fallback prologue unwinders.  */
+
+int default_frame_sniffer (const struct frame_unwind *self,
+			   struct frame_info *this_frame,
+			   void **this_prologue_cache);
+
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to determine
-   the frame ID of THIS frame.
+   use THIS frame, and through it the NEXT frame's register unwind
+   method, to determine the frame ID of THIS frame.
 
    A frame ID provides an invariant that can be used to re-identify an
    instance of a frame.  It is a combination of the frame's `base' and
@@ -72,14 +80,14 @@ typedef int (frame_sniffer_ftype) (const
    with the other unwind methods.  Memory for that cache should be
    allocated using FRAME_OBSTACK_ZALLOC().  */
 
-typedef void (frame_this_id_ftype) (struct frame_info *next_frame,
+typedef void (frame_this_id_ftype) (struct frame_info *this_frame,
 				    void **this_prologue_cache,
 				    struct frame_id *this_id);
 
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to unwind THIS
-   frame's registers (returning the value of the specified register
-   REGNUM in the previous frame).
+   use THIS frame, and implicitly the NEXT frame's register unwind
+   method, to unwind THIS frame's registers (returning the value of
+   the specified register REGNUM in the previous frame).
 
    Traditionally, THIS frame's registers were unwound by examining
    THIS frame's function's prologue and identifying which registers
@@ -91,37 +99,22 @@ typedef void (frame_this_id_ftype) (stru
    register in the previous frame is found in memory at SP+12, and
    THIS frame's SP can be obtained by unwinding the NEXT frame's SP.
 
-   Why not pass in THIS_FRAME?  By passing in NEXT frame and THIS
-   cache, the supplied parameters are consistent with the sibling
-   function THIS_ID.
-
-   Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''?
-   Won't the call frame_register (THIS_FRAME) be faster?  Well,
-   ignoring the possability that the previous frame does not yet
-   exist, the ``frame_register (FRAME)'' function is expanded to
-   ``frame_register_unwind (get_next_frame (FRAME)'' and hence that
-   call will expand to ``frame_register_unwind (get_next_frame
-   (get_prev_frame (NEXT_FRAME)))''.  Might as well call
-   ``frame_register_unwind (NEXT_FRAME)'' directly.
+   This function takes THIS_FRAME as an argument.  It can find the
+   values of registers in THIS frame by calling get_frame_register
+   (THIS_FRAME), and reinvoke itself to find other registers in the
+   PREVIOUS frame by calling frame_unwind_register (THIS_FRAME).
+
+   The result is a GDB value object describing the register value.  It
+   may be a lazy reference to memory, a lazy reference to the value of
+   a register in THIS frame, or a non-lvalue.
 
    THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
    with the other unwind methods.  Memory for that cache should be
    allocated using FRAME_OBSTACK_ZALLOC().  */
 
-typedef void (frame_prev_register_ftype) (struct frame_info *next_frame,
-					  void **this_prologue_cache,
-					  int prev_regnum,
-					  int *optimized,
-					  enum lval_type * lvalp,
-					  CORE_ADDR *addrp,
-					  int *realnump, gdb_byte *valuep);
-
-/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   use the NEXT frame, and its register unwind method, to return the PREV
-   frame's program-counter.  */
-
-typedef CORE_ADDR (frame_prev_pc_ftype) (struct frame_info *next_frame,
-					 void **this_prologue_cache);
+typedef struct value * (frame_prev_register_ftype)
+  (struct frame_info *this_frame, void **this_prologue_cache,
+   int regnum);
 
 /* Deallocate extra memory associated with the frame cache if any.  */
 
@@ -139,7 +132,6 @@ struct frame_unwind
   frame_prev_register_ftype *prev_register;
   const struct frame_data *unwind_data;
   frame_sniffer_ftype *sniffer;
-  frame_prev_pc_ftype *prev_pc;
   frame_dealloc_cache_ftype *dealloc_cache;
 };
 
@@ -152,23 +144,50 @@ struct frame_unwind
 extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
 					   const struct frame_unwind *unwinder);
 
-/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
-   the PC and attributes) and if it is the applicable unwinder return
-   the unwind methods, or NULL if it is not.  */
-
-typedef const struct frame_unwind *(frame_unwind_sniffer_ftype) (struct frame_info *next_frame);
-
 /* Add a frame sniffer to the list.  The predicates are polled in the
    order that they are appended.  The initial list contains the dummy
    frame sniffer.  */
 
-extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch,
-					 frame_unwind_sniffer_ftype *sniffer);
+extern void frame_unwind_append_unwinder (struct gdbarch *gdbarch,
+					  const struct frame_unwind *unwinder);
 
-/* Iterate through the next frame's sniffers until one returns with an
+/* Iterate through sniffers for THIS frame until one returns with an
    unwinder implementation.  Possibly initialize THIS_CACHE.  */
 
-extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame,
+extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *this_frame,
 							      void **this_cache);
 
+/* Helper functions for value-based register unwinding.  These return
+   a (possibly lazy) value of the appropriate type.  */
+
+/* Return a value which indicates that FRAME did not save REGNUM.  */
+
+struct value *frame_unwind_got_optimized (struct frame_info *frame,
+					  int regnum);
+
+/* Return a value which indicates that FRAME copied REGNUM into
+   register NEW_REGNUM.  */
+
+struct value *frame_unwind_got_register (struct frame_info *frame, int regnum,
+					 int new_regnum);
+
+/* Return a value which indicates that FRAME saved REGNUM in memory at
+   ADDR.  */
+
+struct value *frame_unwind_got_memory (struct frame_info *frame, int regnum,
+				       CORE_ADDR addr);
+
+/* Return a value which indicates that FRAME's saved version of
+   REGNUM has a known constant (computed) value of VAL.  */
+
+struct value *frame_unwind_got_constant (struct frame_info *frame, int regnum,
+					 ULONGEST val);
+
+/* Return a value which indicates that FRAME's saved version of REGNUM
+   has a known constant (computed) value of ADDR.  Convert the
+   CORE_ADDR to a target address if necessary.  */
+
+struct value *frame_unwind_got_address (struct frame_info *frame, int regnum,
+					CORE_ADDR addr);
+
 #endif
Index: src/gdb/frame-base.h
===================================================================
--- src.orig/gdb/frame-base.h	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame-base.h	2008-04-17 11:16:19.000000000 -0400
@@ -28,9 +28,9 @@ struct gdbarch;
 struct regcache;
 
 /* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
-   and that this is a `normal frame'; use the NEXT frame, and its
-   register unwind method, to determine the address of THIS frame's
-   `base'.
+   and that this is a `normal frame'; use THIS frame, and implicitly
+   the NEXT frame's register unwind method, to determine the address
+   of THIS frame's `base'.
 
    The exact meaning of `base' is highly dependant on the type of the
    debug info.  It is assumed that dwarf2, stabs, ... will each
@@ -42,17 +42,17 @@ struct regcache;
 
 /* A generic base address.  */
 
-typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *this_frame,
 					   void **this_base_cache);
 
 /* The base address of the frame's local variables.  */
 
-typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *this_frame,
 					     void **this_base_cache);
 
 /* The base address of the frame's arguments / parameters.  */
 
-typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame,
+typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *this_frame,
 					   void **this_base_cache);
 
 struct frame_base
@@ -65,10 +65,10 @@ struct frame_base
   frame_this_args_ftype *this_args;
 };
 
-/* Given the NEXT frame, return the frame base methods for THIS frame,
+/* Given THIS frame, return the frame base methods for THIS frame,
    or NULL if it can't handle THIS frame.  */
 
-typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *next_frame);
+typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *this_frame);
 
 /* Append a frame base sniffer to the list.  The sniffers are polled
    in the order that they are appended.  */
@@ -86,6 +86,6 @@ extern void frame_base_set_default (stru
 /* Iterate through the list of frame base handlers until one returns
    an implementation.  */
 
-extern const struct frame_base *frame_base_find_by_frame (struct frame_info *next_frame);
+extern const struct frame_base *frame_base_find_by_frame (struct frame_info *this_frame);
 
 #endif
Index: src/gdb/valops.c
===================================================================
--- src.orig/gdb/valops.c	2008-04-17 11:11:41.000000000 -0400
+++ src/gdb/valops.c	2008-04-17 11:32:53.000000000 -0400
@@ -622,24 +622,87 @@ value_fetch_lazy (struct value *val)
     }
   else if (VALUE_LVAL (val) == lval_register)
     {
-      struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (val));
-      int regnum = VALUE_REGNUM (val);
+      struct frame_info *frame;
+      int regnum;
       struct type *type = check_typedef (value_type (val));
+      struct value *new_val = val, *mark = value_mark ();
 
-      gdb_assert (frame != NULL);
+      /* Offsets are not supported here; lazy register values must
+	 refer to the entire register.  */
+      gdb_assert (value_offset (val) == 0);
 
-      /* Convertible register routines are used for multi-register
-	 values and for interpretation in different types (e.g. float
-	 or int from a double register).  Lazy register values should
-	 have the register's natural type, so they do not apply.  */
-      gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), regnum,
-					       type));
-
-      /* Get the data.  */
-      if (!get_frame_register_bytes (frame, regnum, value_offset (val),
-				     TYPE_LENGTH (value_type (val)),
-				     value_contents_raw (val)))
+      while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
+	{
+	  frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
+	  regnum = VALUE_REGNUM (new_val);
+
+	  gdb_assert (frame != NULL);
+
+	  /* Convertible register routines are used for multi-register
+	     values and for interpretation in different types
+	     (e.g. float or int from a double register).  Lazy
+	     register values should have the register's natural type,
+	     so they do not apply.  */
+	  gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
+						   regnum, type));
+
+	  new_val = get_frame_register_value (frame, regnum);
+	}
+
+      /* If it's still lazy (for instance, a saved register on the
+	 stack), fetch it.  */
+      if (value_lazy (new_val))
+	value_fetch_lazy (new_val);
+
+      /* If the register was not saved, mark it unavailable.  */
+      if (value_optimized_out (new_val))
 	set_value_optimized_out (val, 1);
+      else
+	memcpy (value_contents_raw (val), value_contents (new_val),
+		TYPE_LENGTH (type));
+
+      if (frame_debug)
+	{
+	  frame = frame_find_by_id (VALUE_FRAME_ID (val));
+	  regnum = VALUE_REGNUM (val);
+
+	  fprintf_unfiltered (gdb_stdlog, "\
+{ value_fetch_lazy (frame=%d,regnum=%d(%s),...) ",
+			      frame_relative_level (frame), regnum,
+			      frame_map_regnum_to_name (frame, regnum));
+
+	  fprintf_unfiltered (gdb_stdlog, "->");
+	  if (value_optimized_out (new_val))
+	    fprintf_unfiltered (gdb_stdlog, " optimized out");
+	  else
+	    {
+	      int i;
+	      const gdb_byte *buf = value_contents (new_val);
+
+	      if (VALUE_LVAL (new_val) == lval_register)
+		fprintf_unfiltered (gdb_stdlog, " register=%d",
+				    VALUE_REGNUM (new_val));
+	      else if (VALUE_LVAL (new_val) == lval_memory)
+		fprintf_unfiltered (gdb_stdlog, " address=0x%s",
+				    paddr_nz (VALUE_ADDRESS (new_val)));
+	      else
+		fprintf_unfiltered (gdb_stdlog, " computed");
+
+	      fprintf_unfiltered (gdb_stdlog, " bytes=");
+	      fprintf_unfiltered (gdb_stdlog, "[");
+	      for (i = 0;
+		   i < register_size (get_frame_arch (frame), regnum);
+		   i++)
+		fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
+	      fprintf_unfiltered (gdb_stdlog, "]");
+	    }
+
+	  fprintf_unfiltered (gdb_stdlog, " }\n");
+	}
+
+      /* Dispose of the intermediate values.  This prevents
+	 watchpoints from trying to watch the saved frame pointer.  */
+      value_free_to_mark (mark);
     }
   else
     internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/sentinel-frame.c	2008-04-17 11:16:19.000000000 -0400
@@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *r
 
 /* Here the register value is taken direct from the register cache.  */
 
-static void
-sentinel_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+sentinel_frame_prev_register (struct frame_info *this_frame,
 			      void **this_prologue_cache,
-			      int regnum, int *optimized,
-			      enum lval_type *lvalp, CORE_ADDR *addrp,
-			      int *realnum, gdb_byte *bufferp)
+			      int regnum)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_cache *cache = *this_prologue_cache;
-  /* Describe the register's location.  A reg-frame maps all registers
-     onto the corresponding hardware register.  */
-  *optimized = 0;
-  *lvalp = lval_register;
-  *addrp = 0;
-  *realnum = regnum;
-
-  /* If needed, find and return the value of the register.  */
-  if (bufferp != NULL)
-    {
-      /* Return the actual value.  */
-      /* Use the regcache_cooked_read() method so that it, on the fly,
-         constructs either a raw or pseudo register from the raw
-         register cache.  */
-      regcache_cooked_read (cache->regcache, regnum, bufferp);
-    }
+  struct value *value;
+
+  /* Return the actual value.  */
+  value = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (value) = lval_register;
+  VALUE_REGNUM (value) = regnum;
+  VALUE_FRAME_ID (value) = get_frame_id (this_frame);
+
+  /* Use the regcache_cooked_read() method so that it, on the fly,
+     constructs either a raw or pseudo register from the raw
+     register cache.  */
+  regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
+
+  return value;
 }
 
 static void
-sentinel_frame_this_id (struct frame_info *next_frame,
+sentinel_frame_this_id (struct frame_info *this_frame,
 			void **this_prologue_cache,
 			struct frame_id *this_id)
 {
@@ -79,22 +76,11 @@ sentinel_frame_this_id (struct frame_inf
   internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
 }
 
-static CORE_ADDR
-sentinel_frame_prev_pc (struct frame_info *next_frame,
-			void **this_prologue_cache)
-{
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
-  return gdbarch_unwind_pc (gdbarch, next_frame);
-}
-
 const struct frame_unwind sentinel_frame_unwinder =
 {
   SENTINEL_FRAME,
   sentinel_frame_this_id,
-  sentinel_frame_prev_register,
-  NULL, /* unwind_data */
-  NULL, /* sniffer */
-  sentinel_frame_prev_pc,
+  sentinel_frame_prev_register
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
Index: src/gdb/ia64-tdep.c
===================================================================
--- src.orig/gdb/ia64-tdep.c	2008-04-17 11:09:20.000000000 -0400
+++ src/gdb/ia64-tdep.c	2008-04-17 11:16:19.000000000 -0400
@@ -2796,7 +2796,6 @@ static const struct frame_unwind ia64_li
   ia64_libunwind_frame_prev_register,
   NULL,
   NULL,
-  NULL,
   libunwind_frame_dealloc_cache
 };
 
Index: src/gdb/libunwind-frame.c
===================================================================
--- src.orig/gdb/libunwind-frame.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/libunwind-frame.c	2008-04-17 11:16:19.000000000 -0400
@@ -214,7 +214,6 @@ static const struct frame_unwind libunwi
   libunwind_frame_prev_register,
   NULL,
   NULL,
-  NULL,
   libunwind_frame_dealloc_cache
 };
 
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame-unwind.c	2008-04-17 11:16:19.000000000 -0400
@@ -20,15 +20,17 @@
 #include "defs.h"
 #include "frame.h"
 #include "frame-unwind.h"
-#include "gdb_assert.h"
 #include "dummy-frame.h"
+#include "value.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
 #include "gdb_obstack.h"
 
 static struct gdbarch_data *frame_unwind_data;
 
 struct frame_unwind_table_entry
 {
-  frame_unwind_sniffer_ftype *sniffer;
   const struct frame_unwind *unwinder;
   struct frame_unwind_table_entry *next;
 };
@@ -55,19 +57,6 @@ frame_unwind_init (struct obstack *obsta
 }
 
 void
-frame_unwind_append_sniffer (struct gdbarch *gdbarch,
-			     frame_unwind_sniffer_ftype *sniffer)
-{
-  struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
-  struct frame_unwind_table_entry **ip;
-
-  /* Find the end of the list and insert the new entry there.  */
-  for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
-  (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
-  (*ip)->sniffer = sniffer;
-}
-
-void
 frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
 				const struct frame_unwind *unwinder)
 {
@@ -81,32 +70,123 @@ frame_unwind_prepend_unwinder (struct gd
   (*table->osabi_head) = entry;
 }
 
+void
+frame_unwind_append_unwinder (struct gdbarch *gdbarch,
+			      const struct frame_unwind *unwinder)
+{
+  struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
+  struct frame_unwind_table_entry **ip;
+
+  /* Find the end of the list and insert the new entry there.  */
+  for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
+  (*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
+  (*ip)->unwinder = unwinder;
+}
+
 const struct frame_unwind *
-frame_unwind_find_by_frame (struct frame_info *next_frame, void **this_cache)
+frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
 {
   int i;
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
   struct frame_unwind_table_entry *entry;
+  struct cleanup *old_cleanup;
   for (entry = table->list; entry != NULL; entry = entry->next)
     {
-      if (entry->sniffer != NULL)
-	{
-	  const struct frame_unwind *desc = NULL;
-	  desc = entry->sniffer (next_frame);
-	  if (desc != NULL)
-	    return desc;
-	}
-      if (entry->unwinder != NULL)
+      struct cleanup *old_cleanup;
+
+      old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
+      if (entry->unwinder->sniffer (entry->unwinder, this_frame,
+				    this_cache))
 	{
-	  if (entry->unwinder->sniffer (entry->unwinder, next_frame,
-					this_cache))
-	    return entry->unwinder;
+	  discard_cleanups (old_cleanup);
+	  return entry->unwinder;
 	}
+      do_cleanups (old_cleanup);
     }
   internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
 }
 
+/* A default frame sniffer which always accepts the frame.  Used by
+   fallback prologue unwinders.  */
+
+int
+default_frame_sniffer (const struct frame_unwind *self,
+		       struct frame_info *this_frame,
+		       void **this_prologue_cache)
+{
+  return 1;
+}
+
+/* Helper functions for value-based register unwinding.  These return
+   a (possibly lazy) value of the appropriate type.  */
+
+/* Return a value which indicates that FRAME did not save REGNUM.  */
+
+struct value *
+frame_unwind_got_optimized (struct frame_info *frame, int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  set_value_optimized_out (reg_val, 1);
+  return reg_val;
+}
+
+/* Return a value which indicates that FRAME copied REGNUM into
+   register NEW_REGNUM.  */
+
+struct value *
+frame_unwind_got_register (struct frame_info *frame, int regnum, int new_regnum)
+{
+  return value_of_register_lazy (frame, new_regnum);
+}
+
+/* Return a value which indicates that FRAME saved REGNUM in memory at
+   ADDR.  */
+
+struct value *
+frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+
+  return value_at_lazy (register_type (gdbarch, regnum), addr);
+}
+
+/* Return a value which indicates that FRAME's saved version of
+   REGNUM has a known constant (computed) value of VAL.  */
+
+struct value *
+frame_unwind_got_constant (struct frame_info *frame, int regnum,
+			   ULONGEST val)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  store_unsigned_integer (value_contents_writeable (reg_val),
+			  register_size (gdbarch, regnum), val);
+  return reg_val;
+}
+
+/* Return a value which indicates that FRAME's saved version of REGNUM
+   has a known constant (computed) value of ADDR.  Convert the
+   CORE_ADDR to a target address if necessary.  */
+
+struct value *
+frame_unwind_got_address (struct frame_info *frame, int regnum,
+			  CORE_ADDR addr)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+  pack_long (value_contents_writeable (reg_val),
+	     register_type (gdbarch, regnum), addr);
+  return reg_val;
+}
+
 extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */
 
 void
Index: src/gdb/dummy-frame.c
===================================================================
--- src.orig/gdb/dummy-frame.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/dummy-frame.c	2008-04-17 11:47:56.000000000 -0400
@@ -39,7 +39,7 @@ struct dummy_frame
 {
   struct dummy_frame *next;
   /* This frame's ID.  Must match the value returned by
-     gdbarch_unwind_dummy_id.  */
+     gdbarch_dummy_id.  */
   struct frame_id id;
   /* The caller's regcache.  */
   struct regcache *regcache;
@@ -124,7 +124,7 @@ struct dummy_frame_cache
 
 int
 dummy_frame_sniffer (const struct frame_unwind *self,
-		     struct frame_info *next_frame,
+		     struct frame_info *this_frame,
 		     void **this_prologue_cache)
 {
   struct dummy_frame *dummyframe;
@@ -141,12 +141,9 @@ dummy_frame_sniffer (const struct frame_
   /* Don't bother unles there is at least one dummy frame.  */
   if (dummy_frame_stack != NULL)
     {
-      /* Use an architecture specific method to extract the prev's
-	 dummy ID from the next frame.  Note that this method uses
-	 frame_register_unwind to obtain the register values needed to
-	 determine the dummy frame's ID.  */
-      this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame), 
-					 next_frame);
+      /* Use an architecture specific method to extract this frame's
+	 dummy ID, assuming it is a dummy frame.  */
+      this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);
 
       /* Use that ID to find the corresponding cache entry.  */
       for (dummyframe = dummy_frame_stack;
@@ -170,43 +167,37 @@ dummy_frame_sniffer (const struct frame_
 /* Given a call-dummy dummy-frame, return the registers.  Here the
    register value is taken from the local copy of the register buffer.  */
 
-static void
-dummy_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+dummy_frame_prev_register (struct frame_info *this_frame,
 			   void **this_prologue_cache,
-			   int regnum, int *optimized,
-			   enum lval_type *lvalp, CORE_ADDR *addrp,
-			   int *realnum, gdb_byte *bufferp)
+			   int regnum)
 {
-  /* The dummy-frame sniffer always fills in the cache.  */
   struct dummy_frame_cache *cache = (*this_prologue_cache);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct value *reg_val;
+
+  /* The dummy-frame sniffer always fills in the cache.  */
   gdb_assert (cache != NULL);
 
   /* Describe the register's location.  Generic dummy frames always
      have the register value in an ``expression''.  */
-  *optimized = 0;
-  *lvalp = not_lval;
-  *addrp = 0;
-  *realnum = -1;
+  reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
 
-  /* If needed, find and return the value of the register.  */
-  if (bufferp != NULL)
-    {
-      /* Return the actual value.  */
-      /* Use the regcache_cooked_read() method so that it, on the fly,
-         constructs either a raw or pseudo register from the raw
-         register cache.  */
-      regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
-    }
+  /* Use the regcache_cooked_read() method so that it, on the fly,
+     constructs either a raw or pseudo register from the raw
+     register cache.  */
+  regcache_cooked_read (cache->prev_regcache, regnum,
+			value_contents_writeable (reg_val));
+  return reg_val;
 }
 
-/* Assuming that THIS frame is a dummy (remember, the NEXT and not
-   THIS frame is passed in), return the ID of THIS frame.  That ID is
+/* Assuming that THIS frame is a dummy, return the ID of THIS frame.  That ID is
    determined by examining the NEXT frame's unwound registers using
-   the method unwind_dummy_id().  As a side effect, THIS dummy frame's
+   the method dummy_id().  As a side effect, THIS dummy frame's
    dummy cache is located and and saved in THIS_PROLOGUE_CACHE.  */
 
 static void
-dummy_frame_this_id (struct frame_info *next_frame,
+dummy_frame_this_id (struct frame_info *this_frame,
 		     void **this_prologue_cache,
 		     struct frame_id *this_id)
 {
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/gdbarch.c	2008-04-17 11:16:19.000000000 -0400
@@ -162,7 +162,7 @@ struct gdbarch
   gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
   gdbarch_register_name_ftype *register_name;
   gdbarch_register_type_ftype *register_type;
-  gdbarch_unwind_dummy_id_ftype *unwind_dummy_id;
+  gdbarch_dummy_id_ftype *dummy_id;
   int deprecated_fp_regnum;
   gdbarch_push_dummy_call_ftype *push_dummy_call;
   int call_dummy_location;
@@ -284,7 +284,7 @@ struct gdbarch startup_gdbarch =
   no_op_reg_to_regnum,  /* dwarf2_reg_to_regnum */
   0,  /* register_name */
   0,  /* register_type */
-  0,  /* unwind_dummy_id */
+  0,  /* dummy_id */
   -1,  /* deprecated_fp_regnum */
   0,  /* push_dummy_call */
   0,  /* call_dummy_location */
@@ -522,7 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   if (gdbarch->register_name == 0)
     fprintf_unfiltered (log, "\n\tregister_name");
   /* Skip verify of register_type, has predicate */
-  /* Skip verify of unwind_dummy_id, has predicate */
+  /* Skip verify of dummy_id, has predicate */
   /* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
   /* Skip verify of push_dummy_call, has predicate */
   /* Skip verify of call_dummy_location, invalid_p == 0 */
@@ -715,6 +715,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: double_format = %s\n",
                       pformat (gdbarch->double_format));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
+                      gdbarch_dummy_id_p (gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: dummy_id = <0x%lx>\n",
+                      (long) gdbarch->dummy_id);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
                       (long) gdbarch->dwarf2_reg_to_regnum);
   fprintf_unfiltered (file,
@@ -979,12 +985,6 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: target_desc = %s\n",
                       paddr_d ((long) gdbarch->target_desc));
   fprintf_unfiltered (file,
-                      "gdbarch_dump: gdbarch_unwind_dummy_id_p() = %d\n",
-                      gdbarch_unwind_dummy_id_p (gdbarch));
-  fprintf_unfiltered (file,
-                      "gdbarch_dump: unwind_dummy_id = <0x%lx>\n",
-                      (long) gdbarch->unwind_dummy_id);
-  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
                       gdbarch_unwind_pc_p (gdbarch));
   fprintf_unfiltered (file,
@@ -1646,27 +1646,27 @@ set_gdbarch_register_type (struct gdbarc
 }
 
 int
-gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch)
+gdbarch_dummy_id_p (struct gdbarch *gdbarch)
 {
   gdb_assert (gdbarch != NULL);
-  return gdbarch->unwind_dummy_id != NULL;
+  return gdbarch->dummy_id != NULL;
 }
 
 struct frame_id
-gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info)
+gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
   gdb_assert (gdbarch != NULL);
-  gdb_assert (gdbarch->unwind_dummy_id != NULL);
+  gdb_assert (gdbarch->dummy_id != NULL);
   if (gdbarch_debug >= 2)
-    fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n");
-  return gdbarch->unwind_dummy_id (gdbarch, info);
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_dummy_id called\n");
+  return gdbarch->dummy_id (gdbarch, this_frame);
 }
 
 void
-set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch,
-                             gdbarch_unwind_dummy_id_ftype unwind_dummy_id)
+set_gdbarch_dummy_id (struct gdbarch *gdbarch,
+                      gdbarch_dummy_id_ftype dummy_id)
 {
-  gdbarch->unwind_dummy_id = unwind_dummy_id;
+  gdbarch->dummy_id = dummy_id;
 }
 
 int
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/gdbarch.h	2008-04-17 11:16:19.000000000 -0400
@@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (s
 
 /* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
 
-extern int gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch);
+extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
 
-typedef struct frame_id (gdbarch_unwind_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *info);
-extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info);
-extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id);
+typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
+extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame);
+extern void set_gdbarch_dummy_id (struct gdbarch *gdbarch, gdbarch_dummy_id_ftype *dummy_id);
 
-/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+/* Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
    deprecated_fp_regnum. */
 
 extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch);
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/gdbarch.sh	2008-04-17 11:16:19.000000000 -0400
@@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:r
 M:struct type *:register_type:int reg_nr:reg_nr
 
 # See gdbint.texinfo, and PUSH_DUMMY_CALL.
-M:struct frame_id:unwind_dummy_id:struct frame_info *info:info
-# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
+M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
+# Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
 # deprecated_fp_regnum.
 v:int:deprecated_fp_regnum:::-1:-1::0
 
Index: src/gdb/frame-base.c
===================================================================
--- src.orig/gdb/frame-base.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/frame-base.c	2008-04-17 11:16:19.000000000 -0400
@@ -28,22 +28,21 @@
    really need to override this.  */
 
 static CORE_ADDR
-default_frame_base_address (struct frame_info *next_frame, void **this_cache)
+default_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
-  struct frame_info *this_frame = get_prev_frame (next_frame);
   return get_frame_base (this_frame); /* sigh! */
 }
 
 static CORE_ADDR
-default_frame_locals_address (struct frame_info *next_frame, void **this_cache)
+default_frame_locals_address (struct frame_info *this_frame, void **this_cache)
 {
-  return default_frame_base_address (next_frame, this_cache);
+  return default_frame_base_address (this_frame, this_cache);
 }
 
 static CORE_ADDR
-default_frame_args_address (struct frame_info *next_frame, void **this_cache)
+default_frame_args_address (struct frame_info *this_frame, void **this_cache)
 {
-  return default_frame_base_address (next_frame, this_cache);
+  return default_frame_base_address (this_frame, this_cache);
 }
 
 const struct frame_base default_frame_base = {
@@ -97,16 +96,16 @@ frame_base_set_default (struct gdbarch *
 }
 
 const struct frame_base *
-frame_base_find_by_frame (struct frame_info *next_frame)
+frame_base_find_by_frame (struct frame_info *this_frame)
 {
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data);
   struct frame_base_table_entry *entry;
 
   for (entry = table->head; entry != NULL; entry = entry->next)
     {
       const struct frame_base *desc = NULL;
-      desc = entry->sniffer (next_frame);
+      desc = entry->sniffer (this_frame);
       if (desc != NULL)
 	return desc;
     }
Index: src/gdb/doc/gdbint.texinfo
===================================================================
--- src.orig/gdb/doc/gdbint.texinfo	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/doc/gdbint.texinfo	2008-04-17 11:50:21.000000000 -0400
@@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN
 * Algorithms::
 * User Interface::
 * libgdb::
+* Stack Frames::
 * Symbol Handling::
 * Language Support::
 * Host Definition::
@@ -273,39 +274,6 @@ cases and real-world issues.  This chapt
 algorithms and mentions some of the specific target definitions that
 they use.
 
-@section Frames
-
-@cindex frame
-@cindex call stack frame
-A frame is a construct that @value{GDBN} uses to keep track of calling
-and called functions.
-
-@cindex frame, unwind
-@value{GDBN}'s frame model, a fresh design, was implemented with the
-need to support @sc{dwarf}'s Call Frame Information in mind.  In fact,
-the term ``unwind'' is taken directly from that specification.
-Developers wishing to learn more about unwinders, are encouraged to
-read the @sc{dwarf} specification.
-
-@findex frame_register_unwind
-@findex get_frame_register
-@value{GDBN}'s model is that you find a frame's registers by
-``unwinding'' them from the next younger frame.  That is,
-@samp{get_frame_register} which returns the value of a register in
-frame #1 (the next-to-youngest frame), is implemented by calling frame
-#0's @code{frame_register_unwind} (the youngest frame).  But then the
-obvious question is: how do you access the registers of the youngest
-frame itself?
-
-@cindex sentinel frame
-@findex get_frame_type
-@vindex SENTINEL_FRAME
-To answer this question, GDB has the @dfn{sentinel} frame, the
-``-1st'' frame.  Unwinding registers from the sentinel frame gives you
-the current values of the youngest real frame's registers.  If @var{f}
-is a sentinel frame, then @code{get_frame_type (@var{f}) ==
-SENTINEL_FRAME}.
-
 @section Prologue Analysis
 
 @cindex prologue analysis
@@ -1853,6 +1821,127 @@ the query interface.  Each function is p
 builder.  The result of the query is constructed using that builder
 before the query function returns.
 
+@node Stack Frames
+@chapter Stack Frames
+
+@cindex frame
+@cindex call stack frame
+A frame is a construct that @value{GDBN} uses to keep track of calling
+and called functions.
+
+@cindex unwind frame
+@value{GDBN}'s frame model, a fresh design, was implemented with the
+need to support @sc{dwarf}'s Call Frame Information in mind.  In fact,
+the term ``unwind'' is taken directly from that specification.
+Developers wishing to learn more about unwinders, are encouraged to
+read the @sc{dwarf} specification, available from
+@url{http://www.dwarfstd.org}.
+
+@findex frame_register_unwind
+@findex get_frame_register
+@value{GDBN}'s model is that you find a frame's registers by
+``unwinding'' them from the next younger frame.  That is,
+@samp{get_frame_register} which returns the value of a register in
+frame #1 (the next-to-youngest frame), is implemented by calling frame
+#0's @code{frame_register_unwind} (the youngest frame).  But then the
+obvious question is: how do you access the registers of the youngest
+frame itself?
+
+@cindex sentinel frame
+@findex get_frame_type
+@vindex SENTINEL_FRAME
+To answer this question, GDB has the @dfn{sentinel} frame, the
+``-1st'' frame.  Unwinding registers from the sentinel frame gives you
+the current values of the youngest real frame's registers.  If @var{f}
+is a sentinel frame, then @code{get_frame_type (@var{f}) @equiv{}
+SENTINEL_FRAME}.
+
+@section Selecting an Unwinder
+
+@findex frame_unwind_prepend_unwinder
+@findex frame_unwind_append_unwinder
+The architecture registers a list of frame unwinders (@code{struct
+frame_unwind}), using the functions
+@code{frame_unwind_prepend_unwinder} and
+@code{frame_unwind_append_unwinder}.  Each unwinder includes a
+sniffer.  Whenever @value{GDBN} needs to unwind a frame (to fetch the
+previous frame's registers or the current frame's ID), it calls
+registered sniffers in order to find one which recognizes the frame.
+The first time a sniffer returns non-zero, the corresponding unwinder
+is assigned to the frame.
+
+@section Unwinding the Frame ID
+@cindex frame ID
+
+Every frame has an associated ID, of type @code{struct frame_id}.
+The ID includes the stack base and function start address for
+the frame.  The ID persists through the entire life of the frame,
+including while other called frames are running; it is used to
+locate an appropriate @code{struct frame_info} from the cache.
+
+Every time the inferior stops, and at various other times, the frame
+cache is flushed.  Because of this, parts of @value{GDBN} which need
+to keep track of individual frames cannot use pointers to @code{struct
+frame_info}.  A frame ID provides a stable reference to a frame, even
+when the unwinder must be run again to generate a new @code{struct
+frame_info} for the same frame.
+
+The frame's unwinder's @code{this_id} method is called to find the ID.
+Note that this is different from register unwinding, where the next
+frame's @code{prev_register} is called to unwind this frame's
+registers.
+
+Both stack base and function address are required to identify the
+frame, because a recursive function has the same function address for
+two consecutive frames and a leaf function may have the same stack
+address as its caller.  On some platforms, a third address is part of
+the ID to further disambiguate frames---for instance, on IA-64
+the separate register stack address is included in the ID.
+
+An invalid frame ID (@code{null_frame_id}) returned from the
+@code{this_id} method means to stop unwinding after this frame.
+
+@section Unwinding Registers
+
+Each unwinder includes a @code{prev_register} method.  This method
+takes a frame, an associated cache pointer, and a register number.
+It returns a @code{struct value *} describing the requested register,
+as saved by this frame.  This is the value of the register that is
+current in this frame's caller.
+
+The returned value must have the same type as the register.  It may
+have any lvalue type.  In most circumstances one of these routines
+will generate the appropriate value:
+
+@table @code
+@item frame_unwind_got_optimized
+@findex frame_unwind_got_optimized
+This register was not saved.
+
+@item frame_unwind_got_register
+@findex frame_unwind_got_register
+This register was copied into another register in this frame.  This
+is also used for unchanged registers; they are ``copied'' into the
+same register.
+
+@item frame_unwind_got_memory
+@findex frame_unwind_got_memory
+This register was saved in memory.
+
+@item frame_unwind_got_constant
+@findex frame_unwind_got_constant
+This register was not saved, but the unwinder can compute the previous
+value some other way.
+
+@item frame_unwind_got_address
+@findex frame_unwind_got_address
+Same as @code{frame_unwind_got_constant}, except that the value is a target
+address.  This is frequently used for the stack pointer, which is not
+explicitly saved but has a known offset from this frame's stack
+pointer.  For architectures with a flat unified address space, this is
+generally the same as @code{frame_unwind_got_constant}.
+@end table
+
 @node Symbol Handling
 
 @chapter Symbol Handling
@@ -3920,14 +4009,6 @@ This method replaces @w{@code{gdbarch_ca
 Return the name of register @var{regnr} as a string.  May return @code{NULL}
 to indicate that @var{regnr} is not a valid register.
 
-@item SAVE_DUMMY_FRAME_TOS (@var{sp})
-@findex SAVE_DUMMY_FRAME_TOS
-@anchor{SAVE_DUMMY_FRAME_TOS} Used in @samp{call_function_by_hand} to
-notify the target dependent code of the top-of-stack value that will be
-passed to the inferior code.  This is the value of the @code{SP}
-after both the dummy frame and space for parameters/results have been
-allocated on the stack.  @xref{gdbarch_unwind_dummy_id}.
-
 @item int gdbarch_sdb_reg_to_regnum (@var{gdbarch}, @var{sdb_regnr})
 @findex gdbarch_sdb_reg_to_regnum
 Use this function to convert sdb register @var{sdb_regnr} into @value{GDBN}
@@ -4109,13 +4190,12 @@ the @code{opcodes} library (@pxref{Suppo
 @file{include/dis-asm.h} used to pass information to the instruction
 decoding routine.
 
-@item frame_id gdbarch_unwind_dummy_id (@var{gdbarch}, @var{frame})
-@findex gdbarch_unwind_dummy_id
-@anchor{gdbarch_unwind_dummy_id} Given @var{frame} return a @w{@code{struct
+@item frame_id gdbarch_dummy_id (@var{gdbarch}, @var{frame})
+@findex gdbarch_dummy_id
+@anchor{gdbarch_dummy_id} Given @var{frame} return a @w{@code{struct
 frame_id}} that uniquely identifies an inferior function call's dummy
 frame.  The value returned must match the dummy frame stack value
-previously saved using @code{SAVE_DUMMY_FRAME_TOS}.
-@xref{SAVE_DUMMY_FRAME_TOS}.
+previously saved by @code{call_function_by_hand}.
 
 @item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
 @findex DEPRECATED_USE_STRUCT_CONVENTION
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c	2008-04-17 11:09:04.000000000 -0400
+++ src/gdb/infcall.c	2008-04-17 11:16:19.000000000 -0400
@@ -462,7 +462,7 @@ call_function_by_hand (struct value *fun
 	 pushed) GDB won't be able to correctly perform back traces.
 	 If a target is having trouble with backtraces, first thing to
 	 do is add FRAME_ALIGN() to the architecture vector. If that
-	 fails, try unwind_dummy_id().
+	 fails, try dummy_id().
 
          If the ABI specifies a "Red Zone" (see the doco) the code
          below will quietly trash it.  */
@@ -656,7 +656,7 @@ call_function_by_hand (struct value *fun
      ID so that the breakpoint code can correctly re-identify the
      dummy breakpoint.  */
   /* Sanity.  The exact same SP value is returned by PUSH_DUMMY_CALL,
-     saved as the dummy-frame TOS, and used by unwind_dummy_id to form
+     saved as the dummy-frame TOS, and used by dummy_id to form
      the frame ID's stack address.  */
   dummy_id = frame_id_build (sp, bp_addr);
 
@@ -671,7 +671,7 @@ call_function_by_hand (struct value *fun
     sal.section = find_pc_overlay (sal.pc);
     /* Sanity.  The exact same SP value is returned by
        PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
-       unwind_dummy_id to form the frame ID's stack address.  */
+       dummy_id to form the frame ID's stack address.  */
     bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy);
     bpt->disposition = disp_del;
   }
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2008-04-17 11:09:19.000000000 -0400
+++ src/gdb/Makefile.in	2008-04-17 11:16:19.000000000 -0400
@@ -2142,7 +2142,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(
 	$(annotate_h) $(language_h) $(frame_unwind_h) $(frame_base_h) \
 	$(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h)
 frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
-	$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h)
+	$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h) $(value_h) \
+	$(regcache_h)
 frv-linux-tdep.o: frv-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \
 	$(frame_h) $(osabi_h) $(regcache_h) $(elf_bfd_h) $(elf_frv_h) \
 	$(frv_tdep_h) $(trad_frame_h) $(frame_unwind_h) $(regset_h) \


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

* Re: [RFC 2/5] Frame unwinding using struct value
       [not found]   ` <20080430230012.GB3801@adacore.com>
@ 2008-05-01  3:37     ` Daniel Jacobowitz
  0 siblings, 0 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-05-01  3:37 UTC (permalink / raw)
  To: gdb-patches

On Wed, Apr 30, 2008 at 04:00:12PM -0700, Joel Brobecker wrote:
> I've added myself for a couple of targets, and I see that Ulrich has
> also added himself before I did :-). I can do a couple more after I'm
> done with the ones I signed up for.

Thank you both.  The remaining targets should be relatively easy
to update in one shot - IA64 was one of the ones I was particularly
hoping you would take :-)

-- 
Daniel Jacobowitz
CodeSourcery


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

end of thread, other threads:[~2008-05-01  3:37 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
2008-04-01 13:23 ` Eli Zaretskii
2008-04-17 15:30   ` Daniel Jacobowitz
2008-04-04 19:10 ` Joel Brobecker
2008-04-17 15:59   ` Daniel Jacobowitz
2008-04-04 19:16 ` Joel Brobecker
2008-04-07 19:34 ` Thiago Jung Bauermann
2008-04-17 16:02   ` Daniel Jacobowitz
2008-04-30 23:31 ` Daniel Jacobowitz
     [not found]   ` <20080430230012.GB3801@adacore.com>
2008-05-01  3:37     ` Daniel Jacobowitz

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