[Lldb-commits] [lldb] b4f2d7c - [lldb] [llgs] Support "t" vCont action

Michał Górny via lldb-commits lldb-commits at lists.llvm.org
Mon Jun 27 08:34:22 PDT 2022


Author: Michał Górny
Date: 2022-06-27T17:33:59+02:00
New Revision: b4f2d7cde54c301f591a8e2a16135bb113c5e7ed

URL: https://github.com/llvm/llvm-project/commit/b4f2d7cde54c301f591a8e2a16135bb113c5e7ed
DIFF: https://github.com/llvm/llvm-project/commit/b4f2d7cde54c301f591a8e2a16135bb113c5e7ed.diff

LOG: [lldb] [llgs] Support "t" vCont action

Implement support for the "t" action that is used to stop a thread.
Normally this action is used only in non-stop mode.  However, there's
no technical reason why it couldn't be also used in all-stop mode,
e.g. to express "resume all threads except ..." (`t:...;c`).

While at it, add a more complete test for vCont correctly resuming
a subset of program's threads.

Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.llvm.org/D126983

Added: 
    

Modified: 
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
    lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py
    lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py
    lldb/test/API/tools/lldb-server/vCont-threads/main.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 5324a2c0bf51e..0fb4c691118b7 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -947,7 +947,7 @@ Status NativeProcessLinux::Resume(const ResumeActionList &resume_actions) {
 
     case eStateSuspended:
     case eStateStopped:
-      llvm_unreachable("Unexpected state");
+      break;
 
     default:
       return Status("NativeProcessLinux::%s (): unexpected state %s specified "

diff  --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
index 10647839eec2e..a6d7500f41792 100644
--- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp
@@ -117,7 +117,7 @@ Status NativeProcessWindows::Resume(const ResumeActionList &resume_actions) {
       }
       case eStateSuspended:
       case eStateStopped:
-        llvm_unreachable("Unexpected state");
+        break;
 
       default:
         return Status(

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 2c009ef7fcd9a..ae8b8ef8ae156 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -1654,7 +1654,7 @@ GDBRemoteCommunication::PacketResult
 GDBRemoteCommunicationServerLLGS::Handle_vCont_actions(
     StringExtractorGDBRemote &packet) {
   StreamString response;
-  response.Printf("vCont;c;C;s;S");
+  response.Printf("vCont;c;C;s;S;t");
 
   return SendPacketNoLock(response.GetString());
 }
@@ -1723,6 +1723,11 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont(
       thread_action.state = eStateStepping;
       break;
 
+    case 't':
+      // Stop
+      thread_action.state = eStateSuspended;
+      break;
+
     default:
       return SendIllFormedResponse(packet, "Unsupported vCont action");
       break;

diff  --git a/lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py b/lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py
index db1e39b9759d7..c17d0b7740dde 100644
--- a/lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py
+++ b/lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py
@@ -39,6 +39,10 @@ def test_vCont_supports_S(self):
         self.build()
         self.vCont_supports_mode("S")
 
+    def test_vCont_supports_t(self):
+        self.build()
+        self.vCont_supports_mode("t")
+
     @skipIfWindows # No pty support to test O* & I* notification packets.
     @skipIf(triple='^mips')
     def test_single_step_only_steps_one_instruction_with_Hc_vCont_s(self):

diff  --git a/lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py b/lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py
index 30a136f127787..2a3275004e831 100644
--- a/lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py
+++ b/lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py
@@ -1,5 +1,6 @@
 import json
 import re
+import time
 
 import gdbremote_testcase
 from lldbsuite.test.decorators import *
@@ -13,8 +14,7 @@ def start_threads(self, num):
         # start the process and wait for output
         self.test_sequence.add_log_lines([
             "read packet: $c#63",
-            {"type": "output_match", "regex": self.maybe_strict_output_regex(
-                r"@started\r\n")},
+            {"type": "output_match", "regex": r".*@started\r\n.*"},
         ], True)
         # then interrupt it
         self.add_interrupt_packets()
@@ -33,9 +33,8 @@ def send_and_check_signal(self, vCont_data, threads):
         self.test_sequence.add_log_lines([
             "read packet: $vCont;{0}#00".format(vCont_data),
             {"type": "output_match",
-             "regex": self.maybe_strict_output_regex(
-                 len(threads) *
-                 r"received SIGUSR1 on thread id: ([0-9a-f]+)\r\n"),
+             "regex": len(threads) *
+                      r".*received SIGUSR1 on thread id: ([0-9a-f]+)\r\n.*",
              "capture": dict((i, "tid{0}".format(i)) for i
                              in range(1, len(threads)+1)),
              },
@@ -243,3 +242,71 @@ def test_signal_two_signals(self):
 
         context = self.expect_gdbremote_sequence()
         self.assertIsNotNone(context)
+
+    THREAD_MATCH_RE = re.compile(r"thread ([0-9a-f]+) running")
+
+    def continue_and_get_threads_running(self, continue_packet):
+        self.test_sequence.add_log_lines(
+            ["read packet: ${}#00".format(continue_packet),
+             ], True)
+        self.expect_gdbremote_sequence()
+        self.reset_test_sequence()
+        time.sleep(1)
+        self.add_interrupt_packets()
+        exp = self.expect_gdbremote_sequence()
+        found = set()
+        for line in exp["O_content"].decode().splitlines():
+            m = self.THREAD_MATCH_RE.match(line)
+            if m is not None:
+                found.add(int(m.group(1), 16))
+        return found
+
+    @add_test_categories(["llgs"])
+    def test_vCont_run_subset_of_threads(self):
+        self.build()
+        self.set_inferior_startup_launch()
+
+        threads = set(self.start_threads(3))
+        all_subthreads = self.continue_and_get_threads_running("c")
+        all_subthreads_list = list(all_subthreads)
+        self.assertEqual(len(all_subthreads), 3)
+        self.assertEqual(threads & all_subthreads, all_subthreads)
+
+        # resume two threads explicitly, stop the third one implicitly
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;c:{:x};c:{:x}".format(*all_subthreads_list[:2])),
+            set(all_subthreads_list[:2]))
+
+        # resume two threads explicitly, stop others explicitly
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;c:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
+            set(all_subthreads_list[:2]))
+
+        # stop one thread explicitly, resume others
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;t:{:x};c".format(all_subthreads_list[-1])),
+            set(all_subthreads_list[:2]))
+
+        # resume one thread explicitly, stop one explicitly,
+        # resume others
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;c:{:x};t:{:x};c".format(*all_subthreads_list[-2:])),
+            set(all_subthreads_list[:2]))
+
+        # resume one thread explicitly, stop one explicitly,
+        # stop others implicitly
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;t:{:x};c:{:x}".format(*all_subthreads_list[:2])),
+            set(all_subthreads_list[1:2]))
+
+        # resume one thread explicitly, stop one explicitly,
+        # stop others explicitly
+        self.assertEqual(
+            self.continue_and_get_threads_running(
+                "vCont;t:{:x};c:{:x};t".format(*all_subthreads_list[:2])),
+            set(all_subthreads_list[1:2]))

diff  --git a/lldb/test/API/tools/lldb-server/vCont-threads/main.cpp b/lldb/test/API/tools/lldb-server/vCont-threads/main.cpp
index f70be42af1a92..301b54f878dfc 100644
--- a/lldb/test/API/tools/lldb-server/vCont-threads/main.cpp
+++ b/lldb/test/API/tools/lldb-server/vCont-threads/main.cpp
@@ -22,7 +22,10 @@ static void sigusr1_handler(int signo) {
 
 static void thread_func() {
   pseudo_barrier_wait(barrier);
-  std::this_thread::sleep_for(std::chrono::minutes(1));
+  for (int i = 0; i < 300; ++i) {
+    std::printf("thread %" PRIx64 " running\n", get_thread_id());
+    std::this_thread::sleep_for(std::chrono::milliseconds(200));
+  }
 }
 
 int main(int argc, char **argv) {


        


More information about the lldb-commits mailing list