]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: fix 'maint info inline-frames' after 'stepi'
authorAndrew Burgess <aburgess@redhat.com>
Thu, 17 Oct 2024 10:56:47 +0000 (11:56 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Sun, 20 Oct 2024 20:54:13 +0000 (21:54 +0100)
There is an invalid assumption within 'maint info inline-frames' which
triggers an assert:

  (gdb) stepi
  0x000000000040119d 18   printf ("Hello World\n");
  (gdb) maintenance info inline-frames
  ../../src/gdb/inline-frame.c:554: internal-error: maintenance_info_inline_frames: Assertion `it != inline_states.end ()' failed.
  A problem internal to GDB has been detected,
  further debugging may prove unreliable.
  ----- Backtrace -----
  ... etc ...

The problem is this assert:

  /* Stopped threads always have cached inline_state information.  */
  gdb_assert (it != inline_states.end ());

If you check out infrun.c and look in handle_signal_stop for the call
to skip_inline_frames then you'll find a rather large comment that
explains that we don't always compute the inline state information for
performance reasons.  So the assertion is not valid.

I've updated the code so that if there is cached information we use
that, but if there is not then we just create our own information for
the current $pc of the current thread.

This means that, if there is cached information, GDB still correctly
shows which frame the inferior is in (it might not be in the inner
most frame).

If there is no cached information we will always display the inferior
as being in the inner most frame, but that's OK, because if
skip_inline_frames has not been called then GDB will have told the
user they are in the inner most frame, so everything lines up.

I've extended the test to check 'maint info inline-frames' after a
stepi which would previously have triggered the assertion.

gdb/inline-frame.c
gdb/testsuite/gdb.base/maint-info-inline-frames-and-blocks.exp

index 8ba886c3efc84c4885cb0a529a26991fd1978cd3..759c526a7c200543f7a15841a8c799eb25ab63eb 100644 (file)
@@ -550,15 +550,38 @@ maintenance_info_inline_frames (const char *arg, int from_tty)
                                return thread == istate.thread;
                              });
 
-      /* Stopped threads always have cached inline_state information.  */
-      gdb_assert (it != inline_states.end ());
+      /* Stopped threads don't always have cached inline_state
+        information.  We always skip computing the inline_state after a
+        stepi or nexti, but also in some other cases when we can be sure
+        that the inferior isn't at the start of an inlined function.
+        Check out the call to skip_inline_frames in handle_signal_stop
+        for more details.  */
+      if (it != inline_states.end ())
+       {
+         /* We do have cached inline frame information, use it.  This
+            gives us access to the current skipped_frames count so we can
+            correctly indicate when the inferior is not in the inner most
+            inlined function.  */
+         gdb_printf (_("Cached inline state information for thread %s.\n"),
+                     print_thread_id (thread));
+
+         function_symbols = &it->function_symbols;
+         skipped_frames = it->skipped_frames;
+         addr = it->saved_pc;
+       }
+      else
+       {
+         /* No cached inline frame information, lookup the information for
+            the current address.  */
+         gdb_printf (_("Inline state information for thread %s.\n"),
+                     print_thread_id (thread));
 
-      gdb_printf (_("Cached inline state information for thread %s.\n"),
-                 print_thread_id (thread));
+         addr = get_frame_pc (get_current_frame ());
+         local_function_symbols.emplace (gather_inline_frames (addr));
 
-      function_symbols = &it->function_symbols;
-      skipped_frames = it->skipped_frames;
-      addr = it->saved_pc;
+         function_symbols = &(local_function_symbols.value ());
+         skipped_frames = 0;
+       }
     }
   else
     {
index 16be22a99635a72f152a8ad28f9dd0622d7d8b4e..97e5d99e405127a1e594db047b74116ce56ad712 100644 (file)
@@ -173,6 +173,20 @@ gdb_test "maint info blocks" [make_blocks_result normal_func \
                                  inline_func_a inline_func_b] \
     "maint info blocks within inline function, all blocks still visible"
 
+# Use 'stepi' and check 'maint info inline-frames' still works.
+gdb_test "stepi" ".*" "perform stepi"
+gdb_test "maint info inline-frames" \
+    [multi_line \
+        "^Inline state information for thread $decimal\\." \
+        "program counter = $hex" \
+        "skipped frames = 0" \
+        "> inline_func_b"] \
+    "check inline-frames state when within inline_func_b after stepi"
+
+gdb_test "maint info blocks" [make_blocks_result normal_func \
+                                 inline_func_a inline_func_b] \
+    "maint info blocks within inline function after stepi, all blocks still visible"
+
 # Use the recorded $pc value to check inline frames.
 gdb_test "maint info inline-frames $pc" \
     [multi_line \