forked from Imagelibrary/binutils-gdb
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:
@@ -1,3 +1,12 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
2003-03-14 Andrew Cagney <cagney@redhat.com>
|
2003-03-14 Andrew Cagney <cagney@redhat.com>
|
||||||
|
|
||||||
* frame.c (get_saved_register): Delete function.
|
* frame.c (get_saved_register): Delete function.
|
||||||
|
|||||||
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;
|
struct frame_info *prev;
|
||||||
int fromleaf;
|
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
|
/* This code only works on normal frames. A sentinel frame, where
|
||||||
the level is -1, should never reach this code. */
|
the level is -1, should never reach this code. */
|
||||||
gdb_assert (this_frame->level >= 0);
|
gdb_assert (this_frame->level >= 0);
|
||||||
@@ -1048,19 +1184,10 @@ legacy_get_prev_frame (struct frame_info *this_frame)
|
|||||||
if (address == 0)
|
if (address == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Create an initially zero previous frame. */
|
/* Link in the already allocated prev frame. */
|
||||||
prev = frame_obstack_zalloc (sizeof (struct frame_info));
|
|
||||||
|
|
||||||
/* Link it in. */
|
|
||||||
this_frame->prev = prev;
|
this_frame->prev = prev;
|
||||||
prev->next = this_frame;
|
prev->next = this_frame;
|
||||||
prev->frame = address;
|
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
|
/* This change should not be needed, FIXME! We should determine
|
||||||
whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
|
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
|
/* If any of the old frame initialization methods are around, use
|
||||||
the legacy get_prev_frame method. Just don't try to unwind a
|
the legacy get_prev_frame method. */
|
||||||
sentinel frame using that method - it doesn't work. All sentinal
|
if (legacy_frame_p (current_gdbarch))
|
||||||
frames use the new unwind code. */
|
|
||||||
if (legacy_frame_p (current_gdbarch)
|
|
||||||
&& this_frame->level >= 0)
|
|
||||||
{
|
{
|
||||||
prev_frame = legacy_get_prev_frame (this_frame);
|
prev_frame = legacy_get_prev_frame (this_frame);
|
||||||
if (frame_debug && prev_frame == NULL)
|
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
|
address on the stack. Trying to use that PC to apply
|
||||||
standard frame ID unwind techniques is just asking for
|
standard frame ID unwind techniques is just asking for
|
||||||
trouble. */
|
trouble. */
|
||||||
if (gdbarch_unwind_dummy_id_p (current_gdbarch))
|
gdb_assert (gdbarch_unwind_dummy_id_p (current_gdbarch));
|
||||||
{
|
/* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
|
||||||
/* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
|
previously saved the dummy frame's ID. Things only work if
|
||||||
previously saved the dummy frame's ID. Things only work
|
the two return the same value. */
|
||||||
if the two return the same value. */
|
gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
|
||||||
gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
|
/* Use an architecture specific method to extract the prev's
|
||||||
/* Use an architecture specific method to extract the prev's
|
dummy ID from the next frame. Note that this method uses
|
||||||
dummy ID from the next frame. Note that this method uses
|
frame_register_unwind to obtain the register values needed to
|
||||||
frame_register_unwind to obtain the register values
|
determine the dummy frame's ID. */
|
||||||
needed to determine the dummy frame's ID. */
|
prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, this_frame);
|
||||||
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;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case NORMAL_FRAME:
|
case NORMAL_FRAME:
|
||||||
case SIGTRAMP_FRAME:
|
case SIGTRAMP_FRAME:
|
||||||
@@ -1455,20 +1556,6 @@ get_prev_frame (struct frame_info *this_frame)
|
|||||||
this_frame->prev = prev_frame;
|
this_frame->prev = prev_frame;
|
||||||
prev_frame->next = this_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;
|
return prev_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1680,7 +1767,9 @@ legacy_frame_p (struct gdbarch *current_gdbarch)
|
|||||||
return (DEPRECATED_INIT_FRAME_PC_P ()
|
return (DEPRECATED_INIT_FRAME_PC_P ()
|
||||||
|| DEPRECATED_INIT_FRAME_PC_FIRST_P ()
|
|| DEPRECATED_INIT_FRAME_PC_FIRST_P ()
|
||||||
|| DEPRECATED_INIT_EXTRA_FRAME_INFO_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
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user