mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-24 04:29:49 +00:00
* 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:
parent
879d1e6b46
commit
a45ae3ed06
@ -1,3 +1,24 @@
|
||||
2008-08-26 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2008-08-26 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* breakpoint.c (remove_breakpoint): Do not fail if unable to remove
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "command.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "gdb_string.h"
|
||||
#include "observer.h"
|
||||
|
||||
/* Dummy frame. This saves the processor state just prior to setting
|
||||
up the inferior function call. Older targets save the registers
|
||||
@ -87,26 +88,8 @@ void
|
||||
dummy_frame_push (struct regcache *caller_regcache,
|
||||
const struct frame_id *dummy_id)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_regcache_arch (caller_regcache);
|
||||
struct dummy_frame *dummy_frame;
|
||||
|
||||
/* Check to see if there are stale dummy frames, perhaps left over
|
||||
from when a longjump took us out of a function that was called by
|
||||
the debugger. */
|
||||
dummy_frame = dummy_frame_stack;
|
||||
while (dummy_frame)
|
||||
/* FIXME: cagney/2004-08-02: Should just test IDs. */
|
||||
if (frame_id_inner (gdbarch, dummy_frame->id, (*dummy_id)))
|
||||
/* Stale -- destroy! */
|
||||
{
|
||||
dummy_frame_stack = dummy_frame->next;
|
||||
regcache_xfree (dummy_frame->regcache);
|
||||
xfree (dummy_frame);
|
||||
dummy_frame = dummy_frame_stack;
|
||||
}
|
||||
else
|
||||
dummy_frame = dummy_frame->next;
|
||||
|
||||
dummy_frame = XZALLOC (struct dummy_frame);
|
||||
dummy_frame->regcache = caller_regcache;
|
||||
dummy_frame->id = (*dummy_id);
|
||||
@ -114,6 +97,47 @@ dummy_frame_push (struct regcache *caller_regcache,
|
||||
dummy_frame_stack = dummy_frame;
|
||||
}
|
||||
|
||||
/* Pop the dummy frame with ID dummy_id from the dummy-frame stack. */
|
||||
|
||||
void
|
||||
dummy_frame_pop (struct frame_id dummy_id)
|
||||
{
|
||||
struct dummy_frame **dummy_ptr;
|
||||
|
||||
for (dummy_ptr = &dummy_frame_stack;
|
||||
(*dummy_ptr) != NULL;
|
||||
dummy_ptr = &(*dummy_ptr)->next)
|
||||
{
|
||||
struct dummy_frame *dummy = *dummy_ptr;
|
||||
if (frame_id_eq (dummy->id, dummy_id))
|
||||
{
|
||||
*dummy_ptr = dummy->next;
|
||||
regcache_xfree (dummy->regcache);
|
||||
xfree (dummy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* There may be stale dummy frames, perhaps left over from when a longjump took us
|
||||
out of a function that was called by the debugger. Clean them up at least once
|
||||
whenever we start a new inferior. */
|
||||
|
||||
static void
|
||||
cleanup_dummy_frames (struct target_ops *target, int from_tty)
|
||||
{
|
||||
struct dummy_frame *dummy, *next;
|
||||
|
||||
for (dummy = dummy_frame_stack; dummy; dummy = next)
|
||||
{
|
||||
next = dummy->next;
|
||||
regcache_xfree (dummy->regcache);
|
||||
xfree (dummy);
|
||||
}
|
||||
|
||||
dummy_frame_stack = NULL;
|
||||
}
|
||||
|
||||
/* Return the dummy frame cache, it contains both the ID, and a
|
||||
pointer to the regcache. */
|
||||
struct dummy_frame_cache
|
||||
@ -258,4 +282,5 @@ _initialize_dummy_frame (void)
|
||||
_("Print the contents of the internal dummy-frame stack."),
|
||||
&maintenanceprintlist);
|
||||
|
||||
observer_attach_inferior_created (cleanup_dummy_frames);
|
||||
}
|
||||
|
@ -41,6 +41,8 @@ struct frame_id;
|
||||
extern void dummy_frame_push (struct regcache *regcache,
|
||||
const struct frame_id *dummy_id);
|
||||
|
||||
extern void dummy_frame_pop (struct frame_id dummy_id);
|
||||
|
||||
/* If the PC falls in a dummy frame, return a dummy frame
|
||||
unwinder. */
|
||||
|
||||
|
68
gdb/frame.c
68
gdb/frame.c
@ -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)
|
||||
|
25
gdb/frame.h
25
gdb/frame.h
@ -111,7 +111,7 @@ struct frame_id
|
||||
frames that do not change the stack but are still distinct and have
|
||||
some form of distinct identifier (e.g. the ia64 which uses a 2nd
|
||||
stack for registers). This field is treated as unordered - i.e. will
|
||||
not be used in frame ordering comparisons such as frame_id_inner().
|
||||
not be used in frame ordering comparisons.
|
||||
|
||||
This field is valid only if special_addr_p is true. Otherwise, this
|
||||
frame is considered to have a wildcard special address, i.e. one that
|
||||
@ -124,22 +124,7 @@ struct frame_id
|
||||
unsigned int special_addr_p : 1;
|
||||
};
|
||||
|
||||
/* Methods for constructing and comparing Frame IDs.
|
||||
|
||||
NOTE: Given stackless functions A and B, where A calls B (and hence
|
||||
B is inner-to A). The relationships: !eq(A,B); !eq(B,A);
|
||||
!inner(A,B); !inner(B,A); all hold.
|
||||
|
||||
This is because, while B is inner-to A, B is not strictly inner-to A.
|
||||
Being stackless, they have an identical .stack_addr value, and differ
|
||||
only by their unordered .code_addr and/or .special_addr values.
|
||||
|
||||
Because frame_id_inner is only used as a safety net (e.g.,
|
||||
detect a corrupt stack) the lack of strictness is not a problem.
|
||||
Code needing to determine an exact relationship between two frames
|
||||
must instead use frame_id_eq and frame_id_unwind. For instance,
|
||||
in the above, to determine that A stepped-into B, the equation
|
||||
"A.id != B.id && A.id == id_unwind (B)" can be used. */
|
||||
/* Methods for constructing and comparing Frame IDs. */
|
||||
|
||||
/* For convenience. All fields are zero. */
|
||||
extern const struct frame_id null_frame_id;
|
||||
@ -176,12 +161,6 @@ extern int frame_id_p (struct frame_id l);
|
||||
either L or R have a zero .func, then the same frame base. */
|
||||
extern int frame_id_eq (struct frame_id l, struct frame_id r);
|
||||
|
||||
/* Returns non-zero when L is strictly inner-than R (they have
|
||||
different frame .bases). Neither L, nor R can be `null'. See note
|
||||
above about frameless functions. */
|
||||
extern int frame_id_inner (struct gdbarch *gdbarch, struct frame_id l,
|
||||
struct frame_id r);
|
||||
|
||||
/* Write the internal representation of a frame ID on the specified
|
||||
stream. */
|
||||
extern void fprint_frame_id (struct ui_file *file, struct frame_id id);
|
||||
|
@ -1712,8 +1712,8 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
||||
(i386_frame_this_id, i386_sigtramp_frame_this_id,
|
||||
i386_dummy_id). It's there, since all frame unwinders for
|
||||
a given target have to agree (within a certain margin) on the
|
||||
definition of the stack address of a frame. Otherwise
|
||||
frame_id_inner() won't work correctly. Since DWARF2/GCC uses the
|
||||
definition of the stack address of a frame. Otherwise frame id
|
||||
comparison might not work correctly. Since DWARF2/GCC uses the
|
||||
stack address *before* the function call as a frame's CFA. On
|
||||
the i386, when %ebp is used as a frame pointer, the offset
|
||||
between the contents %ebp and the CFA as defined by GCC. */
|
||||
|
27
gdb/infrun.c
27
gdb/infrun.c
@ -3323,33 +3323,6 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
|
||||
tss->current_line = stop_pc_sal.line;
|
||||
tss->current_symtab = stop_pc_sal.symtab;
|
||||
|
||||
/* In the case where we just stepped out of a function into the
|
||||
middle of a line of the caller, continue stepping, but
|
||||
step_frame_id must be modified to current frame */
|
||||
#if 0
|
||||
/* NOTE: cagney/2003-10-16: I think this frame ID inner test is too
|
||||
generous. It will trigger on things like a step into a frameless
|
||||
stackless leaf function. I think the logic should instead look
|
||||
at the unwound frame ID has that should give a more robust
|
||||
indication of what happened. */
|
||||
if (step - ID == current - ID)
|
||||
still stepping in same function;
|
||||
else if (step - ID == unwind (current - ID))
|
||||
stepped into a function;
|
||||
else
|
||||
stepped out of a function;
|
||||
/* Of course this assumes that the frame ID unwind code is robust
|
||||
and we're willing to introduce frame unwind logic into this
|
||||
function. Fortunately, those days are nearly upon us. */
|
||||
#endif
|
||||
{
|
||||
struct frame_info *frame = get_current_frame ();
|
||||
struct frame_id current_frame = get_frame_id (frame);
|
||||
if (!(frame_id_inner (get_frame_arch (frame), current_frame,
|
||||
step_frame_id)))
|
||||
step_frame_id = current_frame;
|
||||
}
|
||||
|
||||
if (debug_infrun)
|
||||
fprintf_unfiltered (gdb_stdlog, "infrun: keep going\n");
|
||||
keep_going (ecs);
|
||||
|
25
gdb/stack.c
25
gdb/stack.c
@ -1844,29 +1844,8 @@ If you continue, the return value that you specified will be ignored.\n";
|
||||
error (_("Not confirmed"));
|
||||
}
|
||||
|
||||
/* NOTE: cagney/2003-01-18: Is this silly? Rather than pop each
|
||||
frame in turn, should this code just go straight to the relevant
|
||||
frame and pop that? */
|
||||
|
||||
/* First discard all frames inner-to the selected frame (making the
|
||||
selected frame current). */
|
||||
{
|
||||
struct frame_id selected_id = get_frame_id (get_selected_frame (NULL));
|
||||
while (!frame_id_eq (selected_id, get_frame_id (get_current_frame ())))
|
||||
{
|
||||
struct frame_info *frame = get_current_frame ();
|
||||
if (frame_id_inner (get_frame_arch (frame), selected_id,
|
||||
get_frame_id (frame)))
|
||||
/* Caught in the safety net, oops! We've gone way past the
|
||||
selected frame. */
|
||||
error (_("Problem while popping stack frames (corrupt stack?)"));
|
||||
frame_pop (get_current_frame ());
|
||||
}
|
||||
}
|
||||
|
||||
/* Second discard the selected frame (which is now also the current
|
||||
frame). */
|
||||
frame_pop (get_current_frame ());
|
||||
/* Discard the selected frame and all frames inner-to it. */
|
||||
frame_pop (get_selected_frame (NULL));
|
||||
|
||||
/* Store RETURN_VALUE in the just-returned register set. */
|
||||
if (return_value != NULL)
|
||||
|
Loading…
Reference in New Issue
Block a user