summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-03-04 23:15:24 +0000
committerAndrew Cagney <cagney@redhat.com>2003-03-04 23:15:24 +0000
commite8a2822e65c51b496829a4fa87ee38cabbcb3259 (patch)
tree4b9f6b082c513718684ea7fd276ed01ca41ef1dd
parentc7d043fae8b1bf4c64ef900e2aaca94276cbffee (diff)
downloadgdb-e8a2822e65c51b496829a4fa87ee38cabbcb3259.tar.gz
2003-03-04 Andrew Cagney <cagney@redhat.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.
-rw-r--r--gdb/ChangeLog26
-rw-r--r--gdb/d10v-tdep.c198
-rw-r--r--gdb/dummy-frame.c41
-rw-r--r--gdb/frame-unwind.h116
-rw-r--r--gdb/frame.c41
-rw-r--r--gdb/frame.h4
-rw-r--r--gdb/sentinel-frame.c41
7 files changed, 283 insertions, 184 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d091e2e1dfe..32b799017e5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,29 @@
+2003-03-04 Andrew Cagney <cagney@redhat.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.
+
2003-03-03 Andrew Cagney <cagney@redhat.com>
* frame.c (frame_id_unwind): Delete function.
diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c
index addf9caee96..9111aa318d5 100644
--- a/gdb/d10v-tdep.c
+++ b/gdb/d10v-tdep.c
@@ -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 @@ d10v_skip_prologue (CORE_ADDR pc)
struct d10v_unwind_cache
{
- CORE_ADDR return_pc;
+ CORE_ADDR base;
int frameless;
int size;
CORE_ADDR *saved_regs;
@@ -698,30 +706,30 @@ prologue_find_regs (struct d10v_unwind_cache *info, unsigned short op,
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 @@ d10v_frame_unwind_cache (struct frame_info *fi,
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
+ else if (info->saved_regs[SP_REGNUM])
{
- ULONGEST return_pc;
- frame_read_unsigned_register (fi, LR_REGNUM, &return_pc);
- info->return_pc = d10v_make_iaddr (return_pc);
+ /* 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;
}
-
- /* The SP is not normally (ever?) saved, but check anyway */
- if (!info->saved_regs[SP_REGNUM])
+ else
{
- /* 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;
- }
+ /* 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;
}
-
+ info->base = d10v_make_daddr (base);
return info;
}
@@ -1423,95 +1426,93 @@ display_trace (int low, int high)
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)
+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 (frame, cache);
- CORE_ADDR addr;
+ 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 @@ saved_regs_unwinder (struct frame_info *frame,
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);
}
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 5b638306fd3..6812ed92d1e 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -105,11 +105,12 @@ find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp)
}
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 @@ discard_innermost_dummy (struct dummy_frame **stack)
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 @@ generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
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 @@ dummy_frame_register_unwind (struct frame_info *frame, void **cache,
/* 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 @@ dummy_frame_register_unwind (struct frame_info *frame, void **cache,
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 @@ dummy_frame_pc_unwind (struct frame_info *frame,
(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 =
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 2c67c969fb1..0ee0bc366d6 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -47,54 +47,102 @@ extern const struct frame_unwind *frame_unwind_find_by_pc (struct gdbarch
*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.
-typedef CORE_ADDR (frame_unwind_pc_ftype) (struct frame_info * frame,
- void **unwind_cache);
+ 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.
-/* Same as for registers above, but return the ID of the frame that
- called this one. */
+ 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.
-typedef void (frame_unwind_id_ftype) (struct frame_info * frame,
- void **unwind_cache,
- struct frame_id * id);
+ 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(). */
-/* 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
+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
+ 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
diff --git a/gdb/frame.c b/gdb/frame.c
index a8c3ce903d4..d70ac9653de 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -135,14 +135,27 @@ frame_find_by_id (struct frame_id id)
}
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 @@ frame_pop (struct frame_info *frame)
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 @@ frame_register_unwind (struct frame_info *frame, int regnum,
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 @@ get_prev_frame (struct frame_info *next_frame)
{
/* 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. */
diff --git a/gdb/frame.h b/gdb/frame.h
index 8dd5c933411..bd20ba7aec1 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -310,6 +310,10 @@ extern const char *frame_map_regnum_to_name (int regnum);
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);
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
index fe11d8a6f43..ef8113da4e4 100644
--- a/gdb/sentinel-frame.c
+++ b/gdb/sentinel-frame.c
@@ -45,19 +45,25 @@ sentinel_frame_cache (struct regcache *regcache)
/* 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 @@ sentinel_frame_register_unwind (struct frame_info *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, 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 @@ sentinel_frame_pc_unwind (struct frame_info *frame,
}
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");