diff options
Diffstat (limited to 'gdb/frame.c')
-rw-r--r-- | gdb/frame.c | 60 |
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 |