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:
Andrew Cagney
2003-03-14 20:34:14 +00:00
parent ce5b542e3b
commit 055bb976b5
2 changed files with 161 additions and 63 deletions

View File

@ -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