blob: 6d82d999e7c0ac86c672e25ded91fb0400c352a2 [file] [log] [blame]
The inlined frame unwinder has a built-in assumption that it can
always unwind to a good non-inlined frame. If this assumption is
violated GDB dies with an internal error. Sometimes, when there are
issues unwinding the stack, this assumption is not true: the non-lined
frame is considered 'bad' and gets thrown out. This patch updates GDB
so that, in that case, GDB will stop the backtrace giving the user an
error message, rather than crash with an internal error.
Author: cmtice@google.com
Date: 27-May-2021
diff --git a/gdb/frame.c b/gdb/frame.c
index c746a6a..9cbf88d 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -262,7 +262,7 @@ frame_stash_add (struct frame_info *frame)
either have a stack cycle (corrupted stack?), or some bug
elsewhere in GDB. In any case, ignore the duplicate and return
an indication to the caller. */
- if (*slot != NULL)
+ if ((*slot != NULL) || (frame->stop_reason == UNWIND_SAME_ID))
return 0;
*slot = frame;
@@ -584,7 +584,6 @@ get_frame_id (struct frame_info *fi)
/* Since this is the first frame in the chain, this should
always succeed. */
stashed = frame_stash_add (fi);
- gdb_assert (stashed);
}
return fi->this_id.value;
@@ -1935,7 +1935,16 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
fprint_frame (gdb_stdlog, NULL);
fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
}
- this_frame->stop_reason = UNWIND_SAME_ID;
+ if ((get_frame_type (prev_frame) == INLINE_FRAME)
+ && (prev_frame->stop_reason == UNWIND_SAME_ID))
+ {
+ if (get_frame_type (this_frame) == INLINE_FRAME)
+ this_frame->stop_reason = UNWIND_SAME_ID;
+ return prev_frame;
+ }
+ else
+ this_frame->stop_reason = UNWIND_SAME_ID;
+
/* Unlink. */
prev_frame->next = NULL;
this_frame->prev = NULL;
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
index 9982046..814c4e4 100644
--- a/gdb/inline-frame.c
+++ b/gdb/inline-frame.c
@@ -138,6 +138,7 @@ inline_frame_this_id (struct frame_info *this_frame,
struct frame_id *this_id)
{
struct symbol *func;
+ struct frame_info *prev_frame;
/* In order to have a stable frame ID for a given inline function,
we must get the stack / special addresses from the underlying
@@ -145,7 +146,12 @@ inline_frame_this_id (struct frame_info *this_frame,
get_prev_frame_always. Because we are inlined into some
function, there must be previous frames, so this is safe - as
long as we're careful not to create any cycles. */
- *this_id = get_frame_id (get_prev_frame_always (this_frame));
+ prev_frame = get_prev_frame_always (this_frame);
+ if ((prev_frame != NULL)
+ && (get_frame_unwind_stop_reason (prev_frame) != UNWIND_SAME_ID))
+ *this_id = get_frame_id (prev_frame);
+ else
+ return;
/* We need a valid frame ID, so we need to be based on a valid
frame. FSF submission NOTE: this would be a good assertion to