Author: Michał Górny Date: 2022-06-24T17:20:23+02:00 New Revision: c18784ba330ac0f57e6ec433cfa8317349c445ff
URL: https://github.com/llvm/llvm-project/commit/c18784ba330ac0f57e6ec433cfa8317349c445ff DIFF: https://github.com/llvm/llvm-project/commit/c18784ba330ac0f57e6ec433cfa8317349c445ff.diff LOG: [lldb] [llgs] Implement the vKill packet Implement the support for the vKill packet. This is the modern packet used by the GDB Remote Serial Protocol to kill one of the debugged processes. Unlike the `k` packet, it has well-defined semantics. The `vKill` packet takes the PID of the process to kill, and always replies with an `OK` reply (rather than the exit status, as LLGS does for `k` packets at the moment). Additionally, unlike the `k` packet it does not cause the connection to be terminated once the last process is killed — the client needs to close it explicitly. Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.llvm.org/D127667 Added: Modified: lldb/include/lldb/Utility/StringExtractorGDBRemote.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/TestGdbRemoteFork.py Removed: ################################################################################ diff --git a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index 2a63212e9d287..c32ce0389116e 100644 --- a/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -136,6 +136,7 @@ class StringExtractorGDBRemote : public StringExtractor { eServerPacketType_vAttachName, eServerPacketType_vCont, eServerPacketType_vCont_actions, // vCont? + eServerPacketType_vKill, eServerPacketType_vRun, eServerPacketType_stop_reason, // '?' diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 434fb50862f8b..1ff0b7fe4ee5d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -232,6 +232,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { return this->Handle_k(packet); }); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vKill, + &GDBRemoteCommunicationServerLLGS::Handle_vKill); + RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qLLDBSaveCore, &GDBRemoteCommunicationServerLLGS::Handle_qSaveCore); @@ -482,6 +486,10 @@ GDBRemoteCommunicationServerLLGS::SendWResponse( LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(), *wait_status); + // If the process was killed through vKill, return "OK". + if (m_vkilled_processes.find(process->GetID()) != m_vkilled_processes.end()) + return SendOKResponse(); + StreamGDBRemote response; response.Format("{0:g}", *wait_status); if (bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess)) @@ -1049,9 +1057,13 @@ void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited( lldb::pid_t pid = process->GetID(); m_mainloop.AddPendingCallback([this, pid](MainLoopBase &loop) { m_debugged_processes.erase(pid); + auto vkill_it = m_vkilled_processes.find(pid); + if (vkill_it != m_vkilled_processes.end()) + m_vkilled_processes.erase(vkill_it); + // Terminate the main loop only if vKill has not been used. // When running in non-stop mode, wait for the vStopped to clear // the notification queue. - if (m_debugged_processes.empty() && !m_non_stop) { + else if (m_debugged_processes.empty() && !m_non_stop) { // Close the pipe to the inferior terminal i/o if we launched it and set // one up. MaybeCloseInferiorTerminalConnection(); @@ -1442,6 +1454,30 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { return SendContinueSuccessResponse(); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vKill( + StringExtractorGDBRemote &packet) { + StopSTDIOForwarding(); + + packet.SetFilePos(6); // vKill; + uint32_t pid = packet.GetU32(LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse(packet, + "vKill failed to parse the process id"); + + auto it = m_debugged_processes.find(pid); + if (it == m_debugged_processes.end()) + return SendErrorResponse(42); + + Status error = it->second->Kill(); + if (error.Fail()) + return SendErrorResponse(error.ToError()); + + // OK response is sent when the process dies. + m_vkilled_processes.insert(pid); + return PacketResult::Success; +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR( StringExtractorGDBRemote &packet) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 6a2ef89e07d58..728334ac81698 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -11,6 +11,7 @@ #include <mutex> #include <unordered_map> +#include <unordered_set> #include "lldb/Core/Communication.h" #include "lldb/Host/MainLoop.h" @@ -95,6 +96,7 @@ class GDBRemoteCommunicationServerLLGS std::recursive_mutex m_debugged_process_mutex; std::unordered_map<lldb::pid_t, std::unique_ptr<NativeProcessProtocol>> m_debugged_processes; + std::unordered_set<lldb::pid_t> m_vkilled_processes; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; @@ -129,6 +131,8 @@ class GDBRemoteCommunicationServerLLGS PacketResult Handle_k(StringExtractorGDBRemote &packet); + PacketResult Handle_vKill(StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qC(StringExtractorGDBRemote &packet); diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 17ab5ef21f58a..75fc74de4e215 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -372,6 +372,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_vCont; if (PACKET_MATCHES("vCont?")) return eServerPacketType_vCont_actions; + if (PACKET_STARTS_WITH("vKill;")) + return eServerPacketType_vKill; if (PACKET_STARTS_WITH("vRun;")) return eServerPacketType_vRun; if (PACKET_MATCHES("vStopped")) diff --git a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py index 8a3474ca78df1..a49a5b42c2ba8 100644 --- a/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py +++ b/lldb/test/API/tools/lldb-server/TestGdbRemoteFork.py @@ -296,3 +296,60 @@ def test_kill_all(self): ret = self.expect_gdbremote_sequence() self.assertEqual(set([ret["pid1"], ret["pid2"]]), set([parent_pid, child_pid])) + + def vkill_test(self, kill_parent=False, kill_child=False): + assert kill_parent or kill_child + self.build() + self.prep_debug_monitor_and_inferior(inferior_args=["fork"]) + self.add_qSupported_packets(["multiprocess+", + "fork-events+"]) + ret = self.expect_gdbremote_sequence() + self.assertIn("fork-events+", ret["qSupported_response"]) + self.reset_test_sequence() + + # continue and expect fork + self.test_sequence.add_log_lines([ + "read packet: $c#00", + {"direction": "send", "regex": self.fork_regex.format("fork"), + "capture": self.fork_capture}, + ], True) + ret = self.expect_gdbremote_sequence() + parent_pid = ret["parent_pid"] + parent_tid = ret["parent_tid"] + child_pid = ret["child_pid"] + child_tid = ret["child_tid"] + self.reset_test_sequence() + + if kill_parent: + self.test_sequence.add_log_lines([ + # kill the process + "read packet: $vKill;{}#00".format(parent_pid), + "send packet: $OK#00", + ], True) + if kill_child: + self.test_sequence.add_log_lines([ + # kill the process + "read packet: $vKill;{}#00".format(child_pid), + "send packet: $OK#00", + ], True) + self.test_sequence.add_log_lines([ + # check child PID/TID + "read packet: $Hgp{}.{}#00".format(child_pid, child_tid), + "send packet: ${}#00".format("Eff" if kill_child else "OK"), + # check parent PID/TID + "read packet: $Hgp{}.{}#00".format(parent_pid, parent_tid), + "send packet: ${}#00".format("Eff" if kill_parent else "OK"), + ], True) + self.expect_gdbremote_sequence() + + @add_test_categories(["fork"]) + def test_vkill_child(self): + self.vkill_test(kill_child=True) + + @add_test_categories(["fork"]) + def test_vkill_parent(self): + self.vkill_test(kill_parent=True) + + @add_test_categories(["fork"]) + def test_vkill_both(self): + self.vkill_test(kill_parent=True, kill_child=True) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits