diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-03-17 14:23:50 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-03-17 14:23:50 +0000 |
commit | 6dc42492b62e85e892cb3a0ec4732d4b81f79b87 (patch) | |
tree | c6532c44bc4acf08219f101ad924c4e6cb2092b7 /gdb/dummy-frame.c | |
parent | 112290abe5a8587193c29b2f9b4671fd10d260df (diff) | |
download | gdb-6dc42492b62e85e892cb3a0ec4732d4b81f79b87.zip gdb-6dc42492b62e85e892cb3a0ec4732d4b81f79b87.tar.gz gdb-6dc42492b62e85e892cb3a0ec4732d4b81f79b87.tar.bz2 |
2003-03-17 Andrew Cagney <cagney@redhat.com>
Fix frame off-by-one bug.
* frame-unwind.h (frame_this_id_ftype): Replace
frame_unwind_id_ftype.
(frame_prev_register_ftype): Replace frame_unwind_reg_ftype.
(struct frame_unwind): Replace "id" with "this_id". Replace "reg"
with "prev_register".
* frame-unwind.c (frame_unwind_find_by_pc): Return
legacy_saved_regs_unwind instead of trad_frame_unwind. Update
comment.
* dummy-frame.c (cached_find_dummy_frame): Delete function.
(dummy_frame_this_id): Replace dummy_frame_id_unwind.
(dummy_frame_prev_register): Replace dummy_frame_register_unwind.
(dummy_frame_unwind): Update.
* 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.h (legacy_saved_regs_unwind): Replace trad_frame_unwind.
(struct frame_info): Rename "unwind_cache" to "prologue_cache".
* frame.c (create_sentinel_frame): Update. Initialize
"prologue_cache" instead of "unwind_cache".
(frame_register_unwind): Call this frame's prev_register with the
next frame and this frame's prologue cache.
(get_prev_frame): Simplify. Always 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.
* 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".
Diffstat (limited to 'gdb/dummy-frame.c')
-rw-r--r-- | gdb/dummy-frame.c | 109 |
1 files changed, 82 insertions, 27 deletions
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index bf4a31c..3f7746f 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,80 @@ 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; + return; + } + /* 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 * |