Blame SOURCES/gdb-rhbz1909902-frame_id_p-assert-2.patch

4a80f0
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
4a80f0
From: Pedro Alves <pedro@palves.net>
4a80f0
Date: Sat, 31 Oct 2020 00:27:18 +0000
4a80f0
Subject: gdb-rhbz1909902-frame_id_p-assert-2.patch
4a80f0
4a80f0
;; Backport patch #2 which fixes a frame_id_p assertion failure (RH BZ 1909902).
4a80f0
4a80f0
Fix frame cycle detection
4a80f0
4a80f0
The recent commit to make scoped_restore_current_thread's cdtors
4a80f0
exception free regressed gdb.base/eh_return.exp:
4a80f0
4a80f0
  Breakpoint 1, 0x00000000004012bb in eh2 (gdb/frame.c:641: internal-error: frame_id get_frame_id(frame_info*): Assertion `stashed' failed.
4a80f0
  A problem internal to GDB has been detected,
4a80f0
  further debugging may prove unreliable.
4a80f0
  Quit this debugging session? (y or n) FAIL: gdb.base/eh_return.exp: hit breakpoint (GDB internal error)
4a80f0
4a80f0
That testcase uses __builtin_eh_return and, before the regression, the
4a80f0
backtrace at eh2 looked like this:
4a80f0
4a80f0
 (gdb) bt
4a80f0
 #0  0x00000000004006eb in eh2 (p=0x4006ec <continuation>) at src/gdb/testsuite/gdb.base/eh_return.c:54
4a80f0
 Backtrace stopped: previous frame identical to this frame (corrupt stack?)
4a80f0
4a80f0
That "previous frame identical to this frame" is caught by the cycle
4a80f0
detection based on frame id.
4a80f0
4a80f0
The assertion failing is this one:
4a80f0
4a80f0
 638           /* Since this is the first frame in the chain, this should
4a80f0
 639              always succeed.  */
4a80f0
 640           bool stashed = frame_stash_add (fi);
4a80f0
 641           gdb_assert (stashed);
4a80f0
4a80f0
originally added by
4a80f0
4a80f0
  commit f245535cf583ae4ca13b10d47b3c7d3334593ece
4a80f0
  Author:     Pedro Alves <palves@redhat.com>
4a80f0
  AuthorDate: Mon Sep 5 18:41:38 2016 +0100
4a80f0
4a80f0
      Fix PR19927: Avoid unwinder recursion if sniffer uses calls parse_and_eval
4a80f0
4a80f0
The assertion is failing because frame #1's frame id was stashed
4a80f0
before the id of frame #0 is stashed.  The frame id of frame #1 was
4a80f0
stashed here:
4a80f0
4a80f0
 (top-gdb) bt
4a80f0
 #0  frame_stash_add (frame=0x1e24c90) at src/gdb/frame.c:276
4a80f0
 #1  0x0000000000669c1b in get_prev_frame_if_no_cycle (this_frame=0x19f8370) at src/gdb/frame.c:2120
4a80f0
 #2  0x000000000066a339 in get_prev_frame_always_1 (this_frame=0x19f8370) at src/gdb/frame.c:2303
4a80f0
 #3  0x000000000066a360 in get_prev_frame_always (this_frame=0x19f8370) at src/gdb/frame.c:2319
4a80f0
 #4  0x000000000066b56c in get_frame_unwind_stop_reason (frame=0x19f8370) at src/gdb/frame.c:3028
4a80f0
 #5  0x000000000059f929 in dwarf2_frame_cfa (this_frame=0x19f8370) at src/gdb/dwarf2/frame.c:1462
4a80f0
 #6  0x00000000005ce434 in dwarf_evaluate_loc_desc::get_frame_cfa (this=0x7fffffffc070) at src/gdb/dwarf2/loc.c:666
4a80f0
 #7  0x00000000005989a9 in dwarf_expr_context::execute_stack_op (this=0x7fffffffc070, op_ptr=0x1b2a053 "\364\003", op_end=0x1b2a053 "\364\003") at src/gdb/dwarf2/expr.c:1161
4a80f0
 #8  0x0000000000596af6 in dwarf_expr_context::eval (this=0x7fffffffc070, addr=0x1b2a052 "\234\364\003", len=1) at src/gdb/dwarf2/expr.c:303
4a80f0
 #9  0x0000000000597b4e in dwarf_expr_context::execute_stack_op (this=0x7fffffffc070, op_ptr=0x1b2a063 "", op_end=0x1b2a063 "") at src/gdb/dwarf2/expr.c:865
4a80f0
 #10 0x0000000000596af6 in dwarf_expr_context::eval (this=0x7fffffffc070, addr=0x1b2a061 "\221X", len=2) at src/gdb/dwarf2/expr.c:303
4a80f0
 #11 0x00000000005c8b5a in dwarf2_evaluate_loc_desc_full (type=0x1b564d0, frame=0x19f8370, data=0x1b2a061 "\221X", size=2, per_cu=0x1b28760, per_objfile=0x1a84930, subobj_type=0x1b564d0, subobj_byte_offset=0) at src/gdb/dwarf2/loc.c:2260
4a80f0
 #12 0x00000000005c9243 in dwarf2_evaluate_loc_desc (type=0x1b564d0, frame=0x19f8370, data=0x1b2a061 "\221X", size=2, per_cu=0x1b28760, per_objfile=0x1a84930) at src/gdb/dwarf2/loc.c:2444
4a80f0
 #13 0x00000000005cb769 in locexpr_read_variable (symbol=0x1b59840, frame=0x19f8370) at src/gdb/dwarf2/loc.c:3687
4a80f0
 #14 0x0000000000663137 in language_defn::read_var_value (this=0x122ea60 <c_language_defn>, var=0x1b59840, var_block=0x0, frame=0x19f8370) at src/gdb/findvar.c:618
4a80f0
 #15 0x0000000000663c3b in read_var_value (var=0x1b59840, var_block=0x0, frame=0x19f8370) at src/gdb/findvar.c:822
4a80f0
 #16 0x00000000008c7d9f in read_frame_arg (fp_opts=..., sym=0x1b59840, frame=0x19f8370, argp=0x7fffffffc470, entryargp=0x7fffffffc490) at src/gdb/stack.c:542
4a80f0
 #17 0x00000000008c89cd in print_frame_args (fp_opts=..., func=0x1b597c0, frame=0x19f8370, num=-1, stream=0x1aba860) at src/gdb/stack.c:890
4a80f0
 #18 0x00000000008c9bf8 in print_frame (fp_opts=..., frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, print_args=1, sal=...) at src/gdb/stack.c:1394
4a80f0
 #19 0x00000000008c92b9 in print_frame_info (fp_opts=..., frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, print_args=1, set_current_sal=1) at src/gdb/stack.c:1119
4a80f0
 #20 0x00000000008c75f0 in print_stack_frame (frame=0x19f8370, print_level=0, print_what=SRC_AND_LOC, set_current_sal=1) at src/gdb/stack.c:366
4a80f0
 #21 0x000000000070250b in print_stop_location (ws=0x7fffffffc9e0) at src/gdb/infrun.c:8110
4a80f0
 #22 0x0000000000702569 in print_stop_event (uiout=0x1a8b9e0, displays=true) at src/gdb/infrun.c:8126
4a80f0
 #23 0x000000000096d04b in tui_on_normal_stop (bs=0x1bcd1c0, print_frame=1) at src/gdb/tui/tui-interp.c:98
4a80f0
 ...
4a80f0
4a80f0
Before the commit to make scoped_restore_current_thread's cdtors
4a80f0
exception free, scoped_restore_current_thread's dtor would call
4a80f0
get_frame_id on the selected frame, and we use
4a80f0
scoped_restore_current_thread pervasively.  That had the side effect
4a80f0
of stashing the frame id of frame #0 before reaching the path shown in
4a80f0
the backtrace.  I.e., the frame id of frame #0 happened to be stashed
4a80f0
before the frame id of frame #1.  But that was by chance, not by
4a80f0
design.
4a80f0
4a80f0
This commit:
4a80f0
4a80f0
  commit 256ae5dbc73d1348850f86ee77a0dc3b04bc7cc0
4a80f0
  Author:     Kevin Buettner <kevinb@redhat.com>
4a80f0
  AuthorDate: Mon Oct 31 12:47:42 2016 -0700
4a80f0
4a80f0
      Stash frame id of current frame before stashing frame id for previous frame
4a80f0
4a80f0
Fixed a similar problem, by making sure get_prev_frame computes the
4a80f0
frame id of the current frame before unwinding the previous frame, so
4a80f0
that the cycle detection works properly.  That fix misses the scenario
4a80f0
we're now running against, because if you notice, the backtrace above
4a80f0
shows that frame #4 calls get_prev_frame_always, not get_prev_frame.
4a80f0
I.e., nothing is calling get_frame_id on the current frame.
4a80f0
4a80f0
The fix here is to move Kevin's fix down from get_prev_frame to
4a80f0
get_prev_frame_always.  Or actually, a bit further down to
4a80f0
get_prev_frame_always_1 -- note that inline_frame_this_id calls
4a80f0
get_prev_frame_always, so we need to be careful to avoid recursion in
4a80f0
that scenario.
4a80f0
4a80f0
gdb/ChangeLog:
4a80f0
4a80f0
	* frame.c (get_prev_frame): Move get_frame_id call from here ...
4a80f0
	(get_prev_frame_always_1): ... to here.
4a80f0
	* inline-frame.c (inline_frame_this_id): Mention
4a80f0
	get_prev_frame_always_1 in comment.
4a80f0
4a80f0
Change-Id: Id960c98ab2d072c48a436c3eb160cc4b2a5cfd1d
4a80f0
4a80f0
diff --git a/gdb/frame.c b/gdb/frame.c
4a80f0
--- a/gdb/frame.c
4a80f0
+++ b/gdb/frame.c
4a80f0
@@ -2133,6 +2133,23 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
4a80f0
   if (get_frame_type (this_frame) == INLINE_FRAME)
4a80f0
     return get_prev_frame_if_no_cycle (this_frame);
4a80f0
 
4a80f0
+  /* If this_frame is the current frame, then compute and stash its
4a80f0
+     frame id prior to fetching and computing the frame id of the
4a80f0
+     previous frame.  Otherwise, the cycle detection code in
4a80f0
+     get_prev_frame_if_no_cycle() will not work correctly.  When
4a80f0
+     get_frame_id() is called later on, an assertion error will be
4a80f0
+     triggered in the event of a cycle between the current frame and
4a80f0
+     its previous frame.
4a80f0
+
4a80f0
+     Note we do this after the INLINE_FRAME check above.  That is
4a80f0
+     because the inline frame's frame id computation needs to fetch
4a80f0
+     the frame id of its previous real stack frame.  I.e., we need to
4a80f0
+     avoid recursion in that case.  This is OK since we're sure the
4a80f0
+     inline frame won't create a cycle with the real stack frame.  See
4a80f0
+     inline_frame_this_id.  */
4a80f0
+  if (this_frame->level == 0)
4a80f0
+    get_frame_id (this_frame);
4a80f0
+
4a80f0
   /* Check that this frame is unwindable.  If it isn't, don't try to
4a80f0
      unwind to the prev frame.  */
4a80f0
   this_frame->stop_reason
4a80f0
@@ -2410,16 +2427,6 @@ get_prev_frame (struct frame_info *this_frame)
4a80f0
      something should be calling get_selected_frame() or
4a80f0
      get_current_frame().  */
4a80f0
   gdb_assert (this_frame != NULL);
4a80f0
-  
4a80f0
-  /* If this_frame is the current frame, then compute and stash
4a80f0
-     its frame id prior to fetching and computing the frame id of the
4a80f0
-     previous frame.  Otherwise, the cycle detection code in
4a80f0
-     get_prev_frame_if_no_cycle() will not work correctly.  When
4a80f0
-     get_frame_id() is called later on, an assertion error will
4a80f0
-     be triggered in the event of a cycle between the current
4a80f0
-     frame and its previous frame.  */
4a80f0
-  if (this_frame->level == 0)
4a80f0
-    get_frame_id (this_frame);
4a80f0
 
4a80f0
   frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
4a80f0
 
4a80f0
diff --git a/gdb/inline-frame.c b/gdb/inline-frame.c
4a80f0
--- a/gdb/inline-frame.c
4a80f0
+++ b/gdb/inline-frame.c
4a80f0
@@ -161,7 +161,8 @@ inline_frame_this_id (struct frame_info *this_frame,
4a80f0
      real frame's this_id method.  So we must call
4a80f0
      get_prev_frame_always.  Because we are inlined into some
4a80f0
      function, there must be previous frames, so this is safe - as
4a80f0
-     long as we're careful not to create any cycles.  */
4a80f0
+     long as we're careful not to create any cycles.  See related
4a80f0
+     comments in get_prev_frame_always_1.  */
4a80f0
   *this_id = get_frame_id (get_prev_frame_always (this_frame));
4a80f0
 
4a80f0
   /* We need a valid frame ID, so we need to be based on a valid