+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
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
{
+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
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
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)
{
}
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,
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=");
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;
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)
{
/* 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;
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
if (info)
*this_id = frame_id_build (info->base, get_frame_func (this_frame));
- else
- *this_id = null_frame_id;
}
static struct value *
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
{
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,
{
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;
}
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;
}
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;
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
if (cache != NULL)
(*this_id) = frame_id_build (cache->base, cache->func_addr);
- else
- (*this_id) = null_frame_id;
}
struct value *
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);