Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -945,7 +945,7 @@ case eStateSuspended: case eStateStopped: - llvm_unreachable("Unexpected state"); + break; default: return Status("NativeProcessLinux::%s (): unexpected state %s specified " Index: lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp =================================================================== --- lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -117,7 +117,7 @@ } case eStateSuspended: case eStateStopped: - llvm_unreachable("Unexpected state"); + break; default: return Status( Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1549,7 +1549,7 @@ 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()); } @@ -1626,6 +1626,11 @@ thread_action.state = eStateStepping; break; + case 't': + // Stop + thread_action.state = eStateSuspended; + break; + default: return SendIllFormedResponse(packet, "Unsupported vCont action"); break; Index: lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py =================================================================== --- lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py +++ lldb/test/API/tools/lldb-server/TestGdbRemote_vCont.py @@ -41,6 +41,10 @@ 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): Index: lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py =================================================================== --- lldb/test/API/tools/lldb-server/vCont-threads/TestGdbRemote_vContThreads.py +++ 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 * @@ -14,8 +15,7 @@ # 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() @@ -34,9 +34,8 @@ 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)), }, @@ -228,3 +227,71 @@ 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])) Index: lldb/test/API/tools/lldb-server/vCont-threads/main.cpp =================================================================== --- lldb/test/API/tools/lldb-server/vCont-threads/main.cpp +++ lldb/test/API/tools/lldb-server/vCont-threads/main.cpp @@ -22,7 +22,10 @@ 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) {