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, "<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
(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.