This is the mail archive of the gdb-patches@sources.redhat.com 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]

[offbyone-branch] Re-specify the unwind methods


Hello,

This, I think, `fixes' the off-by-one frame unwind bug. The patch changes the specification of the unwind methods so that that the relationship between the frame and the [prologue] unwind chache is very clear:

/* The following unwind functions all assume a frame chain like:
   (outer) prev <-> this <-> next (inner); Even though some unwind to
   THIS frame (frame ID) and others unwind the PREV frame, they are
   all, consistently passed NEXT frame and THIS cache.

   The intent is to clarify the relationship between NEXT frame and
   THIS cache.  It is, of course, at the expense of confusing somewhat
   the expected unwind behavior of PC/REG unwind VS ID unwind.  Sigh.  */

/* 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.

   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.

   Traditionally, THIS frame's ID was determined by examining THIS
   frame's function's prologue and identifying which register/offset
   are being used as THIS frame's base.

   THIS_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_unwind_id_ftype) (struct frame_info *next_frame,
                                      void **this_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 REGNUM in PREV 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.

   Ex: Assuming THIS is a frameless function that has saved the return
   address (to PREV) in R1, then: a request to unwind THIS's PC
   (returning the value of PC in PREV), becomes a request for the
   value of R1 in THIS (that is where the value was saved), which
   becomes a request to unwind R1 from NEXT.

   THIS_CACHE can be used to share any prologue analysis data with the
   other unwind methods.  Memory for that cache should be allocated
   using frame_obstack_zalloc().  */

typedef void (frame_unwind_reg_ftype) (struct frame_info *next_frame,
                                       void **this_cache,
                                       int prev_regnum,
                                       int *optimized,
                                       enum lval_type * lvalp,
                                       CORE_ADDR *addrp,
                                       int *realnump, void *valuep);

/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
   use the NEXT frame, and its register unwind method, to unwind THIS
   frame's PC, returning the value of PC (the return address) in PREV
   frame.

   Traditionally, THIS frame's PC was unwound by examining THIS
   frame's function prolog and identifying where (in a register or on
   the stack) that return address was saved.

   Please note that this per-frame method may be superseeded by an
   architecture specific method that determines the unwound PC (aka
   return address) using just the register unwind methods.

   THIS_CACHE can be used to share any prologue analysis data with the
   other unwind methods.  Memory for that cache should be allocated
   using frame_obstack_zalloc().  */

typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info *next_frame,
                                           void **this_cache);

/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
   use the NEXT frame, and its register unwind method, to unwind THIS
   frame's entire stack, writing PREV's frames register values into
   REGCACHE.

   NOTE: cagney/2003-01-19: While at present the callers all pop each
   frame in turn, the implementor should try to code things so that
   any frame can be popped directly.

   FIXME: cagney/2003-01-19: Since both FRAME and REGCACHE refer to a
   common register cache, care must be taken when restoring the
   registers.  The `correct fix' is to first first save the registers
   in a scratch cache, and second write that scratch cache back to to
   the real register cache.

   FIXME: cagney/2003-03-04: Isn't this entire function redundant?
   Shouldn't the code instead just iterate through the restore
   reggroup unwinding those registers?  */

typedef void (frame_unwind_pop_ftype) (struct frame_info *next_frame,
                                       void **this_cache,
                                       struct regcache *regcache);

