aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
diff options
context:
space:
mode:
authorAndrew Cagney <cagney@redhat.com>2003-03-14 20:34:14 +0000
committerAndrew Cagney <cagney@redhat.com>2003-03-14 20:34:14 +0000
commit055bb976b5ce73d1fa2fc0d2aba65ac158abe60b (patch)
tree8e199081a38dcad321b4dc9d8e1d17db1693cc49 /gdb/frame.c
parentce5b542e3b4f838716bc7be588cabb8db9481079 (diff)
downloadfsf-binutils-gdb-055bb976b5ce73d1fa2fc0d2aba65ac158abe60b.zip
fsf-binutils-gdb-055bb976b5ce73d1fa2fc0d2aba65ac158abe60b.tar.gz
fsf-binutils-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.c215
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