mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-10-17 21:03:55 +08:00
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.
This commit is contained in:
215
gdb/frame.c
215
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
|
||||
|
Reference in New Issue
Block a user