diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-03-13 17:33:52 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-03-13 17:33:52 +0000 |
commit | 01d8344e9f2cae907cbea8a79e9854ca8e72a36b (patch) | |
tree | 3884211d0bb94f2c073d7876c6c8b87aaf972ce5 | |
parent | ab015601f0f6fc053476cad220d7f7908fdcd850 (diff) | |
download | gdb-01d8344e9f2cae907cbea8a79e9854ca8e72a36b.zip gdb-01d8344e9f2cae907cbea8a79e9854ca8e72a36b.tar.gz gdb-01d8344e9f2cae907cbea8a79e9854ca8e72a36b.tar.bz2 |
2003-03-13 Andrew Cagney <cagney@redhat.com>
* d10v-tdep.c (d10v_frame_this_id): Replace d10v_frame_id_unwind.
(d10v_frame_unwind): Update.
(d10v_frame_prev_register): Replace d10v_frame_register_unwind.
(d10v_frame_unwind_cache): Replace this "fi" with "next_frame".
(saved_regs_unwinder): Replace this "frame" with "next_frame", and
"saved_regs" with "this_saved_regs".
* dummy-frame.c (dummy_frame_unwind): Update.
(cached_find_dummy_frame): Delete.
* frame.c (legacy_frame_p): New function.
(get_prev_frame): Call legacy_frame_p.
* frame.h (legacy_frame_p): Declare.
* dummy-frame.c (dummy_frame_prev_register): Rename
dummy_frame_register_unwind.
(dummy_frame_this_id): Replace dummy_frame_id_unwind.
* sentinel-frame.c (sentinel_frame_prev_register): Replace
sentinel_frame_register_unwind.
(sentinel_frame_this_id): Replace sentinel_frame_id_unwind.
(sentinel_frame_unwinder): Update.
* frame-unwind.c (frame_unwind_find_by_pc): Return
legacy_saved_regs_unwind instead of trad_frame_unwind. Update
comment.
* frame.c (create_sentinel_frame): Initialize prologue_cache.
(frame_register_unwind): Call this frame's prev_register with the
next frame and this frame's prologue cache. Add commented out
code to cache the value.
(get_prev_frame): Call prev frame's this_id with this frame and
prev frame's prologue cache. Document that this call is shifted
one to the left when compared to the frame_register_unwind call.
(legacy_saved_regs_prev_register): Replace
frame_saved_regs_register_unwind.
(legacy_saved_regs_this_id): Replace frame_saved_regs_id_unwind.
(legacy_saved_regs_unwinder): Replace trad_frame_unwinder.
(legacy_saved_regs_unwind): Replace trad_frame_unwind.
* frame.h (legacy_saved_regs_unwind): Replace trad_frame_unwind.
(struct frame_info): Rename "unwind_cache" to "prolog_cache".
* frame-unwind.h (frame_this_id_ftype): Replace
frame_unwind_id_ftype.
(frame_prev_register_ftype): Replace frame_unwind_reg_ftype.
(struct frame_unwind): Update. Rename "id" to "this_id". Rename
"reg" to "prev_register".
-rw-r--r-- | gdb/ChangeLog | 52 | ||||
-rw-r--r-- | gdb/d10v-tdep.c | 120 | ||||
-rw-r--r-- | gdb/dummy-frame.c | 106 | ||||
-rw-r--r-- | gdb/frame-unwind.c | 9 | ||||
-rw-r--r-- | gdb/frame-unwind.h | 110 | ||||
-rw-r--r-- | gdb/frame.c | 146 | ||||
-rw-r--r-- | gdb/frame.h | 15 | ||||
-rw-r--r-- | gdb/sentinel-frame.c | 32 |
8 files changed, 383 insertions, 207 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c9ec531..c634d4c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,55 @@ +2003-03-13 Andrew Cagney <cagney@redhat.com> + + * d10v-tdep.c (d10v_frame_this_id): Replace d10v_frame_id_unwind. + (d10v_frame_unwind): Update. + (d10v_frame_prev_register): Replace d10v_frame_register_unwind. + (d10v_frame_unwind_cache): Replace this "fi" with "next_frame". + (saved_regs_unwinder): Replace this "frame" with "next_frame", and + "saved_regs" with "this_saved_regs". + + * dummy-frame.c (dummy_frame_unwind): Update. + (cached_find_dummy_frame): Delete. + + * frame.c (legacy_frame_p): New function. + (get_prev_frame): Call legacy_frame_p. + * frame.h (legacy_frame_p): Declare. + + * dummy-frame.c (dummy_frame_prev_register): Rename + dummy_frame_register_unwind. + (dummy_frame_this_id): Replace dummy_frame_id_unwind. + + + * sentinel-frame.c (sentinel_frame_prev_register): Replace + sentinel_frame_register_unwind. + (sentinel_frame_this_id): Replace sentinel_frame_id_unwind. + (sentinel_frame_unwinder): Update. + + * frame-unwind.c (frame_unwind_find_by_pc): Return + legacy_saved_regs_unwind instead of trad_frame_unwind. Update + comment. + + * frame.c (create_sentinel_frame): Initialize prologue_cache. + (frame_register_unwind): Call this frame's prev_register with the + next frame and this frame's prologue cache. Add commented out + code to cache the value. + (get_prev_frame): Call prev frame's this_id with this frame and + prev frame's prologue cache. Document that this call is shifted + one to the left when compared to the frame_register_unwind call. + (legacy_saved_regs_prev_register): Replace + frame_saved_regs_register_unwind. + (legacy_saved_regs_this_id): Replace frame_saved_regs_id_unwind. + (legacy_saved_regs_unwinder): Replace trad_frame_unwinder. + (legacy_saved_regs_unwind): Replace trad_frame_unwind. + + * frame.h (legacy_saved_regs_unwind): Replace trad_frame_unwind. + (struct frame_info): Rename "unwind_cache" to "prolog_cache". + + * frame-unwind.h (frame_this_id_ftype): Replace + frame_unwind_id_ftype. + (frame_prev_register_ftype): Replace frame_unwind_reg_ftype. + (struct frame_unwind): Update. Rename "id" to "this_id". Rename + "reg" to "prev_register". + 2003-03-13 D. Venkatasubramanian <dvenkat@noida.hcltech.com> * MAINTAINERS (write after approval): Alphabetically diff --git a/gdb/d10v-tdep.c b/gdb/d10v-tdep.c index b60ce7f..f443cef 100644 --- a/gdb/d10v-tdep.c +++ b/gdb/d10v-tdep.c @@ -705,8 +705,8 @@ 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_prologue_cache) { CORE_ADDR pc; ULONGEST prev_sp; @@ -716,18 +716,18 @@ d10v_frame_unwind_cache (struct frame_info *fi, int i; struct d10v_unwind_cache *info; - if ((*cache)) - return (*cache); + if ((*this_prologue_cache)) + return (*this_prologue_cache); info = FRAME_OBSTACK_ZALLOC (struct d10v_unwind_cache); - (*cache) = info; + (*this_prologue_cache) = info; info->saved_regs = frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS); info->size = 0; info->return_pc = 0; info->sp_offset = 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) @@ -788,7 +788,7 @@ d10v_frame_unwind_cache (struct frame_info *fi, /* The SP was moved to the FP. This indicates that a new frame was created. Get THIS frame's FP value by unwinding it from the next frame. */ - frame_read_unsigned_register (fi, FP_REGNUM, &this_base); + frame_unwind_unsigned_register (next_frame, FP_REGNUM, &this_base); /* The FP points at the last saved register. Adjust the FP back to before the first saved register giving the SP. */ prev_sp = this_base + info->size; @@ -806,7 +806,7 @@ d10v_frame_unwind_cache (struct frame_info *fi, { /* Assume that the FP is this frame's SP but with that pushed stack space added back. */ - frame_read_unsigned_register (fi, SP_REGNUM, &this_base); + frame_unwind_unsigned_register (next_frame, SP_REGNUM, &this_base); prev_sp = this_base + info->size; } @@ -831,7 +831,7 @@ d10v_frame_unwind_cache (struct frame_info *fi, else { ULONGEST return_pc; - frame_read_unsigned_register (fi, LR_REGNUM, &return_pc); + frame_unwind_unsigned_register (next_frame, LR_REGNUM, &return_pc); info->return_pc = d10v_make_iaddr (return_pc); } @@ -1457,58 +1457,55 @@ d10v_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) 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_this_id (struct frame_info *next_frame, + void **this_prologue_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_prologue_cache); + CORE_ADDR base; + CORE_ADDR pc; /* Start with a NULL frame ID. */ - (*id) = null_frame_id; + (*this_id) = null_frame_id; - 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. */ - return; - } + /* The PC is easy. */ + pc = frame_pc_unwind (next_frame); - if (!info->saved_regs[FP_REGNUM]) - { - if (!info->saved_regs[SP_REGNUM] - || info->saved_regs[SP_REGNUM] == STACK_START) - return; + /* 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)) + return; - id->base = info->saved_regs[SP_REGNUM]; - id->pc = info->return_pc; - } + /* Hopefully the prologue analysis either correctly determined the + frame's base (which is the SP from the previous frame), or set + that base to "NULL". */ + base = info->base; + if (base == STACK_START || base == 0) + return; - addr = read_memory_unsigned_integer (info->saved_regs[FP_REGNUM], - register_size (current_gdbarch, FP_REGNUM)); - if (addr == 0) + /* Check that we're not going round in circles with the same frame + ID (but avoid applying the test to sentinel frames which do go + round in circles). Can't use frame_id_eq() as that doesn't yet + compare the frame's PC value. */ + if (frame_relative_level (next_frame) >= 0 + && get_frame_type (next_frame) != DUMMY_FRAME + && get_frame_id (next_frame).pc == pc + && get_frame_id (next_frame).base == base) return; - id->base = d10v_make_daddr (addr); - id->pc = info->return_pc; + this_id->base = base; + this_id->pc = pc; } static void -saved_regs_unwinder (struct frame_info *frame, - CORE_ADDR *saved_regs, +saved_regs_unwinder (struct frame_info *next_frame, + CORE_ADDR *this_saved_regs, int 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 (this_saved_regs[regnum] != 0) { if (regnum == SP_REGNUM) { @@ -1519,7 +1516,7 @@ saved_regs_unwinder (struct frame_info *frame, *realnump = -1; if (bufferp != NULL) store_address (bufferp, register_size (current_gdbarch, regnum), - saved_regs[regnum]); + this_saved_regs[regnum]); } else { @@ -1527,12 +1524,12 @@ saved_regs_unwinder (struct frame_info *frame, a local copy of its value. */ *optimizedp = 0; *lvalp = lval_memory; - *addrp = saved_regs[regnum]; + *addrp = this_saved_regs[regnum]; *realnump = -1; if (bufferp != NULL) { /* Read the value in from memory. */ - read_memory (saved_regs[regnum], bufferp, + read_memory (this_saved_regs[regnum], bufferp, register_size (current_gdbarch, regnum)); } } @@ -1543,38 +1540,39 @@ 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, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); } static void -d10v_frame_register_unwind (struct frame_info *frame, - void **cache, - int 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); +d10v_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct d10v_unwind_cache *info + = d10v_frame_unwind_cache (next_frame, this_prologue_cache); if (regnum == PC_REGNUM) { /* The call instruction saves the caller's PC in LR. The function prologue of the callee may then save the LR on the stack. Find that possibly saved LR value and return it. */ - saved_regs_unwinder (frame, info->saved_regs, LR_REGNUM, optimizedp, + saved_regs_unwinder (next_frame, info->saved_regs, LR_REGNUM, optimizedp, lvalp, addrp, realnump, bufferp); } else { - saved_regs_unwinder (frame, info->saved_regs, regnum, optimizedp, + saved_regs_unwinder (next_frame, info->saved_regs, regnum, optimizedp, lvalp, addrp, realnump, bufferp); } } static struct frame_unwind d10v_frame_unwind = { - d10v_frame_id_unwind, - d10v_frame_register_unwind + d10v_frame_this_id, + d10v_frame_prev_register }; const struct frame_unwind * diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index bf4a31c..58ce8ba 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -30,6 +30,10 @@ #include "gdb_assert.h" #include "frame-unwind.h" +static void dummy_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id); + /* Dummy frame. This saves the processor state just prior to setting up the inferior function call. Older targets save the registers on the target stack (but that really slows down function calls). */ @@ -104,14 +108,6 @@ find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) return NULL; } -struct dummy_frame * -cached_find_dummy_frame (struct frame_info *frame, void **cache) -{ - if ((*cache) == NULL) - (*cache) = find_dummy_frame (get_frame_pc (frame), get_frame_base (frame)); - return (*cache); -} - struct regcache * generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp) { @@ -313,12 +309,19 @@ 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, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, void *bufferp) +dummy_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimized, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnum, void *bufferp) { - struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache); + struct dummy_frame *dummy; + struct frame_id id; + + /* Call the ID method which, if at all possible, will set the + prologue cache. */ + dummy_frame_this_id (next_frame, this_prologue_cache, &id); + dummy = (*this_prologue_cache); gdb_assert (dummy != NULL); /* Describe the register's location. Generic dummy frames always @@ -339,28 +342,77 @@ dummy_frame_register_unwind (struct frame_info *frame, void **cache, } } -/* Assuming that FRAME is a dummy, return the ID of the calling frame - (the frame that the dummy has the saved state of). */ +/* Assuming that THIS frame is a dummy (remember, the NEXT and not + THIS frame is passed in), return the ID of THIS frame. That ID is + determined by examining the NEXT frame's unwound registers using + the method unwind_dummy_id(). As a side effect, THIS dummy frame's + dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */ static void -dummy_frame_id_unwind (struct frame_info *frame, - void **cache, - struct frame_id *id) +dummy_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *this_id) { - struct dummy_frame *dummy = cached_find_dummy_frame (frame, 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; + struct dummy_frame *dummy = (*this_prologue_cache); + if (dummy != NULL) + (*this_id) = dummy->id; + /* When unwinding a normal frame, the stack structure is determined + by analyzing the frame's function's code (be it using brute force + prologue analysis, or the dwarf2 CFI). In the case of a dummy + frame, that simply isn't possible. The The PC is either the + program entry point, or some random address on the stack. Trying + to use that PC to apply standard frame ID unwind techniques is + just asking for trouble. */ + if (gdbarch_unwind_dummy_id_p (current_gdbarch)) + { + /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS, + previously saved the dummy frame's ID. Things only work if + the two return the same value. */ + gdb_assert (SAVE_DUMMY_FRAME_TOS_P ()); + /* Use an architecture specific method to extract the prev's + dummy ID from the next frame. Note that this method uses + frame_register_unwind to obtain the register values needed to + determine the dummy frame's ID. */ + (*this_id) = gdbarch_unwind_dummy_id (current_gdbarch, next_frame); + } + else if (frame_relative_level (next_frame) < 0) + { + /* We're unwinding a sentinel frame, the PC of which is pointing + at a stack dummy. Fake up the dummy frame's ID using the + same sequence as is found a traditional unwinder. Once all + architectures supply the unwind_dummy_id method, this code + can go away. */ + (*this_id).base = read_fp (); + (*this_id).pc = read_pc (); + } + else if (legacy_frame_p (current_gdbarch) + && get_prev_frame (next_frame)) + { + /* Things are looking seriously grim! Assume that the legacy + get_prev_frame code has already created THIS frame and linked + it in to the frame chain (a pretty bold assumption), extract + the ID from THIS base / pc. */ + (*this_id).base = get_frame_base (get_prev_frame (next_frame)); + (*this_id).pc = get_frame_pc (get_prev_frame (next_frame)); + } else - (*id) = dummy->id; + { + /* Outch! We're not trying to find the innermost frame's ID yet + we're trying to unwind to a dummy. The architecture must + provide the unwind_dummy_id() method. Abandon the unwind + process but only after first warning the user. */ + internal_warning (__FILE__, __LINE__, + "Missing unwind_dummy_id architecture method"); + (*this_id) = null_frame_id; + return; + } + (*this_prologue_cache) = find_dummy_frame ((*this_id).pc, (*this_id).base); } static struct frame_unwind dummy_frame_unwind = { - dummy_frame_id_unwind, - dummy_frame_register_unwind + dummy_frame_this_id, + dummy_frame_prev_register }; const struct frame_unwind * diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c index a889f95..c72d24a 100644 --- a/gdb/frame-unwind.c +++ b/gdb/frame-unwind.c @@ -83,16 +83,19 @@ frame_unwind_find_by_pc (struct gdbarch *gdbarch, CORE_ADDR pc) int i; struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data); - /* Seriously old code. Don't even try to use this new mechanism. */ if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES) - return trad_frame_unwind; + /* Seriously old code. Don't even try to use this new mechanism. + (Note: The variable USE_GENERIC_DUMMY_FRAMES is deprecated, not + the dummy frame mechanism. All architectures should be using + generic dummy frames). */ + return legacy_saved_regs_unwind; for (i = 0; i < table->nr; i++) { const struct frame_unwind *desc = table->p[i] (pc); if (desc != NULL) return desc; } - return trad_frame_unwind; + return legacy_saved_regs_unwind; } void diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h index 5d85efe..099f9de 100644 --- a/gdb/frame-unwind.h +++ b/gdb/frame-unwind.h @@ -47,42 +47,92 @@ 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, - int *optimized, - enum lval_type * lvalp, - CORE_ADDR *addrp, - int *realnump, void *valuep); - -/* 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); +/* The following unwind functions assume a chain of frames forming the + sequence: (outer) prev <-> this <-> next (inner). All the + functions are called with called with the next frame's `struct + frame_info' and and this frame's prologue cache. + + THIS frame's register values can be obtained by unwinding NEXT + frame's registers (a recursive operation). + + THIS frame's prologue cache can be used to cache information such + as where this frame's prologue stores the previous frame's + registers. */ + +/* 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 address. + + Traditionally, THIS frame's ID was determined by examining THIS + frame's function's prologue, and identifying the register/offset + used as THIS frame's base. + + Example: An examination of THIS frame's prologue reveals that, on + entry, it saves the PC(+12), SP(+8), and R1(+4) registers + (decrementing the SP by 12). Consequently, the frame ID's base can + be determined by adding 12 to the THIS frame's stack-pointer, and + the value of THIS frame's SP can be obtained by unwinding the NEXT + frame's SP. + + THIS_PROLOGUE_CACHE can be used to share any prolog analysis data + with the other unwind methods. Memory for that cache should be + allocated using frame_obstack_zalloc(). */ + +typedef void (frame_this_id_ftype) (struct frame_info *next_frame, + void **this_prologue_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 the specified register + REGNUM in the previous frame). + + Traditionally, THIS frame's registers were unwound by examining + THIS frame's function's prologue and identifying which registers + that prolog code saved on the stack. + + Example: An examination of THIS frame's prologue reveals that, on + entry, it saves the PC(+12), SP(+8), and R1(+4) registers + (decrementing the SP by 12). Consequently, the value of the PC + register in the previous frame is found in memory at SP+12, and + THIS frame's SP can be obtained by unwinding the NEXT frame's SP. + + Why not pass in THIS_FRAME? By passing in NEXT frame and THIS + cache, the supplied parameters are consistent with the sibling + function THIS_ID. + + Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''? + Won't the call frame_register (THIS_FRAME) be faster? Well, + ignoring the possability that the previous frame does not yet + exist, the ``frame_register (FRAME)'' function is expanded to + ``frame_register_unwind (get_next_frame (FRAME)'' and hence that + call will expand to ``frame_register_unwind (get_next_frame + (get_prev_frame (NEXT_FRAME)))''. Might as well call + ``frame_register_unwind (NEXT_FRAME)'' directly. + + THIS_PROLOGUE_CACHE can be used to share any prolog analysis data + with the other unwind methods. Memory for that cache should be + allocated using frame_obstack_zalloc(). */ + +typedef void (frame_prev_register_ftype) (struct frame_info *next_frame, + void **this_prologue_cache, + int prev_regnum, + int *optimized, + enum lval_type * lvalp, + CORE_ADDR *addrp, + int *realnump, void *valuep); struct frame_unwind { /* Should the frame's type go here? */ /* Should an attribute indicating the frame's address-in-block go here? */ - frame_unwind_id_ftype *id; - frame_unwind_reg_ftype *reg; + frame_this_id_ftype *this_id; + frame_prev_register_ftype *prev_register; }; #endif diff --git a/gdb/frame.c b/gdb/frame.c index 267d484..002a306 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -247,9 +247,32 @@ frame_register_unwind (struct frame_info *frame, int regnum, detected the problem before calling here. */ gdb_assert (frame != NULL); - /* Ask this frame to unwind its register. */ - frame->unwind->reg (frame, &frame->unwind_cache, regnum, - optimizedp, lvalp, addrp, realnump, bufferp); +#if 0 + /* Save each register's value and location, as it is read in, in a + frame based cache. For moment leave this disabled. Plenty of + other things to worry about first. */ + if (regs == NULL) + { + int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) + * sizeof (void *)); + regs = frame_obstack_zalloc (sizeof_cache); + (*this_prologue_cache) = regs; + } + if (regs[regnum] == NULL) + { + regs[regnum] + = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum)); + read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum], + REGISTER_RAW_SIZE (regnum)); + } +#endif + + /* Ask this frame to unwind its register. See comment in + "frame-unwind.h" for why NEXT frame and this unwind cace are + passed in. */ + frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); + } void @@ -499,7 +522,7 @@ create_sentinel_frame (struct regcache *regcache) /* Explicitly initialize the sentinel frame's cache. Provide it with the underlying regcache. In the future additional information, such as the frame's thread will be added. */ - frame->unwind_cache = sentinel_frame_cache (regcache); + frame->prologue_cache = sentinel_frame_cache (regcache); /* For the moment there is only one sentinel frame implementation. */ frame->unwind = sentinel_frame_unwind; /* Link this frame back to itself. The frame is self referential @@ -656,27 +679,26 @@ select_frame (struct frame_info *fi) most frame. */ static void -frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *bufferp) +legacy_saved_regs_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) { - /* There is always a frame at this point. And THIS is the frame - we're interested in. */ + /* HACK: New code is passed the next frame and this cache. + Unfortunatly, old code expects this frame. Since this is a + backward compatibility hack, cheat by walking one level along the + prologue chain to the frame the old code expects. + + Do not try this at home. Professional driver, closed course. */ + struct frame_info *frame = next_frame->prev; + + /* There is always a frame. */ gdb_assert (frame != NULL); - /* 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))); - - /* Only (older) architectures that implement the - DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this - function. */ - gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ()); /* Load the saved_regs register cache. */ - if (get_frame_saved_regs (frame) == NULL) + if (get_frame_saved_regs (frame) == NULL + && DEPRECATED_FRAME_INIT_SAVED_REGS_P ()) DEPRECATED_FRAME_INIT_SAVED_REGS (frame); if (get_frame_saved_regs (frame) != NULL @@ -703,46 +725,25 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache, *realnump = -1; if (bufferp != NULL) { -#if 1 - /* Save each register value, as it is read in, in a - frame based cache. */ - void **regs = (*cache); - if (regs == NULL) - { - int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS) - * sizeof (void *)); - regs = frame_obstack_zalloc (sizeof_cache); - (*cache) = regs; - } - if (regs[regnum] == NULL) - { - regs[regnum] - = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum)); - read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum], - REGISTER_RAW_SIZE (regnum)); - } - memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum)); -#else /* Read the value in from memory. */ read_memory (get_frame_saved_regs (frame)[regnum], bufferp, REGISTER_RAW_SIZE (regnum)); -#endif } } return; } - /* No luck, assume this and the next frame have the same register - value. Pass the request down the frame chain to the next frame. - Hopefully that will find the register's location, either in a - register or in memory. */ - frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, - bufferp); + /* No luck. Assume this and the next frame have the same register + value. Pass the unwind request down the frame chain to the next + frame. Hopefully that frame will find the register's location. */ + frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp, + realnump, bufferp); } static void -frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, - struct frame_id *id) +legacy_saved_regs_this_id (struct frame_info *next_frame, + void **this_prologue_cache, + struct frame_id *id) { int fromleaf; CORE_ADDR base; @@ -801,11 +802,11 @@ frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache, id->base = base; } -const struct frame_unwind trad_frame_unwinder = { - frame_saved_regs_id_unwind, - frame_saved_regs_register_unwind +const struct frame_unwind legacy_saved_regs_unwinder = { + legacy_saved_regs_this_id, + legacy_saved_regs_prev_register }; -const struct frame_unwind *trad_frame_unwind = &trad_frame_unwinder; +const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinder; /* Function: get_saved_register @@ -1327,10 +1328,7 @@ get_prev_frame (struct frame_info *this_frame) the legacy get_prev_frame method. Just don't try to unwind a sentinel frame using that method - it doesn't work. All sentinal frames use the new unwind code. */ - if ((DEPRECATED_INIT_FRAME_PC_P () - || DEPRECATED_INIT_FRAME_PC_FIRST_P () - || DEPRECATED_INIT_EXTRA_FRAME_INFO_P () - || FRAME_CHAIN_P ()) + if (legacy_frame_p (current_gdbarch) && this_frame->level >= 0) { prev_frame = legacy_get_prev_frame (this_frame); @@ -1434,12 +1432,23 @@ get_prev_frame (struct frame_info *this_frame) break; case NORMAL_FRAME: case SIGTRAMP_FRAME: - /* FIXME: cagney/2003-03-04: The below call isn't right. It - should instead be doing something like "prev_frame -> unwind - -> id (this_frame, & prev_frame -> unwind_cache, & prev_frame - -> id)" but that requires more extensive (pending) changes. */ - this_frame->unwind->id (this_frame, &this_frame->unwind_cache, - &prev_frame->id); + /* The callee expects to be invoked with: + + this->unwind->this_id (this->next, &this->cache, &this->id); + + The below is carefully shifted one frame `to the left' so + that both the unwind->this_id and unwind->prev_register + methods are consistently invoked with NEXT_FRAME and + THIS_PROLOGUE_CACHE. + + Also note that, while the PC for this new previous frame was + unwound first (see above), the below is the first call that + [potentially] requires analysis of the new previous frame's + prologue. Consequently, it is this call, that typically ends + up initializing the previous frame's prologue cache. */ + prev_frame->unwind->this_id (this_frame, + &prev_frame->prologue_cache, + &prev_frame->id); /* Check that the unwound ID is valid. */ if (!frame_id_p (prev_frame->id)) { @@ -1696,6 +1705,15 @@ deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs, return frame; } +int +legacy_frame_p (struct gdbarch *current_gdbarch) +{ + return (DEPRECATED_INIT_FRAME_PC_P () + || DEPRECATED_INIT_FRAME_PC_FIRST_P () + || DEPRECATED_INIT_EXTRA_FRAME_INFO_P () + || FRAME_CHAIN_P ()); +} + void _initialize_frame (void) { diff --git a/gdb/frame.h b/gdb/frame.h index 18c4df4..ef84d78 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -27,8 +27,9 @@ struct symtab_and_line; struct frame_unwind; struct block; -/* The traditional frame unwinder. */ -extern const struct frame_unwind *trad_frame_unwind; +/* A legacy unwinder to prop up architectures using the old style + saved regs array. */ +extern const struct frame_unwind *legacy_saved_regs_unwind; /* The frame object. */ @@ -397,9 +398,9 @@ struct frame_info related unwind data. */ struct context *context; - /* Unwind cache shared between the unwind functions - they had - better all agree as to the contents. */ - void *unwind_cache; + /* Prologue cache shared between the unwind functions. See + "frame-unwind.h" for more information. */ + void *prologue_cache; /* The frame's unwinder. */ const struct frame_unwind *unwind; @@ -701,4 +702,8 @@ extern struct context *deprecated_get_frame_context (struct frame_info *fi); extern void deprecated_set_frame_context (struct frame_info *fi, struct context *context); +/* Return non-zero if the architecture is relying on legacy frame + code. */ +extern int legacy_frame_p (struct gdbarch *gdbarch); + #endif /* !defined (FRAME_H) */ diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c index 961e030..e4060d2 100644 --- a/gdb/sentinel-frame.c +++ b/gdb/sentinel-frame.c @@ -45,13 +45,13 @@ 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, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, void *bufferp) +sentinel_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimized, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnum, void *bufferp) { - struct frame_unwind_cache *cache = *unwind_cache; + struct frame_unwind_cache *cache = *this_prologue_cache; /* Describe the register's location. A reg-frame maps all registers onto the corresponding hardware register. */ *optimized = 0; @@ -71,22 +71,20 @@ sentinel_frame_register_unwind (struct frame_info *frame, } void -sentinel_frame_id_unwind (struct frame_info *frame, - void **cache, - struct frame_id *id) +sentinel_frame_this_id (struct frame_info *next_frame, + void **this_prologue_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 (); + /* The sentinel frame is used as a starting point for creating the + previous (inner most) frame. That frame's THIS_ID method will be + called to determine the inner most frame's ID. Not this one. */ + internal_error (__FILE__, __LINE__, "sentinel_frame_this_id called"); } const struct frame_unwind sentinel_frame_unwinder = { - sentinel_frame_id_unwind, - sentinel_frame_register_unwind + sentinel_frame_this_id, + sentinel_frame_prev_register }; const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder; |