mgorny updated this revision to Diff 431140.
mgorny added a comment.
Implemented `vCtrlC` packet and added a test for it.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D125575/new/
https://reviews.llvm.org/D125575
Files:
lldb/include/lldb/Utility/StringExtractorGDBRemote.h
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
lldb/source/Utility/StringExtractorGDBRemote.cpp
lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
Index: lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
===
--- lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
+++ lldb/test/API/tools/lldb-server/TestLldbGdbServer.py
@@ -1410,3 +1410,100 @@
self.assertEqual(decoded[errno_idx], 0) # si_errno
self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code
self.assertEqual(decoded[addr_idx], 0) # si_addr
+
+def test_QNonStop(self):
+self.build()
+self.set_inferior_startup_launch()
+thread_num = 3
+procs = self.prep_debug_monitor_and_inferior(
+inferior_args=["thread:segfault"] + thread_num * ["thread:new"])
+self.test_sequence.add_log_lines(
+["read packet: $QNonStop:1#00",
+ "send packet: $OK#00",
+ "read packet: $c#63",
+ "send packet: $OK#00",
+ ], True)
+self.expect_gdbremote_sequence()
+
+segv_signo = lldbutil.get_signal_number('SIGSEGV')
+all_threads = set()
+all_segv_threads = []
+
+# we should get segfaults from all the threads
+for segv_no in range(thread_num):
+# first wait for the notification event
+self.reset_test_sequence()
+self.test_sequence.add_log_lines(
+[{"direction": "send",
+ "regex": r"^%Stop:T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",
+ "capture": {1: "signo", 2: "thread_id"},
+ },
+ ], True)
+threads = [self.expect_gdbremote_sequence()]
+
+# then we may get events for the remaining threads
+# (but note that not all threads may have been started yet)
+while True:
+self.reset_test_sequence()
+self.test_sequence.add_log_lines(
+["read packet: $vStopped#00",
+ {"direction": "send",
+ "regex": r"^\$(OK|T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);)",
+ "capture": {1: "packet", 2: "signo", 3: "thread_id"},
+ },
+ ], True)
+m = self.expect_gdbremote_sequence()
+if m["packet"] == "OK":
+break
+threads.append(m)
+
+segv_threads = []
+other_threads = []
+for t in threads:
+signo = int(t["signo"], 16)
+if signo == segv_signo:
+segv_threads.append(t["thread_id"])
+else:
+self.assertEqual(signo, 0)
+other_threads.append(t["thread_id"])
+
+# verify that exactly one thread segfaulted
+self.assertEqual(len(segv_threads), 1)
+# we should get only one segv from every thread
+self.assertNotIn(segv_threads[0], all_segv_threads)
+all_segv_threads.extend(segv_threads)
+# segv_threads + other_threads should always be a superset
+# of all_threads, i.e. we should get states for all threads
+# already started
+self.assertFalse(
+all_threads.difference(other_threads + segv_threads))
+all_threads.update(other_threads + segv_threads)
+
+self.reset_test_sequence()
+self.test_sequence.add_log_lines(
+["read packet: $vCont;C{:02x}:{};c#00"
+ .format(segv_signo, segv_threads[0]),
+ "send packet: $OK#00",
+ ], True)
+self.expect_gdbremote_sequence()
+
+# finally, verify that all threads have started
+self.assertEqual(len(all_threads), thread_num + 1)
+
+def test_QNonStop_vCtrlC(self):
+self.build()
+self.set_inferior_startup_launch()
+procs = self.prep_debug_monitor_and_inferior(
+inferior_args=["thread:new"])
+self.test_sequence.add_log_lines(
+["read packet: $QNonStop:1#00",
+ "send packet: $OK#00",
+ "read packet: $c#63",
+