aboutsummaryrefslogtreecommitdiff
path: root/gdb/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/frame.c')
-rw-r--r--gdb/frame.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/gdb/frame.c b/gdb/frame.c
index d289440..1667325 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2044,14 +2044,23 @@ frame_register_unwind_location (struct frame_info *this_frame, int regnum,
outermost, with UNWIND_SAME_ID stop reason. Unlike the other
validity tests, that compare THIS_FRAME and the next frame, we do
this right after creating the previous frame, to avoid ever ending
- up with two frames with the same id in the frame chain. */
+ up with two frames with the same id in the frame chain.
+
+ There is however, one case where this cycle detection is not desirable,
+ when asking for the previous frame of an inline frame, in this case, if
+ the previous frame is a duplicate and we return nullptr then we will be
+ unable to calculate the frame_id of the inline frame, this in turn
+ causes inline_frame_this_id() to fail. So for inline frames (and only
+ for inline frames), the previous frame will always be returned, even when it
+ has a duplicate frame_id. We're not worried about cycles in the frame
+ chain as, if the previous frame returned here has a duplicate frame_id,
+ then the frame_id of the inline frame, calculated based off the frame_id
+ of the previous frame, should also be a duplicate. */
static struct frame_info *
-get_prev_frame_if_no_cycle (struct frame_info *this_frame)
+get_prev_frame_maybe_check_cycle (struct frame_info *this_frame)
{
- struct frame_info *prev_frame;
-
- prev_frame = get_prev_frame_raw (this_frame);
+ struct frame_info *prev_frame = get_prev_frame_raw (this_frame);
/* Don't compute the frame id of the current frame yet. Unwinding
the sentinel frame can fail (e.g., if the thread is gone and we
@@ -2070,7 +2079,42 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
try
{
compute_frame_id (prev_frame);
- if (!frame_stash_add (prev_frame))
+
+ bool cycle_detection_p = get_frame_type (this_frame) != INLINE_FRAME;
+
+ /* This assert checks GDB's state with respect to calculating the
+ frame-id of THIS_FRAME, in the case where THIS_FRAME is an inline
+ frame.
+
+ If THIS_FRAME is frame #0, and is an inline frame, then we put off
+ calculating the frame_id until we specifically make a call to
+ get_frame_id(). As a result we can enter this function in two
+ possible states. If GDB asked for the previous frame of frame #0
+ then THIS_FRAME will be frame #0 (an inline frame), and the
+ frame_id will be in the NOT_COMPUTED state. However, if GDB asked
+ for the frame_id of frame #0, then, as getting the frame_id of an
+ inline frame requires us to get the frame_id of the previous
+ frame, we will still end up in here, and the frame_id status will
+ be COMPUTING.
+
+ If, instead, THIS_FRAME is at a level greater than #0 then things
+ are simpler. For these frames we immediately compute the frame_id
+ when the frame is initially created, and so, for those frames, we
+ will always enter this function with the frame_id status of
+ COMPUTING. */
+ gdb_assert (cycle_detection_p
+ || (this_frame->level > 0
+ && (this_frame->this_id.p
+ == frame_id_status::COMPUTING))
+ || (this_frame->level == 0
+ && (this_frame->this_id.p
+ != frame_id_status::COMPUTED)));
+
+ /* We must do the CYCLE_DETECTION_P check after attempting to add
+ PREV_FRAME into the cache; if PREV_FRAME is unique then we do want
+ it in the cache, but if it is a duplicate and CYCLE_DETECTION_P is
+ false, then we don't want to unlink it. */
+ if (!frame_stash_add (prev_frame) && cycle_detection_p)
{
/* Another frame with the same id was already in the stash. We just
detected a cycle. */
@@ -2147,7 +2191,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
until we have unwound all the way down to the previous non-inline
frame. */
if (get_frame_type (this_frame) == INLINE_FRAME)
- return get_prev_frame_if_no_cycle (this_frame);
+ return get_prev_frame_maybe_check_cycle (this_frame);
/* If this_frame is the current frame, then compute and stash its
frame id prior to fetching and computing the frame id of the
@@ -2248,7 +2292,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
}
}
- return get_prev_frame_if_no_cycle (this_frame);
+ return get_prev_frame_maybe_check_cycle (this_frame);
}
/* Return a "struct frame_info" corresponding to the frame that called