This is the mail archive of the gdb@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]

[RFC] Using values to handle unwinding


This is the patch I referenced yesterday on gdb-patches; the
background is here:
  http://sourceware.org/ml/gdb-patches/2007-10/msg00432.html

I've replaced prev_register with a new method, with this signature:

typedef struct value * (frame_prev_register_value_ftype)
  (struct frame_info *this_frame, void **this_prologue_cache,
   int prev_regnum);

It returns 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 (constant or address).  The
first part of the patch adds support for lazy registers, which are not
fetched until they are needed.  When any frame other than the sentinel
frame sees that a register in the PREV frame is not saved or constant,
it returns a lazy reference to the register in THIS frame.

There are three key differences / motivations:

  - Uses GDB's value infrastructure.  Values carry around the
    location information which previously took four extra arguments
    to every unwinder.  And this lets us use our existing value
    manipulation routines as necessary.

  - Uses the same frame that non-unwinder architecture methods use.
    For instance, in my ARM CPSR unwinding patch I had a routine
    "arm_frame_is_thumb".  It was used during software single
    stepping, where we wanted the state of the current frame, and
    during unwinding, where we wanted the state of THIS frame
    (i.e. the one being unwound / having its ID established).

  - Simplifies getting other registers from the PREV frame.
    For instance, if one register is computed based on the
    value of another.  Previously you had to inline code
    to do this or call the same prev_register routine again
    with the same NEXT frame and THIS cache; awkward if more
    than one function was involved (see previous reason).

The patch at the bottom of my message implements this.  It's complete
and tested on x86_64-linux as far as it goes.  It applies to
HEAD plus my gdbarch_convert_register_p patch from this morning.

This patch leaves the existing prev_register method.  If we want to
adopt this new approach then I would recommend not doing that at all:
just change the type of the prev_register field, break all targets
until they are updated, and fix them.  We can do it on a branch and
merge the whole branch at once, or do it quickly in HEAD.  Converting
the DWARF-2 reader took me only an hour or two, which included writing
the helper routines.

I'm happy with the more concise code in the dwarf2 unwinder now; I
think this will overall shrink and simplify GDB.  And having THIS
frame removed the need for a separate this_id function in the dwarf2
signal frame unwinder.

All comments appreciated!  Really.  I have spent a lot of time
thinking about this, both now and in previous years, and I still think
it's a good idea.  But if it isn't I don't want to convert the other
67 unwinders and find out later.

-- 
Daniel Jacobowitz
CodeSourcery

Index: src/gdb/ada-lang.c
===================================================================
--- src.orig/gdb/ada-lang.c	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/ada-lang.c	2007-10-17 10:03:32.000000000 -0400
@@ -1930,7 +1930,7 @@ ada_value_primitive_packed_val (struct v
       v = allocate_value (type);
       bytes = (unsigned char *) (valaddr + offset);
     }
