diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 29417b35fde3a..11d0fec1926ab 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -181,6 +181,12 @@ bool GDBRemoteCommunicationClient::GetQXferSigInfoReadSupported() { 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 @@ Status GDBRemoteCommunicationClient::Detach(bool keep_stopped, } } - 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) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 3a62747603f6d..4e89ade772ad3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -339,6 +339,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase { bool GetQXferSigInfoReadSupported(); + bool GetMultiprocessSupported(); + LazyBool SupportsAllocDeallocMemory() // const { // Uncomment this to have lldb pretend the debug server doesn't respond to diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 30fb27932d192..0c876a8fd703e 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1186,11 +1186,15 @@ Status ProcessGDBRemote::DoResume() { 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 + continue_packet.Format("vCont;c:{0}-1", pid_prefix); } else { continue_packet.PutCString("vCont"); @@ -1200,7 +1204,7 @@ Status ProcessGDBRemote::DoResume() { 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 +1215,8 @@ Status ProcessGDBRemote::DoResume() { 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 +1227,7 @@ Status ProcessGDBRemote::DoResume() { 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 +1238,8 @@ Status ProcessGDBRemote::DoResume() { 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; } diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestContinue.py b/lldb/test/API/functionalities/gdb_remote_client/TestContinue.py new file mode 100644 index 0000000000000..14147fb5b2bfe --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestContinue.py @@ -0,0 +1,87 @@ +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) + 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) + 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) + self.assertPacketLogContains(["vCont;C13:p400.401"]) + + def test_step_multiprocess(self): + class MyResponder(self.BaseResponder): + def other(self, packet): + if packet == "vCont?": + return "vCont;c;C;s;S" + if packet.startswith("vCont;C"): + return "S13" + if packet.startswith("vCont;s"): + return "W00" + return "" + + self.server.responder = MyResponder() + self.runCmd("platform select remote-linux") + target = self.createTarget("a.yaml") + process = self.connect(target) + thread = process.GetSelectedThread() + thread.StepInstruction(False) + self.assertPacketLogContains(["vCont;s:p400.401"])