CC_UNAVAILABLE
};
+enum class frame_id_status
+{
+ /* Frame id is not computed. */
+ NOT_COMPUTED = 0,
+
+ /* Frame id is being computed (compute_frame_id is active). */
+ COMPUTING,
+
+ /* Frame id has been computed. */
+ COMPUTED,
+};
+
/* We keep a cache of stack frames, each of which is a "struct
frame_info". The innermost one gets allocated (in
wait_for_inferior) each time the inferior stops; sentinel_frame
/* This frame's ID. */
struct
{
- bool p;
+ frame_id_status p;
struct frame_id value;
} this_id;
fprintf_unfiltered (file, "stack=<unavailable>");
else if (id.stack_status == FID_STACK_SENTINEL)
fprintf_unfiltered (file, "stack=<sentinel>");
+ else if (id.stack_status == FID_STACK_OUTER)
+ fprintf_unfiltered (file, "stack=<outer>");
else
fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr));
+
fprintf_unfiltered (file, ",");
fprint_field (file, "code", id.code_addr_p, id.code_addr);
fprintf_unfiltered (file, "<NULL frame>");
return;
}
+
fprintf_unfiltered (file, "{");
fprintf_unfiltered (file, "level=%d", fi->level);
fprintf_unfiltered (file, ",");
+
fprintf_unfiltered (file, "type=");
if (fi->unwind != NULL)
fprint_frame_type (file, fi->unwind->type);
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
+
fprintf_unfiltered (file, "unwind=");
if (fi->unwind != NULL)
gdb_print_host_address (fi->unwind, file);
else
fprintf_unfiltered (file, "<unknown>");
fprintf_unfiltered (file, ",");
+
fprintf_unfiltered (file, "pc=");
if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN)
fprintf_unfiltered (file, "<unknown>");
else if (fi->next->prev_pc.status == CC_UNAVAILABLE)
val_print_unavailable (file);
fprintf_unfiltered (file, ",");
+
fprintf_unfiltered (file, "id=");
- if (fi->this_id.p)
- fprint_frame_id (file, fi->this_id.value);
+ if (fi->this_id.p == frame_id_status::NOT_COMPUTED)
+ fprintf_unfiltered (file, "<not computed>");
+ else if (fi->this_id.p == frame_id_status::COMPUTING)
+ fprintf_unfiltered (file, "<computing>");
else
- fprintf_unfiltered (file, "<unknown>");
+ fprint_frame_id (file, fi->this_id.value);
fprintf_unfiltered (file, ",");
+
fprintf_unfiltered (file, "func=");
if (fi->next != NULL && fi->next->prev_func.status == CC_VALUE)
fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_func.addr));
static void
compute_frame_id (struct frame_info *fi)
{
- gdb_assert (!fi->this_id.p);
+ gdb_assert (fi->this_id.p == frame_id_status::NOT_COMPUTED);
- if (frame_debug)
- fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
- fi->level);
- /* Find the unwinder. */
- if (fi->unwind == NULL)
- 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 = true;
- if (frame_debug)
+ unsigned int entry_generation = get_frame_cache_generation ();
+
+ try
{
- fprintf_unfiltered (gdb_stdlog, "-> ");
- fprint_frame_id (gdb_stdlog, fi->this_id.value);
- fprintf_unfiltered (gdb_stdlog, " }\n");
+ /* Mark this frame's id as "being computed. */
+ fi->this_id.p = frame_id_status::COMPUTING;
+
+ if (frame_debug)
+ fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
+ fi->level);
+
+ /* Find the unwinder. */
+ if (fi->unwind == NULL)
+ 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));
+
+ /* Mark this frame's id as "computed". */
+ fi->this_id.p = frame_id_status::COMPUTED;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "-> ");
+ fprint_frame_id (gdb_stdlog, fi->this_id.value);
+ fprintf_unfiltered (gdb_stdlog, " }\n");
+ }
+ }
+ catch (const gdb_exception &ex)
+ {
+ /* On error, revert the frame id status to not computed. If the frame
+ cache generation changed, the frame object doesn't exist anymore, so
+ don't touch it. */
+ if (get_frame_cache_generation () == entry_generation)
+ fi->this_id.p = frame_id_status::NOT_COMPUTED;
+
+ throw;
}
}
if (fi == NULL)
return null_frame_id;
- if (!fi->this_id.p)
+ /* It's always invalid to try to get a frame's id while it is being
+ computed. */
+ gdb_assert (fi->this_id.p != frame_id_status::COMPUTING);
+
+ if (fi->this_id.p == frame_id_status::NOT_COMPUTED)
{
/* If we haven't computed the frame id yet, then it must be that
this is the current frame. Compute it now, and stash the
const struct frame_id null_frame_id = { 0 }; /* All zeros. */
const struct frame_id sentinel_frame_id = { 0, 0, 0, FID_STACK_SENTINEL, 0, 1, 0 };
-const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 };
+const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_OUTER, 0, 1, 0 };
struct frame_id
frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
/* The frame is valid iff it has a valid stack address. */
bool p = l.stack_status != FID_STACK_INVALID;
- /* outer_frame_id is also valid. */
- if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0)
- p = true;
-
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
{
bool eq;
- if (l.stack_status == FID_STACK_INVALID && l.special_addr_p
- && r.stack_status == FID_STACK_INVALID && 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 = true;
- else if (l.stack_status == FID_STACK_INVALID
- || r.stack_status == FID_STACK_INVALID)
+ if (l.stack_status == FID_STACK_INVALID
+ || r.stack_status == FID_STACK_INVALID)
/* 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 = false;
if (value_optimized_out (value))
{
fprintf_unfiltered (gdb_stdlog, " ");
- val_print_optimized_out (value, gdb_stdlog);
+ val_print_not_saved (gdb_stdlog);
}
else
{
(the unwound PC is the same as the pc), so make it so. */
frame->next = frame;
/* The sentinel frame has a special ID. */
- frame->this_id.p = true;
+ frame->this_id.p = frame_id_status::COMPUTED;
frame->this_id.value = sentinel_frame_id;
if (frame_debug)
{
based on the PC. */
frame_unwind_find_by_frame (fi, &fi->prologue_cache);
- fi->this_id.p = true;
+ fi->this_id.p = frame_id_status::COMPUTED;
fi->this_id.value = frame_id_build (addr, pc);
if (frame_debug)
gdb_assert (!frame->prev_p);
/* The sniffer should not check the frame's ID; that's circular. */
- gdb_assert (!frame->this_id.p);
+ gdb_assert (frame->this_id.p != frame_id_status::COMPUTED);
/* Clear cached fields dependent on the unwinder.