This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC 2/5] Frame unwinding using struct value


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) \


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