This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[offbyone-branch] Re-specify the unwind methods
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Tue, 04 Mar 2003 18:26:11 -0500
- Subject: [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");