diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-03-04 23:15:24 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-03-04 23:15:24 +0000 |
commit | fc34faedba1aacec97bca094627e9c322049e68d (patch) | |
tree | a3687e35ec968fa55c6705cbdfb786c10ca6fc33 | |
parent | d0107aa6c25b4caf3cf7e6ef7268239e6834ba92 (diff) | |
download | gdb-fc34faedba1aacec97bca094627e9c322049e68d.zip gdb-fc34faedba1aacec97bca094627e9c322049e68d.tar.gz gdb-fc34faedba1aacec97bca094627e9c322049e68d.tar.bz2 |
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/ChangeLog | 26 | ||||
-rw-r--r-- | gdb/d10v-tdep.c | 198 | ||||
-rw-r--r-- | gdb/dummy-frame.c | 41 | ||||
-rw-r--r-- | gdb/frame-unwind.h | 116 | ||||
-rw-r--r-- | gdb/frame.c | 41 | ||||
-rw-r--r-- | gdb/frame.h | 4 | ||||
-rw-r--r-- | gdb/sentinel-frame.c | 41 |
7 files changed, 283 insertions, 184 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d091e2e..32b7990 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 addf9ca..9111aa3 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 5b63830..6812ed9 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 2c67c96..0ee0bc3 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 a8c3ce9..d70ac96 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 8dd5c93..bd20ba7 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 fe11d8a..ef8113d 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"); |