diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1762,6 +1762,7 @@ break; } + // If there's no thread-id (e.g. "vCont;c"), it's "p-1.-1". lldb::pid_t pid = StringExtractorGDBRemote::AllProcesses; lldb::tid_t tid = StringExtractorGDBRemote::AllThreads; @@ -1770,7 +1771,7 @@ // Consume the separator. packet.GetChar(); - auto pid_tid = packet.GetPidTid(StringExtractorGDBRemote::AllProcesses); + auto pid_tid = packet.GetPidTid(LLDB_INVALID_PROCESS_ID); if (!pid_tid) return SendIllFormedResponse(packet, "Malformed thread-id"); @@ -1784,29 +1785,35 @@ packet, "'t' action not supported for individual threads"); } - if (pid == StringExtractorGDBRemote::AllProcesses) { - if (m_debugged_processes.size() > 1) - return SendIllFormedResponse( - packet, "Resuming multiple processes not supported yet"); + // If we get TID without PID, it's the current process. + if (pid == LLDB_INVALID_PROCESS_ID) { if (!m_continue_process) { - LLDB_LOG(log, "no debugged process"); + LLDB_LOG(log, "no process selected via Hc"); return SendErrorResponse(0x36); } pid = m_continue_process->GetID(); } + assert(pid != LLDB_INVALID_PROCESS_ID); if (tid == StringExtractorGDBRemote::AllThreads) tid = LLDB_INVALID_THREAD_ID; - thread_action.tid = tid; - thread_actions[pid].Append(thread_action); + if (pid == StringExtractorGDBRemote::AllProcesses) { + if (tid != LLDB_INVALID_THREAD_ID) + return SendIllFormedResponse( + packet, "vCont: p-1 is not valid with a specific tid"); + for (auto &process_it : m_debugged_processes) + thread_actions[process_it.first].Append(thread_action); + } else + thread_actions[pid].Append(thread_action); } assert(thread_actions.size() >= 1); - if (thread_actions.size() > 1) + if (thread_actions.size() > 1 && !m_non_stop) return SendIllFormedResponse( - packet, "Resuming multiple processes not supported yet"); + packet, + "Resuming multiple processes is supported in non-stop mode only"); for (std::pair x : thread_actions) { auto process_it = m_debugged_processes.find(x.first); diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py --- a/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py +++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteForkNonStop.py @@ -150,3 +150,55 @@ self.assertEqual(output.count(b"PID: "), 2) self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output) self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output) + + @add_test_categories(["fork"]) + def test_vCont_both_nonstop(self): + lock1 = self.getBuildArtifact("lock1") + lock2 = self.getBuildArtifact("lock2") + parent_pid, parent_tid, child_pid, child_tid = ( + self.start_fork_test(["fork", "process:sync:" + lock1, "print-pid", + "process:sync:" + lock2, "stop"], + nonstop=True)) + + self.test_sequence.add_log_lines([ + "read packet: $vCont;c:p{}.{};c:p{}.{}#00".format( + parent_pid, parent_tid, child_pid, child_tid), + "send packet: $OK#00", + {"direction": "send", "regex": "%Stop:T.*"}, + ], True) + self.expect_gdbremote_sequence() + + output = self.get_all_output_via_vStdio( + lambda output: output.count(b"PID: ") >= 2) + self.assertEqual(output.count(b"PID: "), 2) + self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output) + self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output) + + def vCont_both_nonstop_test(self, vCont_packet): + lock1 = self.getBuildArtifact("lock1") + lock2 = self.getBuildArtifact("lock2") + parent_pid, parent_tid, child_pid, child_tid = ( + self.start_fork_test(["fork", "process:sync:" + lock1, "print-pid", + "process:sync:" + lock2, "stop"], + nonstop=True)) + + self.test_sequence.add_log_lines([ + "read packet: ${}#00".format(vCont_packet), + "send packet: $OK#00", + {"direction": "send", "regex": "%Stop:T.*"}, + ], True) + self.expect_gdbremote_sequence() + + output = self.get_all_output_via_vStdio( + lambda output: output.count(b"PID: ") >= 2) + self.assertEqual(output.count(b"PID: "), 2) + self.assertIn("PID: {}".format(int(parent_pid, 16)).encode(), output) + self.assertIn("PID: {}".format(int(child_pid, 16)).encode(), output) + + @add_test_categories(["fork"]) + def test_vCont_both_implicit_nonstop(self): + self.vCont_both_nonstop_test("vCont;c") + + @add_test_categories(["fork"]) + def test_vCont_both_minus_one_nonstop(self): + self.vCont_both_nonstop_test("vCont;c:p-1.-1")