With that specified, the patch goes onto make a first cut (i.e., it doesn't yet work) at updating the corresponding code.

The next pass will be to fix the bugs (and get this out of the theory stage).

After that comes figuring out what to do with the mainline.

Andrew
2003-03-04  Andrew Cagney  <cagney at redhat dot com>

	* d10v-tdep.c (d10v_frame_unwind_cache): Update to work with
	NEXT_FRAME and THIS_CACHE.
	(d10v_frame_pc_unwind): Ditto.
	(d10v_frame_id_unwind): Ditto.
	(saved_regs_unwinder): Ditto.
	(d10v_frame_register_unwind): Ditto.
	* dummy-frame.c (dummy_frame_register_unwind): Ditto.
	(dummy_frame_pc_unwind): Ditto.
	(cached_find_dummy_frame): Ditto.
	(dummy_frame_id_unwind): Ditto.
	(dummy_frame_pop): Ditto.
	* sentinel-frame.c (sentinel_frame_register_unwind): Ditto.
	(sentinel_frame_pc_unwind): Ditto.
	(sentinel_frame_id_unwind): Ditto.
	(sentinel_frame_pop): Ditto.
	* frame.c (frame_id_unwind): Reinstate function.
	* frame.h (frame_id_unwind): Reinstate declaration.
	* frame.c (frame_pc_unwind): Pass frame->next to the PC's unwind
	method.
	(frame_pop, frame_register_unwind): Ditto.
	* frame-unwind.h (frame_unwind_id_ftype, frame_unwind_reg_ftype)
	(frame_unwind_pc_ftype, frame_unwind_pop_ftype): Re-specify
	behavior in terms of PREV_REGNUM, THIS_CACHE and NEXT_FRAME.

Index: d10v-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/d10v-tdep.c,v
retrieving revision 1.80
diff -u -r1.80 d10v-tdep.c
--- d10v-tdep.c	3 Mar 2003 20:50:17 -0000	1.80
+++ d10v-tdep.c	4 Mar 2003 23:14:01 -0000
@@ -45,6 +45,14 @@
 
 #include "gdb_assert.h"
 
+static void d10v_frame_register_unwind (struct frame_info *next_frame,
+					void **this_cache,
+					int prev_regnum, int *optimizedp,
+					enum lval_type *lvalp,
+					CORE_ADDR *addrp,
+					int *realnump, void *bufferp);
+
+
 struct frame_extra_info
   {
     CORE_ADDR return_pc;
@@ -616,7 +624,7 @@
 
 struct d10v_unwind_cache
 {
-  CORE_ADDR return_pc;
+  CORE_ADDR base;
   int frameless;
   int size;
   CORE_ADDR *saved_regs;
@@ -698,30 +706,30 @@
    for it IS the sp for the next frame. */
 
 struct d10v_unwind_cache *
-d10v_frame_unwind_cache (struct frame_info *fi,
-			 void **cache)
+d10v_frame_unwind_cache (struct frame_info *next_frame,
+			 void **this_cache)
 {
-  CORE_ADDR fp, pc;
+  CORE_ADDR pc;
+  ULONGEST sp;
+  ULONGEST base;
   unsigned long op;
   unsigned short op1, op2;
   int i;
   struct d10v_unwind_cache *info;
 
-  if ((*cache))
-    return (*cache);
+  if ((*this_cache))
+    return (*this_cache);
 
   info = FRAME_OBSTACK_ZALLOC (struct d10v_unwind_cache);
-  (*cache) = info;
+  (*this_cache) = info;
   info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
 
   info->frameless = 0;
   info->size = 0;
-  info->return_pc = 0;
 
-  fp = get_frame_base (fi);
   info->next_addr = 0;
 
-  pc = get_pc_function_start (get_frame_pc (fi));
+  pc = get_pc_function_start (frame_pc_unwind (next_frame));
 
   info->uses_frame = 0;
   while (1)
@@ -776,45 +784,40 @@
 
   info->size = -info->next_addr;
 
-  if (!(fp & 0xffff))
-    fp = d10v_read_sp ();
+  /* Start out with the frame's stack top.  */
+  frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
+  sp = d10v_make_daddr (sp);
 
   for (i = 0; i < NUM_REGS - 1; i++)
     if (info->saved_regs[i])
       {
-	info->saved_regs[i] = fp - (info->next_addr - info->saved_regs[i]);
+	info->saved_regs[i] = sp - (info->next_addr - info->saved_regs[i]);
       }
 
-  if (info->saved_regs[LR_REGNUM])
+  /* Compute the frame's base.  */
+  if (info->saved_regs[FP_REGNUM])
     {
-      CORE_ADDR return_pc 
-	= read_memory_unsigned_integer (info->saved_regs[LR_REGNUM], 
-					register_size (current_gdbarch, LR_REGNUM));
-      info->return_pc = d10v_make_iaddr (return_pc);
+      /* The FP was saved, which means that the current FP is live.
+         Unwind its value from the NEXT frame.  */
+      frame_unwind_unsigned_register (next_frame, FP_REGNUM, &base);
+    }
+  else if (info->saved_regs[SP_REGNUM])
+    {
+      /* The SP was saved (this is very unusual), the frame base is
+	 just the PREV's frame's TOP-OF-STACK.  */
+      base = read_memory_unsigned_integer (info->saved_regs[SP_REGNUM], 
+					   register_size (current_gdbarch,
+							  SP_REGNUM));
+      info->frameless = 1;
     }
   else
     {
-      ULONGEST return_pc;
-      frame_read_unsigned_register (fi, LR_REGNUM, &return_pc);
-      info->return_pc = d10v_make_iaddr (return_pc);
+      /* Assume that the FP is this frame's SP but with that pushed
+         stack space added back.  */
+      frame_unwind_unsigned_register (next_frame, SP_REGNUM, &base);
+      base += info->size;
     }
-
-  /* The SP is not normally (ever?) saved, but check anyway */
-  if (!info->saved_regs[SP_REGNUM])
-    {
-      /* if the FP was saved, that means the current FP is valid, */
-      /* otherwise, it isn't being used, so we use the SP instead */
-      if (info->uses_frame)
-	info->saved_regs[SP_REGNUM] 
-	  = d10v_read_fp () + info->size;
-      else
-	{
-	  info->saved_regs[SP_REGNUM] = fp + info->size;
-	  info->frameless = 1;
-	  info->saved_regs[FP_REGNUM] = 0;
-	}
-    }
-
+  info->base = d10v_make_daddr (base);
   return info;
 }
 
@@ -1423,95 +1426,93 @@
 
 
 static CORE_ADDR
-d10v_frame_pc_unwind (struct frame_info *frame,
-		      void **cache)
+d10v_frame_pc_unwind (struct frame_info *next_frame,
+		      void **this_cache)
 {
-  struct d10v_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
-  return info->return_pc;
+  /* FIXME: This shouldn't be needed.  Instead a per-architecture
+     method should be called.  */
+  int optimized;
+  enum lval_type lval;
+  CORE_ADDR addr;
+  int realnum;
+  ULONGEST lr;
+  void *buffer = alloca (max_register_size (current_gdbarch));
+  d10v_frame_register_unwind (next_frame, this_cache, LR_REGNUM, 
+			      &optimized, &lval, &addr, &realnum,
+			      buffer);
+  lr = extract_unsigned_integer (buffer, register_size (current_gdbarch,
+							LR_REGNUM));
+  return d10v_make_iaddr (lr);
+			
 }
 
-/* Given a GDB frame, determine the address of the calling function's
+/* Given the next frame, determine the address of this function's
    frame.  This will be used to create a new GDB frame struct.  */
 
 static void
-d10v_frame_id_unwind (struct frame_info *frame,
-		      void **cache,
-		      struct frame_id *id)
-{
-  struct d10v_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
-  CORE_ADDR addr;
+d10v_frame_id_unwind (struct frame_info *next_frame,
+		      void **this_cache,
+		      struct frame_id *this_id)
+{
+  struct d10v_unwind_cache *info
+    = d10v_frame_unwind_cache (next_frame, this_cache);
+  CORE_ADDR base;
+  CORE_ADDR pc;
 
   /* Start with a NULL frame ID.  */
-  (*id) = null_frame_id;
+  (*this_id) = null_frame_id;
+
+  /* The PC is easy.  */
+  pc = frame_pc_unwind (next_frame);
 
-  if (info->return_pc == IMEM_START
-      || info->return_pc <= IMEM_START
-      || inside_entry_file (info->return_pc))
+  /* This is meant to halt the backtrace at "_start".  Make sure we
+     don't halt it at a generic dummy frame. */
+  if (pc == IMEM_START || pc <= IMEM_START || inside_entry_file (pc))
     {
-      /* This is meant to halt the backtrace at "_start".
-	 Make sure we don't halt it at a generic dummy frame. */
       return;
     }
 
+#if 0
   if (!info->saved_regs[FP_REGNUM])
     {
       if (!info->saved_regs[SP_REGNUM]
 	  || info->saved_regs[SP_REGNUM] == STACK_START)
 	return;
 
-      id->base = info->saved_regs[SP_REGNUM];
-      id->pc = info->return_pc;
+      this_id->base = info->saved_regs[SP_REGNUM];
+      this_id->pc = info->return_pc;
     }
 
   addr = read_memory_unsigned_integer (info->saved_regs[FP_REGNUM],
 				       register_size (current_gdbarch, FP_REGNUM));
   if (addr == 0)
     return;
+#endif
 
-  id->base = d10v_make_daddr (addr);
-  id->pc = info->return_pc;
+  /* Hopefully the prolog analysis has correctly determined the
+     frame's base.  */
+  this_id->base = info->base;
+  this_id->pc = pc;
 }
 
 static void
-saved_regs_unwinder (struct frame_info *frame,
+saved_regs_unwinder (struct frame_info *next_frame,
 		     CORE_ADDR *saved_regs,
-		     int regnum, int *optimizedp,
+		     int prev_regnum, int *optimizedp,
 		     enum lval_type *lvalp, CORE_ADDR *addrp,
 		     int *realnump, void *bufferp)
 {
-  /* If we're using generic dummy frames, we'd better not be in a call
-     dummy.  (generic_call_dummy_register_unwind ought to have been called
-     instead.)  */
-  gdb_assert (!(DEPRECATED_USE_GENERIC_DUMMY_FRAMES
-		&& (get_frame_type (frame) == DUMMY_FRAME)));
-
-  if (saved_regs[regnum] != 0)
+  if (saved_regs[prev_regnum] != 0)
     {
-      if (regnum == SP_REGNUM)
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = saved_regs[prev_regnum];
+      *realnump = -1;
+      if (bufferp != NULL)
 	{
-	  /* SP register treated specially.  */
-	  *optimizedp = 0;
-	  *lvalp = not_lval;
-	  *addrp = 0;
-	  *realnump = -1;
-	  if (bufferp != NULL)
-	    store_address (bufferp, register_size (current_gdbarch, regnum),
-			   saved_regs[regnum]);
-	}
-      else
-	{
-	  /* Any other register is saved in memory, fetch it but cache
-	     a local copy of its value.  */
-	  *optimizedp = 0;
-	  *lvalp = lval_memory;
-	  *addrp = saved_regs[regnum];
-	  *realnump = -1;
-	  if (bufferp != NULL)
-	    {
-	      /* Read the value in from memory.  */
-	      read_memory (saved_regs[regnum], bufferp,
-			   register_size (current_gdbarch, regnum));
-	    }
+	  /* Read the value in from memory.  */
+	  read_memory (saved_regs[prev_regnum], bufferp,
+		       register_size (current_gdbarch, prev_regnum));
 	}
       return;
     }
@@ -1520,20 +1521,23 @@
      value.  If a value is needed, pass the request on down the chain;
      otherwise just return an indication that the value is in the same
      register as the next frame.  */
-  frame_register (frame, regnum, optimizedp, lvalp, addrp,
-		  realnump, bufferp);
+  frame_register_unwind (next_frame, prev_regnum, optimizedp, lvalp, addrp,
+			 realnump, bufferp);
 }
 
 
 static void
-d10v_frame_register_unwind (struct frame_info *frame,
-			    void **cache,
-			    int regnum, int *optimizedp,
+d10v_frame_register_unwind (struct frame_info *next_frame,
+			    void **this_cache,
+			    int prev_regnum, int *optimizedp,
 			    enum lval_type *lvalp, CORE_ADDR *addrp,
 			    int *realnump, void *bufferp)
 {
-  struct d10v_unwind_cache *info = d10v_frame_unwind_cache (frame, cache);
-  saved_regs_unwinder (frame, info->saved_regs, regnum, optimizedp,
+  struct d10v_unwind_cache *info
+    = d10v_frame_unwind_cache (next_frame, this_cache);
+  if (prev_regnum == PC_REGNUM)
+    prev_regnum = LR_REGNUM;
+  saved_regs_unwinder (next_frame, info->saved_regs, prev_regnum, optimizedp,
 		       lvalp, addrp, realnump, bufferp);
 }
 
Index: dummy-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dummy-frame.c,v
retrieving revision 1.10
diff -u -r1.10 dummy-frame.c
--- dummy-frame.c	19 Jan 2003 17:39:16 -0000	1.10
+++ dummy-frame.c	4 Mar 2003 23:14:01 -0000
@@ -105,11 +105,12 @@
 }
 
 struct dummy_frame *
-cached_find_dummy_frame (struct frame_info *frame, void **cache)
+cached_find_dummy_frame (struct frame_info *next_frame, void **this_cache)
 {
-  if ((*cache) == NULL)
-    (*cache) = find_dummy_frame (get_frame_pc (frame), get_frame_base (frame));
-  return (*cache);
+  if ((*this_cache) == NULL)
+    (*this_cache) = find_dummy_frame (frame_pc_unwind (next_frame),
+				      frame_id_unwind (next_frame).base);
+  return (*this_cache);
 }
 
 struct regcache *
@@ -286,13 +287,13 @@
    dummy stack frame. */
 
 static void
-dummy_frame_pop (struct frame_info *fi, void **cache,
+dummy_frame_pop (struct frame_info *next_frame, void **this_cache,
 		 struct regcache *regcache)
 {
-  struct dummy_frame *dummy = cached_find_dummy_frame (fi, cache);
+  struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
 
   /* If it isn't, what are we even doing here?  */
-  gdb_assert (get_frame_type (fi) == DUMMY_FRAME);
+  /* gdb_assert (get_frame_type (fi) == DUMMY_FRAME); */
 
   if (dummy == NULL)
     error ("Can't pop dummy frame!");
@@ -344,12 +345,12 @@
    register value is taken from the local copy of the register buffer.  */
 
 static void
-dummy_frame_register_unwind (struct frame_info *frame, void **cache,
-			     int regnum, int *optimized,
+dummy_frame_register_unwind (struct frame_info *next_frame, void **this_cache,
+			     int prev_regnum, int *optimized,
 			     enum lval_type *lvalp, CORE_ADDR *addrp,
 			     int *realnum, void *bufferp)
 {
-  struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
+  struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
   gdb_assert (dummy != NULL);
 
   /* Describe the register's location.  Generic dummy frames always
@@ -366,7 +367,7 @@
       /* 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 (dummy->regcache, regnum, bufferp);
+      regcache_cooked_read (dummy->regcache, prev_regnum, bufferp);
     }
 }
 
@@ -374,10 +375,10 @@
    previous frame.  */
 
 static CORE_ADDR
-dummy_frame_pc_unwind (struct frame_info *frame,
-		       void **cache)
+dummy_frame_pc_unwind (struct frame_info *next_frame,
+		       void **this_cache)
 {
-  struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
+  struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
   /* Oops!  In a dummy-frame but can't find the stack dummy.  Pretend
      that the frame doesn't unwind.  Should this function instead
      return a has-no-caller indication?  */
@@ -391,18 +392,18 @@
    (the frame that the dummy has the saved state of).  */
 
 static void
-dummy_frame_id_unwind (struct frame_info *frame,
-		       void **cache,
-		       struct frame_id *id)
+dummy_frame_id_unwind (struct frame_info *next_frame,
+		       void **this_cache,
+		       struct frame_id *this_id)
 {
-  struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
+  struct dummy_frame *dummy = cached_find_dummy_frame (next_frame, this_cache);
   /* Oops!  In a dummy-frame but can't find the stack dummy.  Pretend
      that the frame doesn't unwind.  Should this function instead
      return a has-no-caller indication?  */
   if (dummy == NULL)
-    (*id) = null_frame_id;
+    (*this_id) = null_frame_id;
   else
-    (*id) = dummy->id;
+    (*this_id) = dummy->id;
 }
 
 static struct frame_unwind dummy_frame_unwind =
Index: frame-unwind.h
===================================================================
RCS file: /cvs/src/src/gdb/frame-unwind.h,v
retrieving revision 1.3
diff -u -r1.3 frame-unwind.h
--- frame-unwind.h	19 Jan 2003 17:39:16 -0000	1.3
+++ frame-unwind.h	4 Mar 2003 23:14:01 -0000
@@ -47,54 +47,102 @@
 							   *gdbarch,
 							   CORE_ADDR pc);
 
-/* Return the location (and possibly value) of REGNUM for the previous
-   (older, up) frame.  All parameters except VALUEP can be assumed to
-   be non NULL.  When VALUEP is NULL, just the location of the
-   register should be returned.
-
-   UNWIND_CACHE is provided as mechanism for implementing a per-frame
-   local cache.  It's initial value being NULL.  Memory for that cache
-   should be allocated using frame_obstack_zalloc().
-
-   Register window architectures (eg SPARC) should note that REGNUM
-   identifies the register for the previous frame.  For instance, a
-   request for the value of "o1" for the previous frame would be found
-   in the register "i1" in this FRAME.  */
-
-typedef void (frame_unwind_reg_ftype) (struct frame_info * frame,
-				       void **unwind_cache,
-				       int regnum,
+/* The following unwind functions all assume a frame chain like:
+   (outer) prev <-> this <-> next (inner); Even though some unwind to
+   THIS frame (frame ID) and others unwind the PREV frame, they are
+   all, consistently passed NEXT frame and THIS cache.
+
+   The intent is to clarify the relationship between NEXT frame and
+   THIS cache.  It is, of course, at the expense of confusing somewhat
+   the expected unwind behavior of PC/REG unwind VS ID unwind.  Sigh.  */
+
+/* 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.
+
+   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.
+
+   Traditionally, THIS frame's ID was determined by examining THIS
+   frame's function's prologue and identifying which register/offset
+   are being used as THIS frame's base.
+
+   THIS_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_unwind_id_ftype) (struct frame_info *next_frame,
+				      void **this_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 REGNUM in PREV 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.
+
+   Ex: Assuming THIS is a frameless function that has saved the return
+   address (to PREV) in R1, then: a request to unwind THIS's PC
+   (returning the value of PC in PREV), becomes a request for the
+   value of R1 in THIS (that is where the value was saved), which
+   becomes a request to unwind R1 from NEXT.
+
+   THIS_CACHE can be used to share any prologue analysis data with the
+   other unwind methods.  Memory for that cache should be allocated
+   using frame_obstack_zalloc().  */
+
+typedef void (frame_unwind_reg_ftype) (struct frame_info *next_frame,
+				       void **this_cache,
+				       int prev_regnum,
 				       int *optimized,
 				       enum lval_type * lvalp,
 				       CORE_ADDR *addrp,
 				       int *realnump, void *valuep);
 
-/* Same as for registers above, but return the address at which the
-   calling frame would resume.  */
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+   use the NEXT frame, and its register unwind method, to unwind THIS
+   frame's PC, returning the value of PC (the return address) in PREV
+   frame.
+
+   Traditionally, THIS frame's PC was unwound by examining THIS
+   frame's function prolog and identifying where (in a register or on
+   the stack) that return address was saved.
+
+   Please note that this per-frame method may be superseeded by an
+   architecture specific method that determines the unwound PC (aka
+   return address) using just the register unwind methods.
+
+   THIS_CACHE can be used to share any prologue analysis data with the
+   other unwind methods.  Memory for that cache should be allocated
+   using frame_obstack_zalloc().  */
+
+typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info *next_frame,
+					   void **this_cache);
+
+/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
+   use the NEXT frame, and its register unwind method, to unwind THIS
+   frame's entire stack, writing PREV's frames register values into
+   REGCACHE.
 
-typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info * frame,
-					   void **unwind_cache);
-
-/* Same as for registers above, but return the ID of the frame that
-   called this one.  */
-
-typedef void (frame_unwind_id_ftype) (struct frame_info * frame,
-				      void **unwind_cache,
-				      struct frame_id * id);
-
-/* Discard the frame by restoring the registers (in regcache) back to
-   that of the caller.  */
-/* NOTE: cagney/2003-01-19: While at present the callers all pop each
+   NOTE: cagney/2003-01-19: While at present the callers all pop each
    frame in turn, the implementor should try to code things so that
-   any frame can be popped directly.  */
-/* FIXME: cagney/2003-01-19: Since both FRAME and REGCACHE refer to a
+   any frame can be popped directly.
+
+   FIXME: cagney/2003-01-19: Since both FRAME and REGCACHE refer to a
    common register cache, care must be taken when restoring the
    registers.  The `correct fix' is to first first save the registers
    in a scratch cache, and second write that scratch cache back to to
-   the real register cache.  */
+   the real register cache.
+
+   FIXME: cagney/2003-03-04: Isn't this entire function redundant?
+   Shouldn't the code instead just iterate through the restore
+   reggroup unwinding those registers?  */
 
-typedef void (frame_unwind_pop_ftype) (struct frame_info *frame,
-				       void **unwind_cache,
+typedef void (frame_unwind_pop_ftype) (struct frame_info *next_frame,
+				       void **this_cache,
 				       struct regcache *regcache);
 
 struct frame_unwind
Index: frame.c
===================================================================
RCS file: /cvs/src/src/gdb/frame.c,v
retrieving revision 1.71.2.1
diff -u -r1.71.2.1 frame.c
--- frame.c	3 Mar 2003 21:19:03 -0000	1.71.2.1
+++ frame.c	4 Mar 2003 23:14:04 -0000
@@ -135,14 +135,27 @@
 }
 
 CORE_ADDR
-frame_pc_unwind (struct frame_info *frame)
+frame_pc_unwind (struct frame_info *this_frame)
 {
-  if (!frame->pc_unwind_cache_p)
+  if (!this_frame->pc_unwind_cache_p)
     {
-      frame->pc_unwind_cache = frame->unwind->pc (frame, &frame->unwind_cache);
-      frame->pc_unwind_cache_p = 1;
+      this_frame->pc_unwind_cache
+	= this_frame->unwind->pc (this_frame->next, &this_frame->unwind_cache);
+      this_frame->pc_unwind_cache_p = 1;
     }
-  return frame->pc_unwind_cache;
+  return this_frame->pc_unwind_cache;
+}
+
+struct frame_id
+frame_id_unwind (struct frame_info *this_frame)
+{
+  if (!this_frame->id_unwind_cache_p)
+    {
+      this_frame->unwind->id (this_frame->next, &this_frame->unwind_cache,
+			      &this_frame->id_unwind_cache);
+      this_frame->id_unwind_cache_p = 1;
+    }
+  return this_frame->id_unwind_cache;
 }
 
 void
@@ -154,12 +167,12 @@
      values are needed to restore other registers.  Instead, this code
      should pass in a scratch cache and, as a second step, restore the
      registers using that.  */
-  frame->unwind->pop (frame, &frame->unwind_cache, current_regcache);
+  frame->unwind->pop (frame->next, &frame->unwind_cache, current_regcache);
   flush_cached_frames ();
 }
 
 void
-frame_register_unwind (struct frame_info *frame, int regnum,
+frame_register_unwind (struct frame_info *this_frame, int prev_regnum,
 		       int *optimizedp, enum lval_type *lvalp,
 		       CORE_ADDR *addrp, int *realnump, void *bufferp)
 {
@@ -177,11 +190,13 @@
      is broken.  There is always a frame.  If there, for some reason,
      isn't, there is some pretty busted code as it should have
      detected the problem before calling here.  */
-  gdb_assert (frame != NULL);
+  gdb_assert (this_frame != NULL && this_frame->next != NULL);
 
-  /* Ask this frame to unwind its register.  */
-  frame->unwind->reg (frame, &frame->unwind_cache, regnum,
-		      optimizedp, lvalp, addrp, realnump, bufferp);
+  /* Ask this frame's register unwinder to return the value of
+     PREV_REGNUM using register values unwound from the NEXT frame.  */
+  this_frame->unwind->reg (this_frame->next, &this_frame->unwind_cache,
+			   prev_regnum, optimizedp, lvalp, addrp, realnump,
+			   bufferp);
 }
 
 void
@@ -1336,8 +1351,8 @@
   {
     /* FIXME: cagney/2002-12-18: Instead of this hack, should just
        save the frame ID directly.  */
-    struct frame_id id = prev_frame->unwind->id (next_frame,
-						 &prev_frame->unwind_cache);
+    struct frame_id id;
+    prev_frame->unwind->id (next_frame, &prev_frame->unwind_cache, &id);
     /* Check that the unwound ID is valid.  As of 2003-02-24 the
        x86-64 was returning an invalid frame ID when trying to do an
        unwind a sentinel frame that belonged to a frame dummy.  */
Index: frame.h
===================================================================
RCS file: /cvs/src/src/gdb/frame.h,v
retrieving revision 1.70.2.1
diff -u -r1.70.2.1 frame.h
--- frame.h	3 Mar 2003 21:19:04 -0000	1.70.2.1
+++ frame.h	4 Mar 2003 23:14:04 -0000
@@ -310,6 +310,10 @@
 
 extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
 
+/* Unwind the frame ID.  Return an ID that uniquely identifies the
+   caller's frame.  */
+extern struct frame_id frame_id_unwind (struct frame_info *frame);
+
 /* Discard the specified frame.  Restoring the registers to the state
    of the caller.  */
 extern void frame_pop (struct frame_info *frame);
Index: sentinel-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/sentinel-frame.c,v
retrieving revision 1.2
diff -u -r1.2 sentinel-frame.c
--- sentinel-frame.c	27 Jan 2003 21:41:41 -0000	1.2
+++ sentinel-frame.c	4 Mar 2003 23:14:04 -0000
@@ -45,19 +45,25 @@
 /* Here the register value is taken direct from the register cache.  */
 
 void
-sentinel_frame_register_unwind (struct frame_info *frame,
-				void **unwind_cache,
-				int regnum, int *optimized,
+sentinel_frame_register_unwind (struct frame_info *next_frame,
+				void **this_cache,
+				int prev_regnum, int *optimized,
 				enum lval_type *lvalp, CORE_ADDR *addrp,
 				int *realnum, void *bufferp)
 {
-  struct frame_unwind_cache *cache = *unwind_cache;
+  /* Hey don't let on but, for the sentinel frame, next_frame->next ==
+     next_frame.  Fortunatly, that local knowledge isn't needed,
+     instead THIS_CACHE contains all the information needed to find
+     the frame's thread's REGCACHE and that REGCACHE is then accessed
+     directly.  */
+  struct frame_unwind_cache *cache = *this_cache;
+
   /* Describe the register's location.  A reg-frame maps all registers
      onto the corresponding hardware register.  */
   *optimized = 0;
   *lvalp = lval_register;
-  *addrp = REGISTER_BYTE (regnum);
-  *realnum = regnum;
+  *addrp = REGISTER_BYTE (prev_regnum);
+  *realnum = prev_regnum;
 
   /* If needed, find and return the value of the register.  */
   if (bufferp != NULL)
@@ -66,13 +72,13 @@
       /* 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);
+      regcache_cooked_read (cache->regcache, prev_regnum, bufferp);
     }
 }
 
 CORE_ADDR
-sentinel_frame_pc_unwind (struct frame_info *frame,
-			  void **cache)
+sentinel_frame_pc_unwind (struct frame_info *next_frame,
+			  void **this_cache)
 {
   /* FIXME: cagney/2003-01-08: This should be using a per-architecture
      method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
@@ -82,21 +88,16 @@
 }
 
 void
-sentinel_frame_id_unwind (struct frame_info *frame,
-			  void **cache,
-			  struct frame_id *id)
+sentinel_frame_id_unwind (struct frame_info *next_frame,
+			  void **this_cache,
+			  struct frame_id *this_id)
 {
-  /* FIXME: cagney/2003-01-08: This should be using a per-architecture
-     method that doesn't suffer from DECR_PC_AFTER_BREAK problems.
-     Such a method would take unwind_cache, regcache and stop reason
-     parameters.  */
-  id->base = read_fp ();
-  id->pc = read_pc ();
+  internal_error (__FILE__, __LINE__, "sentinel_frame_id_unwind called");
 }
 
 static void
-sentinel_frame_pop (struct frame_info *frame,
-		    void **cache,
+sentinel_frame_pop (struct frame_info *next_frame,
+		    void **this_cache,
 		    struct regcache *regcache)
 {
   internal_error (__FILE__, __LINE__, "Function sentinal_frame_pop called");

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