-  else if (value_lazy (obj))
+  else if (VALUE_LVAL (v) == lval_memory && value_lazy (obj))
     {
       v = value_at (type,
                     VALUE_ADDRESS (obj) + value_offset (obj) + offset);
Index: src/gdb/findvar.c
===================================================================
--- src.orig/gdb/findvar.c	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/findvar.c	2007-10-17 11:18:48.000000000 -0400
@@ -281,6 +281,30 @@ value_of_register (int regnum, struct fr
   return reg_val;
 }
 
+/* Return a `value' with the contents of (virtual or cooked) register
+   REGNUM as found in the specified FRAME.  The register's type is
+   determined by register_type().  The value is not fetched.  */
+
+struct value *
+value_of_register_lazy (struct frame_info *frame, int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value *reg_val;
+
+  gdb_assert (regnum < (gdbarch_num_regs (gdbarch)
+			+ gdbarch_num_pseudo_regs (gdbarch)));
+
+  /* We should have a valid (i.e. non-sentinel) frame.  */
+  gdb_assert (frame_id_p (get_frame_id (frame)));
+
+  reg_val = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (reg_val) = lval_register;
+  VALUE_REGNUM (reg_val) = regnum;
+  VALUE_FRAME_ID (reg_val) = get_frame_id (frame);
+  set_value_lazy (reg_val, 1);
+  return reg_val;
+}
+
 /* Given a pointer of type TYPE in target form in BUF, return the
    address it represents.  */
 CORE_ADDR
@@ -695,7 +719,7 @@ locate_var_value (struct symbol *var, st
   if (lazy_value == 0)
     error (_("Address of \"%s\" is unknown."), SYMBOL_PRINT_NAME (var));
 
-  if (value_lazy (lazy_value)
+  if ((VALUE_LVAL (lazy_value) == lval_memory && value_lazy (lazy_value))
       || TYPE_CODE (type) == TYPE_CODE_FUNC)
     {
       struct value *val;
Index: src/gdb/valarith.c
===================================================================
--- src.orig/gdb/valarith.c	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/valarith.c	2007-10-17 10:03:32.000000000 -0400
@@ -266,7 +266,7 @@ value_subscripted_rvalue (struct value *
     error (_("no such vector element"));
 
   v = allocate_value (elt_type);
-  if (value_lazy (array))
+  if (VALUE_LVAL (array) == lval_memory && value_lazy (array))
     set_value_lazy (v, 1);
   else
     memcpy (value_contents_writeable (v),
Index: src/gdb/valops.c
===================================================================
--- src.orig/gdb/valops.c	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/valops.c	2007-10-17 10:49:23.000000000 -0400
@@ -519,12 +519,102 @@ value_at_lazy (struct type *type, CORE_A
 int
 value_fetch_lazy (struct value *val)
 {
-  CORE_ADDR addr = VALUE_ADDRESS (val) + value_offset (val);
-  int length = TYPE_LENGTH (value_enclosing_type (val));
+  if (VALUE_LVAL (val) == lval_memory)
+    {
+      CORE_ADDR addr = VALUE_ADDRESS (val) + value_offset (val);
+      int length = TYPE_LENGTH (value_enclosing_type (val));
+
+      struct type *type = value_type (val);
+      if (length)
+	read_memory (addr, value_contents_all_raw (val), length);
+    }
+  else if (VALUE_LVAL (val) == lval_register)
+    {
+      struct frame_info *frame;
+      int regnum;
+      struct type *type = check_typedef (value_type (val));
+      struct value *new_val = val, *mark = value_mark ();
+
+      /* Offsets are not supported here; lazy register values must
+	 refer to the entire register.  */
+      gdb_assert (value_offset (val) == 0);
+
+      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));
 
-  struct type *type = value_type (val);
-  if (length)
-    read_memory (addr, value_contents_all_raw (val), length);
+      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.");
 
   set_value_lazy (val, 0);
   return 0;
@@ -1319,7 +1409,7 @@ search_struct_field (char *name, struct 
 	      VALUE_ADDRESS (v2) = VALUE_ADDRESS (arg1);
 	      VALUE_FRAME_ID (v2) = VALUE_FRAME_ID (arg1);
 	      set_value_offset (v2, value_offset (arg1) + boffset);
-	      if (value_lazy (arg1))
+	      if (VALUE_LVAL (arg1) == lval_memory && value_lazy (arg1))
 		set_value_lazy (v2, 1);
 	      else
 		memcpy (value_contents_raw (v2),
@@ -2875,7 +2965,7 @@ value_slice (struct value *array, int lo
       TYPE_CODE (slice_type) = TYPE_CODE (array_type);
 
       slice = allocate_value (slice_type);
-      if (value_lazy (array))
+      if (VALUE_LVAL (array) == lval_memory && value_lazy (array))
 	set_value_lazy (slice, 1);
       else
 	memcpy (value_contents_writeable (slice),
Index: src/gdb/value.c
===================================================================
--- src.orig/gdb/value.c	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/value.c	2007-10-17 10:03:32.000000000 -0400
@@ -136,9 +136,9 @@ struct value
   short regnum;
 
   /* If zero, contents of this value are in the contents field.  If
-     nonzero, contents are in inferior memory at address in the
-     location.address field plus the offset field (and the lval field
-     should be lval_memory).
+     nonzero, contents are in inferior.  If the lval field is lval_memory,
+     the contents are in inferior memory at location.address plus offset.
+     The lval field may also be lval_register.
 
      WARNING: This field is used by the code which handles watchpoints
      (see breakpoint.c) to decide whether a particular value can be
@@ -1344,7 +1344,7 @@ value_primitive_field (struct value *arg
          bases, etc.  */
       v = allocate_value (value_enclosing_type (arg1));
       v->type = type;
-      if (value_lazy (arg1))
+      if (VALUE_LVAL (arg1) == lval_memory && value_lazy (arg1))
 	set_value_lazy (v, 1);
       else
 	memcpy (value_contents_all_raw (v), value_contents_all_raw (arg1),
@@ -1358,7 +1358,7 @@ value_primitive_field (struct value *arg
       /* Plain old data member */
       offset += TYPE_FIELD_BITPOS (arg_type, fieldno) / 8;
       v = allocate_value (type);
-      if (value_lazy (arg1))
+      if (VALUE_LVAL (arg1) == lval_memory && value_lazy (arg1))
 	set_value_lazy (v, 1);
       else
 	memcpy (value_contents_raw (v),
Index: src/gdb/value.h
===================================================================
--- src.orig/gdb/value.h	2007-10-17 09:24:11.000000000 -0400
+++ src/gdb/value.h	2007-10-17 11:18:48.000000000 -0400
@@ -135,9 +135,9 @@ extern int value_embedded_offset (struct
 extern void set_value_embedded_offset (struct value *value, int val);
 
 /* If zero, contents of this value are in the contents field.  If
-   nonzero, contents are in inferior memory at address in the
-   location.address field plus the offset field (and the lval field
-   should be lval_memory).
+   nonzero, contents are in inferior.  If the lval field is lval_memory,
+   the contents are in inferior memory at location.address plus offset.
+   The lval field may also be lval_register.
 
    WARNING: This field is used by the code which handles watchpoints
    (see breakpoint.c) to decide whether a particular value can be
@@ -299,6 +299,8 @@ extern struct value *value_of_variable (
 
 extern struct value *value_of_register (int regnum, struct frame_info *frame);
 
+struct value *value_of_register_lazy (struct frame_info *frame, int regnum);
+
 extern int symbol_read_needs_frame (struct symbol *);
 
 extern struct value *read_var_value (struct symbol *var,
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c	2007-10-17 10:11:26.000000000 -0400
+++ src/gdb/frame.c	2007-10-17 10:53:39.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)
@@ -258,7 +258,10 @@ get_frame_id (struct frame_info *fi)
 	fi->unwind = frame_unwind_find_by_frame (fi->next,
 						 &fi->prologue_cache);
       /* Find THIS frame's ID.  */
-      fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
+      if (fi->unwind->prev_register_value != NULL)
+	fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
+      else
+	fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
       fi->this_id.p = 1;
       if (frame_debug)
 	{
@@ -427,15 +430,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
@@ -552,15 +547,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 +557,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 +614,111 @@ 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->next,
+						&frame->prologue_cache);
+
+  /* Ask this frame to unwind its register.  */
+  if (frame->unwind->prev_register_value != NULL)
+    value = frame->unwind->prev_register_value (frame, &frame->prologue_cache,
+						regnum);
+  else
+    {
+      gdb_byte buffer[MAX_REGISTER_SIZE];
+      int optimized;
+      CORE_ADDR addr;
+      int realnum;
+      enum lval_type lval;
+
+      gdb_assert (frame->unwind->prev_register != NULL);
+
+      /* We can not create a lazy value, because if the result is not_lval
+	 we have no way to fetch the bytes later.  */
+      frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
+				    &optimized, &lval, &addr, &realnum, buffer);
+
+      if (optimized)
+	{
+	  value = value_zero (register_type (get_frame_arch (frame), regnum),
+			      not_lval);
+	  set_value_optimized_out (value, 1);
+	}
+      else if (lval == lval_memory)
+	value = value_at_lazy (register_type (get_frame_arch (frame), regnum),
+			       addr);
+      else if (lval == lval_register)
+	value = value_of_register_lazy (frame, realnum);
+      else
+	{
+	  gdb_assert (lval == not_lval);
+
+	  value = value_zero (register_type (get_frame_arch (frame), regnum),
+			      not_lval);
+	  VALUE_LVAL (value) = not_lval;
+	  memcpy (value_contents_writeable (value), buffer,
+		  TYPE_LENGTH (value_type (value)));
+	}
+    }
+
+  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)
 {
@@ -1566,7 +1638,12 @@ 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);
+    {
+      if (fi->unwind->prev_register_value != NULL)
+	return fi->base->this_base (fi, &fi->prologue_cache);
+      else
+	return fi->base->this_base (fi->next, &fi->prologue_cache);
+    }
   return fi->base->this_base (fi->next, &fi->base_cache);
 }
 
@@ -1582,10 +1659,13 @@ 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);
+    {
+      if (fi->unwind->prev_register_value != NULL)
+	return fi->base->this_locals (fi, &fi->prologue_cache);
+      else
+	return fi->base->this_locals (fi->next, &fi->prologue_cache);
+    }
+  return fi->base->this_locals (fi->next, &fi->base_cache);
 }
 
 CORE_ADDR
@@ -1600,10 +1680,13 @@ 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);
+    {
+      if (fi->unwind->prev_register_value != NULL)
+	return fi->base->this_args (fi, &fi->prologue_cache);
+      else
+	return fi->base->this_args (fi->next, &fi->prologue_cache);
+    }
+  return fi->base->this_args (fi->next, &fi->base_cache);
 }
 
 /* Level of the selected frame: 0 for innermost, 1 for its caller, ...
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h	2007-10-17 10:11:26.000000000 -0400
+++ src/gdb/frame.h	2007-10-17 10:43:15.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).
@@ -459,13 +463,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,
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h	2007-10-17 10:11:26.000000000 -0400
+++ src/gdb/frame-unwind.h	2007-10-17 11:19:45.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.  */
 
@@ -53,6 +54,10 @@ typedef int (frame_sniffer_ftype) (const
    use the NEXT frame, and its register unwind method, to determine
    the frame ID of THIS frame.
 
+   NOTE!  If this unwinder has a prev_register_value method, then
+   the frame argument will be THIS frame instead of NEXT frame!
+   FIXME: This is transitional.
+
    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
    the frame's function's code address.
@@ -76,7 +81,10 @@ typedef void (frame_this_id_ftype) (stru
 				    void **this_prologue_cache,
 				    struct frame_id *this_id);
 
-/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+/* The use of prev_register_value is recommended instead of
+   prev_register.
+
+   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).
@@ -117,11 +125,37 @@ typedef void (frame_prev_register_ftype)
 					  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.  */
+   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
+   that prolog code saved on the stack.
 
-typedef CORE_ADDR (frame_prev_pc_ftype) (struct frame_info *next_frame,
-					 void **this_prologue_cache);
+   Example: An examination of THIS frame's prologue reveals that, on
+   entry, it saves the PC(+12), SP(+8), and R1(+4) registers
+   (decrementing the SP by 12).  Consequently, the value of the PC
+   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.
+
+   This version takes THIS_FRAME, unlike the older prev_register
+   interface (above).  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 struct value * (frame_prev_register_value_ftype)
+  (struct frame_info *this_frame, void **this_prologue_cache,
+   int prev_regnum);
 
 /* Deallocate extra memory associated with the frame cache if any.  */
 
@@ -139,8 +173,8 @@ 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;
+  frame_prev_register_value_ftype *prev_register_value;
 };
 
 /* Register a frame unwinder, _prepending_ it to the front of the
@@ -171,4 +205,32 @@ extern void frame_unwind_append_sniffer 
 extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_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 REGNUM from FRAME is not
+   available.  */
+
+struct value *frame_unwind_got_optimized (struct frame_info *frame,
+					  int regnum);
+
+/* Return a value which indicates that REGNUM from FRAME is saved
+   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 REGNUM from FRAME 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 REGNUM from FRAME 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	2007-10-17 10:11:26.000000000 -0400
+++ src/gdb/frame-base.h	2007-10-17 10:11:33.000000000 -0400
@@ -27,6 +27,13 @@ struct frame_base;
 struct gdbarch;
 struct regcache;
 
+/* NOTE!  If this frame base shares a cache with the prologue
+   unwinder, and that prologue unwinder has a prev_register_value
+   method, then the frame argument to all of these methods will be
+   THIS frame instead of NEXT frame!
+
+   FIXME: This is transitional.  */
+
 /* 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
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c	2007-10-17 10:11:26.000000000 -0400
+++ src/gdb/sentinel-frame.c	2007-10-17 11:19:31.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,
-			      void **this_prologue_cache,
-			      int regnum, int *optimized,
-			      enum lval_type *lvalp, CORE_ADDR *addrp,
-			      int *realnum, gdb_byte *bufferp)
+static struct value *
+sentinel_frame_prev_register_value (struct frame_info *this_frame,
+				    void **this_prologue_cache,
+				    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 = register_offset_hack (current_gdbarch, regnum);
-  *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,15 @@ 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, /* prev_register */
   NULL, /* unwind_data */
   NULL, /* sniffer */
-  sentinel_frame_prev_pc,
+  NULL, /* dealloc_cache */
+  sentinel_frame_prev_register_value
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
Index: src/gdb/ia64-tdep.c
===================================================================
--- src.orig/gdb/ia64-tdep.c	2007-10-17 10:55:11.000000000 -0400
+++ src/gdb/ia64-tdep.c	2007-10-17 10:55:13.000000000 -0400
@@ -2794,7 +2794,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	2007-10-17 10:54:57.000000000 -0400
+++ src/gdb/libunwind-frame.c	2007-10-17 10:55:03.000000000 -0400
@@ -213,7 +213,6 @@ static const struct frame_unwind libunwi
   libunwind_frame_prev_register,
   NULL,
   NULL,
-  NULL,
   libunwind_frame_dealloc_cache
 };
 
Index: src/gdb/dwarf2-frame.c
===================================================================
--- src.orig/gdb/dwarf2-frame.c	2007-10-17 11:18:48.000000000 -0400
+++ src/gdb/dwarf2-frame.c	2007-10-17 11:19:45.000000000 -0400
@@ -230,15 +230,15 @@ dwarf2_frame_state_free (void *p)
 static CORE_ADDR
 read_reg (void *baton, int reg)
 {
-  struct frame_info *next_frame = (struct frame_info *) baton;
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct frame_info *this_frame = (struct frame_info *) baton;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   int regnum;
   gdb_byte *buf;
 
   regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
 
   buf = alloca (register_size (gdbarch, regnum));
-  frame_unwind_register (next_frame, regnum, buf);
+  get_frame_register (this_frame, regnum, buf);
 
   /* Convert the register to an integer.  This returns a LONGEST
      rather than a CORE_ADDR, but unpack_pointer does the same thing
@@ -270,13 +270,13 @@ no_get_tls_address (void *baton, CORE_AD
 
 static CORE_ADDR
 execute_stack_op (gdb_byte *exp, ULONGEST len,
-		  struct frame_info *next_frame, CORE_ADDR initial)
+		  struct frame_info *this_frame, CORE_ADDR initial)
 {
   struct dwarf_expr_context *ctx;
   CORE_ADDR result;
 
   ctx = new_dwarf_expr_context ();
-  ctx->baton = next_frame;
+  ctx->baton = this_frame;
   ctx->read_reg = read_reg;
   ctx->read_mem = read_mem;
   ctx->get_frame_base = no_get_frame_base;
@@ -287,7 +287,7 @@ execute_stack_op (gdb_byte *exp, ULONGES
   result = dwarf_expr_fetch (ctx, 0);
 
   if (ctx->in_reg)
-    result = read_reg (next_frame, result);
+    result = read_reg (this_frame, result);
 
   free_dwarf_expr_context (ctx);
 
@@ -297,12 +297,12 @@ execute_stack_op (gdb_byte *exp, ULONGES
 
 static void
 execute_cfa_program (gdb_byte *insn_ptr, gdb_byte *insn_end,
-		     struct frame_info *next_frame,
+		     struct frame_info *this_frame,
 		     struct dwarf2_frame_state *fs, int eh_frame_p)
 {
-  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  CORE_ADDR pc = get_frame_pc (this_frame);
   int bytes_read;
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
 
   while (insn_ptr < insn_end && fs->pc <= pc)
     {
@@ -549,8 +549,7 @@ bad CFI data; mismatched DW_CFA_restore_
 		 Incidentally that's what GCC does too in its
 		 unwinder.  */
 	      {
-		struct gdbarch *gdbarch = get_frame_arch (next_frame);
-		int size = register_size(gdbarch, 0);
+		int size = register_size (gdbarch, 0);
 		dwarf2_frame_state_alloc_regs (&fs->regs, 32);
 		for (reg = 8; reg < 16; reg++)
 		  {
@@ -618,7 +617,7 @@ struct dwarf2_frame_ops
 static void
 dwarf2_frame_default_init_reg (struct gdbarch *gdbarch, int regnum,
 			       struct dwarf2_frame_state_reg *reg,
-			       struct frame_info *next_frame)
+			       struct frame_info *this_frame)
 {
   /* If we have a register that acts as a program counter, mark it as
      a destination for the return address.  If we have a register that
@@ -683,11 +682,15 @@ dwarf2_frame_set_init_reg (struct gdbarc
 static void
 dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
 		       struct dwarf2_frame_state_reg *reg,
-		       struct frame_info *next_frame)
+		       struct frame_info *this_frame)
 {
   struct dwarf2_frame_ops *ops = gdbarch_data (gdbarch, dwarf2_frame_data);
 
-  ops->init_reg (gdbarch, regnum, reg, next_frame);
+  /* FIXME: Most definitions of the init_reg callback still take an
+     argument named next_frame instead of this_frame.  Only one,
+     in sparc-tdep.c, uses its argument; that one has been updated.
+     The others just need the name changed.  */
+  ops->init_reg (gdbarch, regnum, reg, this_frame);
 }
 
 /* Set the architecture-specific signal trampoline recognition
@@ -804,10 +807,10 @@ struct dwarf2_frame_cache
 };
 
 static struct dwarf2_frame_cache *
-dwarf2_frame_cache (struct frame_info *next_frame, void **this_cache)
+dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
 {
   struct cleanup *old_chain;
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   const int num_regs = gdbarch_num_regs (gdbarch)
 		       + gdbarch_num_pseudo_regs (gdbarch);
   struct dwarf2_frame_cache *cache;
@@ -828,9 +831,9 @@ dwarf2_frame_cache (struct frame_info *n
 
   /* Unwind the PC.
 
-     Note that if NEXT_FRAME is never supposed to return (i.e. a call
+     Note that if the next frame is never supposed to return (i.e. a call
      to abort), the compiler might optimize away the instruction at
-     NEXT_FRAME's return address.  As a result the return address will
+     its return address.  As a result the return address will
      point at some random instruction, and the CFI for that
      instruction is probably worthless to us.  GCC's unwinder solves
      this problem by substracting 1 from the return address to get an
@@ -841,7 +844,7 @@ dwarf2_frame_cache (struct frame_info *n
      frame_unwind_address_in_block does just this.  It's not clear how
      reliable the method is though; there is the potential for the
      register state pre-call being different to that on return.  */
-  fs->pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+  fs->pc = get_frame_address_in_block (this_frame);
 
   /* Find the correct FDE.  */
   fde = dwarf2_frame_find_fde (&fs->pc);
@@ -857,21 +860,21 @@ dwarf2_frame_cache (struct frame_info *n
 
   /* First decode all the insns in the CIE.  */
   execute_cfa_program (fde->cie->initial_instructions,
-		       fde->cie->end, next_frame, fs, fde->eh_frame_p);
+		       fde->cie->end, this_frame, fs, fde->eh_frame_p);
 
   /* Save the initialized register set.  */
   fs->initial = fs->regs;
   fs->initial.reg = dwarf2_frame_state_copy_regs (&fs->regs);
 
   /* Then decode the insns in the FDE up to our target PC.  */
-  execute_cfa_program (fde->instructions, fde->end, next_frame, fs,
+  execute_cfa_program (fde->instructions, fde->end, this_frame, fs,
 		       fde->eh_frame_p);
 
   /* Caclulate the CFA.  */
   switch (fs->cfa_how)
     {
     case CFA_REG_OFFSET:
-      cache->cfa = read_reg (next_frame, fs->cfa_reg);
+      cache->cfa = read_reg (this_frame, fs->cfa_reg);
       if (fs->armcc_cfa_offsets_reversed)
 	cache->cfa -= fs->cfa_offset;
       else
@@ -880,7 +883,7 @@ dwarf2_frame_cache (struct frame_info *n
 
     case CFA_EXP:
       cache->cfa =
-	execute_stack_op (fs->cfa_exp, fs->cfa_exp_len, next_frame, 0);
+	execute_stack_op (fs->cfa_exp, fs->cfa_exp_len, this_frame, 0);
       break;
 
     default:
@@ -892,7 +895,7 @@ dwarf2_frame_cache (struct frame_info *n
     int regnum;
 
     for (regnum = 0; regnum < num_regs; regnum++)
-      dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], next_frame);
+      dwarf2_frame_init_reg (gdbarch, regnum, &cache->reg[regnum], this_frame);
   }
 
   /* Go through the DWARF2 CFI generated table and save its register
@@ -995,118 +998,77 @@ incomplete CFI data; unspecified registe
 }
 
 static void
-dwarf2_frame_this_id (struct frame_info *next_frame, void **this_cache,
+dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache,
 		      struct frame_id *this_id)
 {
   struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (next_frame, this_cache);
+    dwarf2_frame_cache (this_frame, this_cache);
 
   if (cache->undefined_retaddr)
     return;
 
-  (*this_id) = frame_id_build (cache->cfa,
-			       frame_func_unwind (next_frame, NORMAL_FRAME));
+  (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame));
 }
 
-static void
-dwarf2_signal_frame_this_id (struct frame_info *next_frame, void **this_cache,
-			     struct frame_id *this_id)
-{
-  struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (next_frame, this_cache);
-
-  if (cache->undefined_retaddr)
-    return;
-
-  (*this_id) = frame_id_build (cache->cfa,
-			       frame_func_unwind (next_frame, SIGTRAMP_FRAME));
-}
-
-static void
-dwarf2_frame_prev_register (struct frame_info *next_frame, void **this_cache,
-			    int regnum, int *optimizedp,
-			    enum lval_type *lvalp, CORE_ADDR *addrp,
-			    int *realnump, gdb_byte *valuep)
+static struct value *
+dwarf2_frame_prev_register_value (struct frame_info *this_frame,
+				  void **this_cache, int regnum)
 {
-  struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (next_frame, this_cache);
+    dwarf2_frame_cache (this_frame, this_cache);
+  CORE_ADDR addr;
+  int realnum;
 
   switch (cache->reg[regnum].how)
     {
     case DWARF2_FRAME_REG_UNDEFINED:
       /* If CFI explicitly specified that the value isn't defined,
 	 mark it as optimized away; the value isn't available.  */
-      *optimizedp = 1;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
+      return frame_unwind_got_optimized (this_frame, regnum);
+#if 0
+      /* FIXME: There's no easy way to do this now so we need to figure
+	 out where it mattered.  A strategic error when attempting to
+	 access the contents of an optimized-out value should turn
+	 it up.  This patch causes no failures, so either it has
+	 been fixed or the testsuite does not catch it.
+
+         I suspect making frame_pop ignore unavailable registers
+         would do the trick.  */
       if (valuep)
 	{
 	  /* In some cases, for example %eflags on the i386, we have
 	     to provide a sane value, even though this register wasn't
-	     saved.  Assume we can get it from NEXT_FRAME.  */
-	  frame_unwind_register (next_frame, regnum, valuep);
+	     saved.  Assume we can get it from the next frame.  */
+	  get_frame_register (this_frame, regnum, valuep);
 	}
       break;
+#endif
 
     case DWARF2_FRAME_REG_SAVED_OFFSET:
-      *optimizedp = 0;
-      *lvalp = lval_memory;
-      *addrp = cache->cfa + cache->reg[regnum].loc.offset;
-      *realnump = -1;
-      if (valuep)
-	{
-	  /* Read the value in from memory.  */
-	  read_memory (*addrp, valuep, register_size (gdbarch, regnum));
-	}
-      break;
+      addr = cache->cfa + cache->reg[regnum].loc.offset;
+      return frame_unwind_got_memory (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_REG:
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      *addrp = 0;
-      *realnump = gdbarch_dwarf2_reg_to_regnum
-		    (gdbarch, cache->reg[regnum].loc.reg);
-      if (valuep)
-	frame_unwind_register (next_frame, (*realnump), valuep);
-      break;
+      realnum
+	= gdbarch_dwarf2_reg_to_regnum (gdbarch, cache->reg[regnum].loc.reg);
+      return value_of_register_lazy (this_frame, realnum);
 
     case DWARF2_FRAME_REG_SAVED_EXP:
-      *optimizedp = 0;
-      *lvalp = lval_memory;
-      *addrp = execute_stack_op (cache->reg[regnum].loc.exp,
-				 cache->reg[regnum].exp_len,
-				 next_frame, cache->cfa);
-      *realnump = -1;
-      if (valuep)
-	{
-	  /* Read the value in from memory.  */
-	  read_memory (*addrp, valuep, register_size (gdbarch, regnum));
-	}
-      break;
+      addr = execute_stack_op (cache->reg[regnum].loc.exp,
+			       cache->reg[regnum].exp_len,
+			       this_frame, cache->cfa);
+      return frame_unwind_got_memory (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_VAL_OFFSET:
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-	store_unsigned_integer (valuep, register_size (gdbarch, regnum),
-				cache->cfa + cache->reg[regnum].loc.offset);
-      break;
+      addr = cache->cfa + cache->reg[regnum].loc.offset;
+      return frame_unwind_got_constant (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_VAL_EXP:
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-	store_unsigned_integer (valuep, register_size (gdbarch, regnum),
-				execute_stack_op (cache->reg[regnum].loc.exp,
-						  cache->reg[regnum].exp_len,
-						  next_frame, cache->cfa));
-      break;
+      addr = execute_stack_op (cache->reg[regnum].loc.exp,
+			       cache->reg[regnum].exp_len,
+			       this_frame, cache->cfa);
+      return frame_unwind_got_constant (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_UNSPECIFIED:
       /* GCC, in its infinite wisdom decided to not provide unwind
@@ -1116,57 +1078,24 @@ dwarf2_frame_prev_register (struct frame
 	 "undefined").  Code above issues a complaint about this.
 	 Here just fudge the books, assume GCC, and that the value is
 	 more inner on the stack.  */
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      *addrp = 0;
-      *realnump = regnum;
-      if (valuep)
-	frame_unwind_register (next_frame, (*realnump), valuep);
-      break;
+      return value_of_register_lazy (this_frame, regnum);
 
     case DWARF2_FRAME_REG_SAME_VALUE:
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      *addrp = 0;
-      *realnump = regnum;
-      if (valuep)
-	frame_unwind_register (next_frame, (*realnump), valuep);
-      break;
+      return value_of_register_lazy (this_frame, regnum);
 
     case DWARF2_FRAME_REG_CFA:
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-	pack_long (valuep, register_type (gdbarch, regnum), cache->cfa);
-      break;
+      return frame_unwind_got_address (this_frame, regnum, cache->cfa);
 
     case DWARF2_FRAME_REG_CFA_OFFSET:
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-	pack_long (valuep, register_type (gdbarch, regnum),
-		   cache->cfa + cache->reg[regnum].loc.offset);
-      break;
+      addr = cache->cfa + cache->reg[regnum].loc.offset;
+      return frame_unwind_got_address (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_RA_OFFSET:
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-        {
-          CORE_ADDR pc = cache->reg[regnum].loc.offset;
-
-          regnum = gdbarch_dwarf2_reg_to_regnum
-		     (gdbarch, cache->retaddr_reg.loc.reg);
-          pc += frame_unwind_register_unsigned (next_frame, regnum);
-          pack_long (valuep, register_type (gdbarch, regnum), pc);
-        }
-      break;
+      addr = cache->reg[regnum].loc.offset;
+      regnum = gdbarch_dwarf2_reg_to_regnum
+	(gdbarch, cache->retaddr_reg.loc.reg);
+      addr += get_frame_register_unsigned (this_frame, regnum);
+      return frame_unwind_got_address (this_frame, regnum, addr);
 
     default:
       internal_error (__FILE__, __LINE__, _("Unknown register rule."));
@@ -1177,14 +1106,22 @@ static const struct frame_unwind dwarf2_
 {
   NORMAL_FRAME,
   dwarf2_frame_this_id,
-  dwarf2_frame_prev_register
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  dwarf2_frame_prev_register_value
 };
 
 static const struct frame_unwind dwarf2_signal_frame_unwind =
 {
   SIGTRAMP_FRAME,
-  dwarf2_signal_frame_this_id,
-  dwarf2_frame_prev_register
+  dwarf2_frame_this_id,
+  NULL,
+  NULL,
+  NULL,
+  NULL,
+  dwarf2_frame_prev_register_value
 };
 
 const struct frame_unwind *
@@ -1222,10 +1159,10 @@ dwarf2_frame_sniffer (struct frame_info 
    response to the "info frame" command.  */
 
 static CORE_ADDR
-dwarf2_frame_base_address (struct frame_info *next_frame, void **this_cache)
+dwarf2_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
   struct dwarf2_frame_cache *cache =
-    dwarf2_frame_cache (next_frame, this_cache);
+    dwarf2_frame_cache (this_frame, this_cache);
 
   return cache->cfa;
 }
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c	2007-10-17 11:18:48.000000000 -0400
+++ src/gdb/frame-unwind.c	2007-10-17 11:22:16.000000000 -0400
@@ -20,8 +20,11 @@
 #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;
@@ -107,6 +110,67 @@ frame_unwind_find_by_frame (struct frame
   internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
 }
 
+/* Helper functions for value-based register unwinding.  These return
+   a (possibly lazy) value of the appropriate type.  */
+
+/* Return a value which indicates that REGNUM from FRAME is not
+   available.  */
+
+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 REGNUM from FRAME is saved
+   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 REGNUM from FRAME 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 REGNUM from FRAME 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/sparc-tdep.c
===================================================================
--- src.orig/gdb/sparc-tdep.c	2007-10-17 11:18:48.000000000 -0400
+++ src/gdb/sparc-tdep.c	2007-10-17 11:19:45.000000000 -0400
@@ -1191,7 +1191,7 @@ sparc32_stabs_argument_has_addr (struct 
 static int
 sparc32_dwarf2_struct_return_p (struct frame_info *next_frame)
 {
-  CORE_ADDR pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+  CORE_ADDR pc = get_frame_address_in_block (this_frame, NORMAL_FRAME);
   struct symbol *sym = find_pc_function (pc);
 
   if (sym)
@@ -1202,7 +1202,7 @@ sparc32_dwarf2_struct_return_p (struct f
 static void
 sparc32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
 			       struct dwarf2_frame_state_reg *reg,
-			       struct frame_info *next_frame)
+			       struct frame_info *this_frame)
 {
   int off;
 
@@ -1221,7 +1221,7 @@ sparc32_dwarf2_frame_init_reg (struct gd
     case SPARC32_NPC_REGNUM:
       reg->how = DWARF2_FRAME_REG_RA_OFFSET;
       off = 8;
-      if (sparc32_dwarf2_struct_return_p (next_frame))
+      if (sparc32_dwarf2_struct_return_p (this_frame))
 	off += 4;
       if (regnum == SPARC32_NPC_REGNUM)
 	off += 4;
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in	2007-10-17 11:20:53.000000000 -0400
+++ src/gdb/Makefile.in	2007-10-17 11:22:01.000000000 -0400
@@ -2040,7 +2040,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]