Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -339,6 +339,8 @@ bool GetQXferSigInfoReadSupported(); + bool GetMultiprocessSupported(); + LazyBool SupportsAllocDeallocMemory() // const { // Uncomment this to have lldb pretend the debug server doesn't respond to Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -181,6 +181,12 @@ return m_supports_qXfer_siginfo_read == eLazyBoolYes; } +bool GDBRemoteCommunicationClient::GetMultiprocessSupported() { + if (m_supports_memory_tagging == eLazyBoolCalculate) + GetRemoteQSupported(); + return m_supports_multiprocess == eLazyBoolYes; +} + uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() { if (m_max_packet_size == 0) { GetRemoteQSupported(); @@ -1514,7 +1520,7 @@ } } - if (m_supports_multiprocess) { + if (GetMultiprocessSupported()) { // Some servers (e.g. qemu) require specifying the PID even if only a single // process is running. if (pid == LLDB_INVALID_PROCESS_ID) Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1186,11 +1186,18 @@ StreamString continue_packet; bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport()) { + std::string pid_prefix; + if (m_gdb_comm.GetMultiprocessSupported()) + pid_prefix = llvm::formatv("p{0:x-}.", GetID()); + if (m_continue_c_tids.size() == num_threads || (m_continue_c_tids.empty() && m_continue_C_tids.empty() && m_continue_s_tids.empty() && m_continue_S_tids.empty())) { - // All threads are continuing, just send a "c" packet - continue_packet.PutCString("c"); + // All threads are continuing + if (m_gdb_comm.GetMultiprocessSupported()) + continue_packet.Format("vCont;c:{0}-1", pid_prefix); + else + continue_packet.PutCString("c"); } else { continue_packet.PutCString("vCont"); @@ -1200,7 +1207,7 @@ t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); + continue_packet.Format(";c:{0}{1:x-}", pid_prefix, *t_pos); } else continue_packet_error = true; } @@ -1211,8 +1218,8 @@ s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, - s_pos->first); + continue_packet.Format(";C{0:x-2}:{1}{2:x-}", s_pos->second, + pid_prefix, s_pos->first); } else continue_packet_error = true; } @@ -1223,7 +1230,7 @@ t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos) - continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); + continue_packet.Format(";s:{0}{1:x-}", pid_prefix, *t_pos); } else continue_packet_error = true; } @@ -1234,8 +1241,8 @@ s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos) - continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, - s_pos->first); + continue_packet.Format(";S{0:x-2}:{1}{2:x-}", s_pos->second, + pid_prefix, s_pos->first); } else continue_packet_error = true; } Index: lldb/test/API/functionalities/gdb_remote_client/TestContinue.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/gdb_remote_client/TestContinue.py @@ -0,0 +1,74 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test.gdbclientutils import * +from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase + + +class TestContinue(GDBRemoteTestBase): + class BaseResponder(MockGDBServerResponder): + def qSupported(self, client_supported): + return "PacketSize=3fff;QStartNoAckMode+;multiprocess+" + + def qfThreadInfo(self): + return "mp400.401" + + def haltReason(self): + return "S13" + + def cont(self): + return "W01" + + def other(self, packet): + if packet == "vCont?": + return "vCont;c;C;s;S" + if packet.startswith("vCont;"): + return "W00" + return "" + + def test_continue_no_multiprocess(self): + class MyResponder(self.BaseResponder): + def qSupported(self, client_supported): + return "PacketSize=3fff;QStartNoAckMode+" + + def qfThreadInfo(self): + return "m401" + + self.server.responder = MyResponder() + self.runCmd("platform select remote-linux") + target = self.createTarget("a.yaml") + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, + [lldb.eStateExited]) + self.assertPacketLogContains(["vCont;C13:401"]) + + def test_continue_no_vCont(self): + class MyResponder(self.BaseResponder): + def qSupported(self, client_supported): + return "PacketSize=3fff;QStartNoAckMode+" + + def qfThreadInfo(self): + return "m401" + + def other(self, packet): + return "" + + self.server.responder = MyResponder() + self.runCmd("platform select remote-linux") + target = self.createTarget("a.yaml") + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, + [lldb.eStateExited]) + self.assertPacketLogContains(["Hc401", "C13"]) + + def test_continue_multiprocess(self): + class MyResponder(self.BaseResponder): + pass + + self.server.responder = MyResponder() + self.runCmd("platform select remote-linux") + target = self.createTarget("a.yaml") + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, + [lldb.eStateExited]) + self.assertPacketLogContains(["vCont;C13:p400.401"])