* dummy-frame.h (dummy_frame_pop): Add prototype.

* dummy-frame.c: Include "observer.h".
	(dummy_frame_push): Do not check for stale frames.
	(dummy_frame_pop): New function.
	(cleanup_dummy_frames): New function.
	(_initialize_dummy_frame): Install it as inferior_created observer.

	* frame.h (struct frame_id): Update comments.
	(frame_id_inner): Remove prototype.
	* frame.c (frame_id_inner): Make static.  Add comments.
	(frame_find_by_id): Update frame_id_inner safety net check to avoid
	false positives for targets using non-contiguous stack ranges.
	(get_prev_frame_1): Update frame_id_inner safety net check.
	(frame_pop): Call dummy_frame_pop when popping a dummy frame.

	* stack.c (return_command): Directly pop the selected frame.
	* infrun.c (handle_inferior_event): Remove dead code.
	* i386-tdep.c (i386_push_dummy_call): Update comment.
This commit is contained in:
Ulrich Weigand
2008-08-26 17:40:25 +00:00
parent 879d1e6b46
commit a45ae3ed06
8 changed files with 124 additions and 109 deletions

View File

@ -368,7 +368,33 @@ frame_id_eq (struct frame_id l, struct frame_id r)
return eq;
}
int
/* Safety net to check whether frame ID L should be inner to
frame ID R, according to their stack addresses.
This method cannot be used to compare arbitrary frames, as the
ranges of valid stack addresses may be discontiguous (e.g. due
to sigaltstack).
However, it can be used as safety net to discover invalid frame
IDs in certain circumstances.
* If frame NEXT is the immediate inner frame to THIS, and NEXT
is a NORMAL frame, then the stack address of NEXT must be
inner-than-or-equal to the stack address of THIS.
Therefore, if frame_id_inner (THIS, NEXT) holds, some unwind
error has occurred.
* If frame NEXT is the immediate inner frame to THIS, and NEXT
is a NORMAL frame, and NEXT and THIS have different stack
addresses, no other frame in the frame chain may have a stack
address in between.
Therefore, if frame_id_inner (TEST, THIS) holds, but
frame_id_inner (TEST, NEXT) does not hold, TEST cannot refer
to a valid frame in the frame chain. */
static int
frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
{
int inner;
@ -395,28 +421,34 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
struct frame_info *
frame_find_by_id (struct frame_id id)
{
struct frame_info *frame;
struct frame_info *frame, *prev_frame;
/* ZERO denotes the null frame, let the caller decide what to do
about it. Should it instead return get_current_frame()? */
if (!frame_id_p (id))
return NULL;
for (frame = get_current_frame ();
frame != NULL;
frame = get_prev_frame (frame))
for (frame = get_current_frame (); ; frame = prev_frame)
{
struct frame_id this = get_frame_id (frame);
if (frame_id_eq (id, this))
/* An exact match. */
return frame;
if (frame_id_inner (get_frame_arch (frame), id, this))
/* Gone to far. */
prev_frame = get_prev_frame (frame);
if (!prev_frame)
return NULL;
/* As a safety net to avoid unnecessary backtracing while trying
to find an invalid ID, we check for a common situation where
we can detect from comparing stack addresses that no other
frame in the current frame chain can have this ID. See the
comment at frame_id_inner for details. */
if (get_frame_type (frame) == NORMAL_FRAME
&& !frame_id_inner (get_frame_arch (frame), id, this)
&& frame_id_inner (get_frame_arch (prev_frame), id,
get_frame_id (prev_frame)))
return NULL;
/* Either we're not yet gone far enough out along the frame
chain (inner(this,id)), or we're comparing frameless functions
(same .base, different .func, no test available). Struggle
on until we've definitly gone to far. */
}
return NULL;
}
@ -517,6 +549,11 @@ frame_pop (struct frame_info *this_frame)
scratch = frame_save_as_regcache (prev_frame);
cleanups = make_cleanup_regcache_xfree (scratch);
/* If we are popping a dummy frame, clean up the associated
data as well. */
if (get_frame_type (this_frame) == DUMMY_FRAME)
dummy_frame_pop (get_frame_id (this_frame));
/* FIXME: cagney/2003-03-16: It should be possible to tell the
target's register cache that it is about to be hit with a burst
register transfer and that the sequence of register writes should
@ -1207,11 +1244,10 @@ get_prev_frame_1 (struct frame_info *this_frame)
/* Check that this frame's ID isn't inner to (younger, below, next)
the next frame. This happens when a frame unwind goes backwards.
Exclude signal trampolines (due to sigaltstack the frame ID can
go backwards) and sentinel frames (the test is meaningless). */
if (this_frame->next->level >= 0
&& this_frame->next->unwind->type != SIGTRAMP_FRAME
&& frame_id_inner (get_frame_arch (this_frame), this_id,
This check is valid only if the next frame is NORMAL. See the
comment at frame_id_inner for details. */
if (this_frame->next->unwind->type == NORMAL_FRAME
&& frame_id_inner (get_frame_arch (this_frame->next), this_id,
get_frame_id (this_frame->next)))
{
if (frame_debug)