* frame.c (get_frame_id): Default to outer_frame_id if the this_id
        method does not supply an ID.  Assert that the result is not
        null_frame_id.
        (outer_frame_id): New.
        (frame_id_p): Accept outer_frame_id.
        (frame_id_eq): Allow outer_frame_id to be equal to itself.
        (frame_find_by_id): Revert previous local workarounds.
        (get_prev_frame_1): Adjust end-of-stack check to test outer_frame_id.
        * frame.h (null_frame_id, frame_id_p): Update comments.
        (outer_frame_id): Declare.
        * infrun.c (handle_inferior_event): Do not treat all steps from the
        outermost frame as subroutine calls.

        * libunwind-frame.c (libunwind_frame_this_id): Do not clear THIS_ID.
        * hppa-tdep.c (hppa_stub_frame_this_id): Likewise.
        * ia64-tdep.c (ia64_frame_this_id): Likewise.
        (ia64_libunwind_frame_this_id, ia64_libunwind_sigtramp_frame_this_id):
        Use outer_frame_id instead of null_frame_id.
        * amd64obsd-tdep.c (amd64obsd_trapframe_cache): Use outer_frame_id.
        * i386obsd-tdep.c (i386obsd_trapframe_cache): Likewise.
        * inline-frame.c (inline_frame_this_id): Refuse outer_frame_id.
        * thread.c (restore_selected_frame): Update comment and remove
        frame_id_p check.

        gdb/doc/
        * gdbint.texinfo (Unwinding the Frame ID): Reference outer_frame_id.
This commit is contained in:
Joel Brobecker 2009-09-13 16:28:29 +00:00
parent 97b11f4094
commit 005ca36a8b
13 changed files with 93 additions and 30 deletions

View File

@ -1,3 +1,29 @@
2009-09-13 Daniel Jacobowitz <dan@codesourcery.com>
* frame.c (get_frame_id): Default to outer_frame_id if the this_id
method does not supply an ID. Assert that the result is not
null_frame_id.
(outer_frame_id): New.
(frame_id_p): Accept outer_frame_id.
(frame_id_eq): Allow outer_frame_id to be equal to itself.
(frame_find_by_id): Revert previous local workarounds.
(get_prev_frame_1): Adjust end-of-stack check to test outer_frame_id.
* frame.h (null_frame_id, frame_id_p): Update comments.
(outer_frame_id): Declare.
* infrun.c (handle_inferior_event): Do not treat all steps from the
outermost frame as subroutine calls.
* libunwind-frame.c (libunwind_frame_this_id): Do not clear THIS_ID.
* hppa-tdep.c (hppa_stub_frame_this_id): Likewise.
* ia64-tdep.c (ia64_frame_this_id): Likewise.
(ia64_libunwind_frame_this_id, ia64_libunwind_sigtramp_frame_this_id):
Use outer_frame_id instead of null_frame_id.
* amd64obsd-tdep.c (amd64obsd_trapframe_cache): Use outer_frame_id.
* i386obsd-tdep.c (i386obsd_trapframe_cache): Likewise.
* inline-frame.c (inline_frame_this_id): Refuse outer_frame_id.
* thread.c (restore_selected_frame): Update comment and remove
frame_id_p check.
2009-09-11 Doug Evans <dje@google.com>
* dwarf2expr.c (execute_stack_op, case DW_OP_piece): Delete unused

View File

