gdb: set frame_info_ptr::m_cached_id in the destructor
Currently frame_info_ptr caches the frame_id at construction time, see
frame_info_ptr::frame_info_ptr in frame.c. The problem with this is
that a frame's frame-id might not be known at this point.
Consider get_prev_frame_maybe_check_cycle, this calls
get_prev_frame_raw to create the previous frame, placing the result
into a frame_info_ptr PREV_FRAME. Then (for frames other than frame
0) compute_frame_id is called, however, this only computes the
frame_id for the frame_info object pointed to by the frame_info_ptr,
the cached frame_id within the frame_info_ptr itself is not updated.
What this means is that in get_prev_frame_maybe_check_cycle, the
PREV_FRAME local has no cached frame-id.
If we consider the call stack:
get_selected_frame
lookup_selected_frame
frame_find_by_id
get_prev_frame
get_prev_frame_always
get_prev_frame_always_1
get_prev_frame_maybe_check_cycle
Then what we see is that the frame_info_ptr created in
get_prev_frame_maybe_check_cycle, which lacks a cached frame_id, can
be passed all the way back to lookup_selected_frame, where it will be
stored in the SELECTED_FRAME global by a call to select_frame. The
outer get_selected_frame call (in the above backtrace) will then
return the SELECTED_FRAME global, which lacks a cached frame-id.
If GDB ever tries to reinflate the SELECTED_FRAME frame_info_ptr (or a
copy of it), then we will trigger the assert:
`gdb_assert (frame_id_p (m_cached_id));` which can be found in
`frame_info_ptr::reinflate` in frame.c.
An example of how this can be triggered is included in the updated
test case, frame #1 is selected and the frame is printed. The pretty
printer performs an inferior call which invalidates the frame cache,
the assertion then triggers when trying to reinflate the selected
frame frame_info_ptr.
The problem is that frame's don't always know their frame-id when they
are placed into a frame_info_ptr, but they always do (for frame other
than #0) after get_prev_frame_maybe_check_cycle has finished. We
could try to have get_prev_frame_maybe_check_cycle or compute_frame_id
push the computed frame-id into the frame_info_ptr, or we can just
defer caching the frame-id until we know we might need it, i.e. when
the frame cache is being flushed.
This second approach is actually nice in that it defers the work until
we know we need it, and frame_info_ptr objects that are created and
destroyed without the frame cache ever being flushed no longer need to
cache the frame-id. This isn't going to give any noticable
performance improvement, but still, it feels nice.
The changes in this commit then are:
1. In reinit_frame_cache we call frame_info_ptr::invalidate before
deleting all the frame_info objects (by clearing the obstacks),
this allows us to copy the frame_id from these objects.
2. In frame_info_ptr::frame_info_ptr we still need to record every
frame_info_ptr in the global list, and for now at least, we still
cache the frame level, this is needed for
frame_info_ptr::is_null, which checks the cached level.
3. In frame_info::invalidate, we can assert that the cached level
matches the stored frame's level, this should never change, and
it is here that we now cache the frame-id.
3 files changed