]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
btrace: do not stop replaying or recording while a thread is running
authorMarkus Metzger <markus.t.metzger@intel.com>
Wed, 13 Aug 2025 14:25:27 +0000 (14:25 +0000)
committerMarkus Metzger <markus.t.metzger@intel.com>
Mon, 3 Nov 2025 06:21:11 +0000 (06:21 +0000)
With asynchronous stepping commands, one may start replaying a thread in
the background and then stop recording its inferior in the foreground.

This causes the execution history to be cleared and the record target to
be unpushed while the thread is using said execution history.

I fail to see a use-case for this, so rather than trying to make this
work, I prevent such a scenario by not allowing replaying or recording to
be stopped while a thread is running.

We could do this only when a thread is running in replay mode and preserve
the existing behavior of being able to stop recording while threads are
running in recording mode.  It seems more consistent to not allow this for
both replaying and recording threads, though.

gdb/record-btrace.c
gdb/testsuite/gdb.btrace/enable-running.exp

index 1af9f49ec60f2d06a708e5d8129f8e373cabef11..1534b76de77518ecb19b448d31a2c65198f9797b 100644 (file)
@@ -413,6 +413,11 @@ record_btrace_target::stop_recording ()
 {
   DEBUG ("stop recording");
 
+  /* Check that before so stop recording is atomic.  */
+  for (thread_info &tp : current_inferior ()->non_exited_threads ())
+    if (tp.state == THREAD_RUNNING)
+      error (_("You cannot stop recording while threads are running."));
+
   bool is_replaying = record_is_replaying (inferior_ptid);
   record_stop_replaying ();
   record_btrace_auto_disable ();
@@ -2140,12 +2145,25 @@ record_btrace_start_replaying (struct thread_info *tp)
 static void
 record_btrace_stop_replaying (struct thread_info *tp)
 {
-  struct btrace_thread_info *btinfo;
+  struct btrace_thread_info *btinfo = &tp->btrace;
 
-  btinfo = &tp->btrace;
+  if (btinfo->replay == nullptr)
+    return;
+
+  switch (tp->state)
+    {
+    case THREAD_STOPPED:
+      break;
+
+    case THREAD_RUNNING:
+      error (_("Cannot stop replaying a running thread."));
+
+    case THREAD_EXITED:
+      gdb_assert_not_reached ("unexpected thread state");
+    }
 
   xfree (btinfo->replay);
-  btinfo->replay = NULL;
+  btinfo->replay = nullptr;
 
   /* Make sure we're not leaving any stale registers.  */
   registers_changed_thread (tp);
index 92ae5663cc44b8c1db663264beb4d283dfc21b2c..c2e64864b281798fb4a088b76b959a3912f1438e 100644 (file)
@@ -93,4 +93,4 @@ foreach thread {1 2 3 4} {
 }
 
 # Stop recording while all threads are running.
-gdb_test "record stop" "Process record is stopped \[^\\\r\\\n\]*"
+gdb_test "record stop" "You cannot stop recording while threads are running\."