diff options
author | Andrew Cagney <cagney@redhat.com> | 2003-03-14 20:34:14 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2003-03-14 20:34:14 +0000 |
commit | 055bb976b5ce73d1fa2fc0d2aba65ac158abe60b (patch) | |
tree | 8e199081a38dcad321b4dc9d8e1d17db1693cc49 /gdb/frame.c | |
parent | ce5b542e3b4f838716bc7be588cabb8db9481079 (diff) | |
download | gdb-055bb976b5ce73d1fa2fc0d2aba65ac158abe60b.zip gdb-055bb976b5ce73d1fa2fc0d2aba65ac158abe60b.tar.gz gdb-055bb976b5ce73d1fa2fc0d2aba65ac158abe60b.tar.bz2 |
2003-03-14 Andrew Cagney <cagney@redhat.com>
* frame.c (get_prev_frame): When a legacy frame, always call
legacy_get_prev_frame. Simplify unwind code using assumption that
the unwinder is new.
(legacy_get_prev_frame): Handle legacy sentinel frame unwind here.
(legacy_frame_p): When no gdbarch_unwind_dummy_id, or
SAVED_DUMMY_FRAME_TOS, assume a legacy frame.
Diffstat (limited to 'gdb/frame.c')
-rw-r--r-- | gdb/frame.c | 215 |
1 files changed, 152 insertions, 63 deletions
diff --git a/gdb/frame.c b/gdb/frame.c index 26e80be..cf9349d 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -992,6 +992,142 @@ legacy_get_prev_frame (struct frame_info *this_frame) struct frame_info *prev; int fromleaf; + /* Allocate the new frame but do not wire it in to the frame chain. + Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along + frame->next to pull some fancy tricks (of course such code is, by + definition, recursive). Try to prevent it. + + There is no reason to worry about memory leaks, should the + remainder of the function fail. The allocated memory will be + quickly reclaimed when the frame cache is flushed, and the `we've + been here before' check, in get_prev_frame will stop repeated + memory allocation calls. */ + prev = FRAME_OBSTACK_ZALLOC (struct frame_info); + prev->level = this_frame->level + 1; + + /* NOTE: cagney/2002-11-18: Should have been correctly setting the + frame's type here, before anything else, and not last, at the + bottom of this function. The various + DEPRECATED_INIT_EXTRA_FRAME_INFO, DEPRECATED_INIT_FRAME_PC, + DEPRECATED_INIT_FRAME_PC_FIRST and + DEPRECATED_FRAME_INIT_SAVED_REGS methods are full of work-arounds + that handle the frame not being correctly set from the start. + Unfortunatly those same work-arounds rely on the type defaulting + to NORMAL_FRAME. Ulgh! The new frame code does not have this + problem. */ + prev->type = NORMAL_FRAME; + + /* Handle sentinel frame unwind as a special case. */ + if (this_frame->level < 0) + { + /* Try to unwind the PC. If that doesn't work, assume we've reached + the oldest frame and simply return. Is there a better sentinal + value? The unwound PC value is then used to initialize the new + previous frame's type. + + Note that the pc-unwind is intentionally performed before the + frame chain. This is ok since, for old targets, both + frame_pc_unwind (nee, FRAME_SAVED_PC) and FRAME_CHAIN()) assume + THIS_FRAME's data structures have already been initialized (using + DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order + doesn't matter. + + By unwinding the PC first, it becomes possible to, in the case of + a dummy frame, avoid also unwinding the frame ID. This is + because (well ignoring the PPC) a dummy frame can be located + using THIS_FRAME's frame ID. */ + + prev->pc = frame_pc_unwind (this_frame); + if (prev->pc == 0) + { + /* The allocated PREV_FRAME will be reclaimed when the frame + obstack is next purged. */ + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "Outermost frame - unwound PC zero\n"); + return NULL; + } + prev->type = frame_type_from_pc (prev->pc); + + /* Set the unwind functions based on that identified PC. */ + prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc); + + /* Find the prev's frame's ID. */ + if (prev->type == DUMMY_FRAME + && gdbarch_unwind_dummy_id_p (current_gdbarch)) + { + /* 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. */ + /* 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. */ + prev->id = gdbarch_unwind_dummy_id (current_gdbarch, this_frame); + } + else + { + /* 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. */ + prev->id.base = read_fp (); + prev->id.pc = read_pc (); + } + + /* Check that the unwound ID is valid. */ + if (!frame_id_p (prev->id)) + { + if (frame_debug) + fprintf_unfiltered (gdb_stdlog, + "Outermost legacy sentinel frame - unwound frame ID invalid\n"); + return NULL; + } + + /* Check that the new frame isn't inner to (younger, below, + next) the old frame. If that happens the frame unwind is + going backwards. */ + /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since + that doesn't have a valid frame ID. Should instead set the + sentinel frame's frame ID to a `sentinel'. Leave it until + after the switch to storing the frame ID, instead of the + frame base, in the frame object. */ + + /* FIXME: cagney/2002-12-18: Instead of this hack, should only + store the frame ID in PREV_FRAME. Unfortunatly, some + architectures (HP/UX) still reply on EXTRA_FRAME_INFO and, + hence, still poke at the "struct frame_info" object directly. */ + prev->frame = prev->id.base; + + /* Link it in. */ + this_frame->prev = prev; + prev->next = this_frame; + + /* FIXME: cagney/2002-01-19: This call will go away. Instead of + initializing extra info, all frames will use the frame_cache + (passed to the unwind functions) to store additional frame + info. Unfortunatly legacy targets can't use + legacy_get_prev_frame() to unwind the sentinel frame and, + consequently, are forced to take this code path and rely on + the below call to DEPRECATED_INIT_EXTRA_FRAME_INFO to + initialize the inner-most frame. */ + if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) + { + DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev); + } + return prev; + } + /* This code only works on normal frames. A sentinel frame, where the level is -1, should never reach this code. */ gdb_assert (this_frame->level >= 0); @@ -1048,19 +1184,10 @@ legacy_get_prev_frame (struct frame_info *this_frame) if (address == 0) return 0; - /* Create an initially zero previous frame. */ - prev = frame_obstack_zalloc (sizeof (struct frame_info)); - - /* Link it in. */ + /* Link in the already allocated prev frame. */ this_frame->prev = prev; prev->next = this_frame; prev->frame = address; - prev->level = this_frame->level + 1; - /* FIXME: cagney/2002-11-18: Should be setting the frame's type - here, before anything else, and not last. Various INIT functions - are full of work-arounds for the frames type not being set - correctly from the word go. Ulgh! */ - prev->type = NORMAL_FRAME; /* This change should not be needed, FIXME! We should determine whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen @@ -1305,11 +1432,8 @@ get_prev_frame (struct frame_info *this_frame) } /* If any of the old frame initialization methods are around, use - 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 (legacy_frame_p (current_gdbarch) - && this_frame->level >= 0) + the legacy get_prev_frame method. */ + if (legacy_frame_p (current_gdbarch)) { prev_frame = legacy_get_prev_frame (this_frame); if (frame_debug && prev_frame == NULL) @@ -1376,39 +1500,16 @@ get_prev_frame (struct frame_info *this_frame) 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. */ - prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, - this_frame); - } - else if (this_frame->level < 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. */ - prev_frame->id.base = read_fp (); - prev_frame->id.pc = read_pc (); - } - else - { - /* Outch! We're not on the innermost frame 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"); - return NULL; - } + gdb_assert (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. */ + prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, this_frame); break; case NORMAL_FRAME: case SIGTRAMP_FRAME: @@ -1455,20 +1556,6 @@ get_prev_frame (struct frame_info *this_frame) this_frame->prev = prev_frame; prev_frame->next = this_frame; - /* FIXME: cagney/2002-01-19: This call will go away. Instead of - initializing extra info, all frames will use the frame_cache - (passed to the unwind functions) to store additional frame info. - Unfortunatly legacy targets can't use legacy_get_prev_frame() to - unwind the sentinel frame and, consequently, are forced to take - this code path and rely on the below call to - DEPRECATED_INIT_EXTRA_FRAME_INFO to initialize the inner-most - frame. */ - if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()) - { - gdb_assert (prev_frame->level == 0); - DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame); - } - return prev_frame; } @@ -1680,7 +1767,9 @@ 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 ()); + || FRAME_CHAIN_P () + || !gdbarch_unwind_dummy_id_p (current_gdbarch) + || !SAVE_DUMMY_FRAME_TOS_P ()); } void |