@ -380,7 +380,7 @@ amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
{
/* Trap from user space; terminate backtrace. */
trad_frame_set_id (cache, null_frame_id);
trad_frame_set_id (cache, outer_frame_id);
}
else
{

View File

@ -1,3 +1,7 @@
2009-09-13 Daniel Jacobowitz <dan@codesourcery.com>
* gdbint.texinfo (Unwinding the Frame ID): Reference outer_frame_id.
2009-09-10 Michael Snyder <msnyder@vmware.com>
* gdb.texinfo (qSupported): Mention new ReverseContinue and

View File

@ -2042,9 +2042,17 @@ address as its caller. On some platforms, a third address is part of
the ID to further disambiguate frames---for instance, on IA-64
the separate register stack address is included in the ID.
An invalid frame ID (@code{null_frame_id}) returned from the
An invalid frame ID (@code{outer_frame_id}) returned from the
@code{this_id} method means to stop unwinding after this frame.
@code{null_frame_id} is another invalid frame ID which should be used
when there is no frame. For instance, certain breakpoints are attached
to a specific frame, and that frame is identified through its frame ID
(we use this to implement the "finish" command). Using
@code{null_frame_id} as the frame ID for a given breakpoint means
that the breakpoint is not specific to any frame. The @code{this_id}
method should never return @code{null_frame_id}.
@section Unwinding Registers
Each unwinder includes a @code{prev_register} method. This method

View File

@ -324,7 +324,10 @@ get_frame_id (struct frame_info *fi)
if (fi->unwind == NULL)
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
/* Find THIS frame's ID. */
/* Default to outermost if no ID is found. */
fi->this_id.value = outer_frame_id;
fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
gdb_assert (frame_id_p (fi->this_id.value));
fi->this_id.p = 1;
if (frame_debug)
{
@ -364,6 +367,7 @@ frame_unwind_caller_id (struct frame_info *next_frame)
}
const struct frame_id null_frame_id; /* All zeros. */
const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 };
struct frame_id
frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
@ -405,6 +409,9 @@ frame_id_p (struct frame_id l)
int p;
/* The frame is valid iff it has a valid stack address. */
p = l.stack_addr_p;
/* outer_frame_id is also valid. */
if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
p = 1;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
@ -427,7 +434,14 @@ int
frame_id_eq (struct frame_id l, struct frame_id r)
{
int eq;
if (!l.stack_addr_p || !r.stack_addr_p)
if (!l.stack_addr_p && l.special_addr_p && !r.stack_addr_p && r.special_addr_p)
/* The outermost frame marker is equal to itself. This is the
dodgy thing about outer_frame_id, since between execution steps
we might step into another function - from which we can't
unwind either. More thought required to get rid of
outer_frame_id. */
eq = 1;
else if (!l.stack_addr_p || !r.stack_addr_p)
/* Like a NaN, if either ID is invalid, the result is false.
Note that a frame ID is invalid iff it is the null frame ID. */
eq = 0;
@ -1425,7 +1439,7 @@ get_prev_frame_1 (struct frame_info *this_frame)
unwind to the prev frame. Be careful to not apply this test to
the sentinel frame. */
this_id = get_frame_id (this_frame);
if (this_frame->level >= 0 && !frame_id_p (this_id))
if (this_frame->level >= 0 && frame_id_eq (this_id, outer_frame_id))
{
if (frame_debug)
{

View File

@ -142,9 +142,14 @@ struct frame_id
/* Methods for constructing and comparing Frame IDs. */
/* For convenience. All fields are zero. */
/* For convenience. All fields are zero. This means "there is no frame". */
extern const struct frame_id null_frame_id;
/* This means "there is no frame ID, but there is a frame". It should be
replaced by best-effort frame IDs for the outermost frame, somehow.
The implementation is only special_addr_p set. */
extern const struct frame_id outer_frame_id;
/* Flag to control debugging. */
extern int frame_debug;
@ -170,7 +175,8 @@ extern struct frame_id frame_id_build_special (CORE_ADDR stack_addr,
extern struct frame_id frame_id_build_wild (CORE_ADDR stack_addr);
/* Returns non-zero when L is a valid frame (a valid frame has a
non-zero .base). */
non-zero .base). The outermost frame is valid even without an
ID. */
extern int frame_id_p (struct frame_id l);
/* Returns non-zero when L is a valid frame representing an inlined

View File

@ -2427,8 +2427,6 @@ hppa_stub_frame_this_id (struct frame_info *this_frame,
if (info)
*this_id = frame_id_build (info->base, get_frame_func (this_frame));
else
*this_id = null_frame_id;
}
static struct value *

View File

@ -376,7 +376,7 @@ i386obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
{
/* Trap from user space; terminate backtrace. */
trad_frame_set_id (cache, null_frame_id);
trad_frame_set_id (cache, outer_frame_id);
}
else
{

View File

@ -1774,9 +1774,7 @@ ia64_frame_this_id (struct frame_info *this_frame, void **this_cache,
ia64_frame_cache (this_frame, this_cache);
/* If outermost frame, mark with null frame id. */
if (cache->base == 0)
(*this_id) = null_frame_id;
else
if (cache->base != 0)
(*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
@ -2790,15 +2788,14 @@ ia64_libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache,
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct frame_id id;
struct frame_id id = outer_frame_id;
char buf[8];
CORE_ADDR bsp;
libunwind_frame_this_id (this_frame, this_cache, &id);
if (frame_id_eq (id, null_frame_id))
if (frame_id_eq (id, outer_frame_id))
{
(*this_id) = null_frame_id;
(*this_id) = outer_frame_id;
return;
}
@ -2923,13 +2920,13 @@ ia64_libunwind_sigtramp_frame_this_id (struct frame_info *this_frame,
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
char buf[8];
CORE_ADDR bsp;
struct frame_id id;
struct frame_id id = outer_frame_id;
CORE_ADDR prev_ip;
libunwind_frame_this_id (this_frame, this_cache, &id);
if (frame_id_eq (id, null_frame_id))
if (frame_id_eq (id, outer_frame_id))
{
(*this_id) = null_frame_id;
(*this_id) = outer_frame_id;
return;
}

View File

@ -3796,10 +3796,22 @@ infrun: not switching back to stepped thread, it has vanished\n");
NOTE: frame_id_eq will never report two invalid frame IDs as
being equal, so to get into this block, both the current and
previous frame must have valid frame IDs. */
/* The outer_frame_id check is a heuristic to detect stepping
through startup code. If we step over an instruction which
sets the stack pointer from an invalid value to a valid value,
we may detect that as a subroutine call from the mythical
"outermost" function. This could be fixed by marking
outermost frames as !stack_p,code_p,special_p. Then the
initial outermost frame, before sp was valid, would
have code_addr == &_start. See the commend in frame_id_eq
for more. */
if (!frame_id_eq (get_stack_frame_id (frame),
ecs->event_thread->step_stack_frame_id)
&& frame_id_eq (frame_unwind_caller_id (frame),
ecs->event_thread->step_stack_frame_id))
&& (frame_id_eq (frame_unwind_caller_id (get_current_frame ()),
ecs->event_thread->step_stack_frame_id)
&& (!frame_id_eq (ecs->event_thread->step_stack_frame_id,
outer_frame_id)
|| step_start_function != find_pc_function (stop_pc))))
{
CORE_ADDR real_stop_pc;

View File

@ -148,6 +148,10 @@ inline_frame_this_id (struct frame_info *this_frame,
frame"). This will take work. */
gdb_assert (frame_id_p (*this_id));
/* For now, require we don't match outer_frame_id either (see
comment above). */
gdb_assert (!frame_id_eq (*this_id, outer_frame_id));
/* Future work NOTE: Alexandre Oliva applied a patch to GCC 4.3
which generates DW_AT_entry_pc for inlined functions when
possible. If this attribute is available, we should use it

View File

@ -278,8 +278,6 @@ libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache,
if (cache != NULL)
(*this_id) = frame_id_build (cache->base, cache->func_addr);
else
(*this_id) = null_frame_id;
}
struct value *

View File

@ -885,15 +885,11 @@ restore_selected_frame (struct frame_id a_frame_id, int frame_level)
frame = find_relative_frame (get_current_frame (), &count);
if (count == 0
&& frame != NULL
/* Either the frame ids match, of they're both invalid. The
latter case is not failsafe, but since it's highly unlikely
/* The frame ids must match - either both valid or both outer_frame_id.
The latter case is not failsafe, but since it's highly unlikely
the search by level finds the wrong frame, it's 99.9(9)% of
the time (for all practical purposes) safe. */
&& (frame_id_eq (get_frame_id (frame), a_frame_id)
/* Note: could be better to check every frame_id
member for equality here. */
|| (!frame_id_p (get_frame_id (frame))
&& !frame_id_p (a_frame_id))))
&& frame_id_eq (get_frame_id (frame), a_frame_id))
{
/* Cool, all is fine. */
select_frame (frame);