diff options
4 files changed, 178 insertions, 2 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 44475981bdd..585b28ecc30 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -422,6 +422,10 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec, case StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState: packet_result = Handle_QRestoreRegisterState (packet); break; + + case StringExtractorGDBRemote::eServerPacketType_vAttach: + packet_result = Handle_vAttach (packet); + break; } } else @@ -4111,6 +4115,44 @@ GDBRemoteCommunicationServer::Handle_QRestoreRegisterState (StringExtractorGDBRe return SendOKResponse(); } +GDBRemoteCommunicationServer::PacketResult +GDBRemoteCommunicationServer::Handle_vAttach (StringExtractorGDBRemote &packet) +{ + Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // We don't support if we're not llgs. + if (!IsGdbServer()) + return SendUnimplementedResponse ("only supported for lldb-gdbserver"); + + // Consume the ';' after vAttach. + packet.SetFilePos (strlen ("vAttach")); + if (!packet.GetBytesLeft () || packet.GetChar () != ';') + return SendIllFormedResponse (packet, "vAttach missing expected ';'"); + + // Grab the PID to which we will attach (assume hex encoding). + lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); + + // Attempt to attach. + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); + + Error error = AttachToProcess (pid); + + if (error.Fail ()) + { + if (log) + log->Printf ("GDBRemoteCommunicationServer::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); + return SendErrorResponse (0x01); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState (m_debugged_process_sp->GetState (), true); + + return PacketResult::Success; +} + void GDBRemoteCommunicationServer::FlushInferiorOutput () { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index d20cc2ae8f7..412b591e6ec 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -457,6 +457,9 @@ protected: PacketResult Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet); + PacketResult + Handle_vAttach (StringExtractorGDBRemote &packet); + void SetCurrentThreadID (lldb::tid_t tid); diff --git a/lldb/test/tools/lldb-gdbserver/TestGdbRemoteAttach.py b/lldb/test/tools/lldb-gdbserver/TestGdbRemoteAttach.py new file mode 100644 index 00000000000..fd16f3f4681 --- /dev/null +++ b/lldb/test/tools/lldb-gdbserver/TestGdbRemoteAttach.py @@ -0,0 +1,122 @@ +import gdbremote_testcase +import lldbgdbserverutils +import unittest2 + +from lldbtest import * + +class TestGdbRemoteAttach(gdbremote_testcase.GdbRemoteTestCaseBase): + + def attach_with_vAttach(self): + # Start the inferior, start the debug monitor, nothing is attached yet. + procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:60"]) + self.assertIsNotNone(procs) + + # Make sure the target process has been launched. + inferior = procs.get("inferior") + self.assertIsNotNone(inferior) + self.assertTrue(inferior.pid > 0) + self.assertTrue(lldbgdbserverutils.process_is_running(inferior.pid, True)) + + # Add attach packets. + self.test_sequence.add_log_lines([ + # Do the attach. + "read packet: $vAttach;{:x}#00".format(inferior.pid), + # Expect a stop notification from the attach. + { "direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$", "capture":{1:"stop_signal_hex"} }, + ], True) + self.add_process_info_collection_packets() + + # Run the stream + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Gather process info response + process_info = self.parse_process_info_response(context) + self.assertIsNotNone(process_info) + + # Ensure the process id matches what we expected. + pid_text = process_info.get('pid', None) + self.assertIsNotNone(pid_text) + reported_pid = int(pid_text, base=16) + self.assertEqual(reported_pid, inferior.pid) + + @debugserver_test + @dsym_test + def test_attach_with_vAttach_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_attach_manually() + self.attach_with_vAttach() + + @llgs_test + @dwarf_test + def test_attach_with_vAttach_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_attach_manually() + self.attach_with_vAttach() + + +if __name__ == '__main__': + unittest2.main() +import gdbremote_testcase +import lldbgdbserverutils +import unittest2 + +from lldbtest import * + +class TestGdbRemoteAttach(gdbremote_testcase.GdbRemoteTestCaseBase): + + def attach_with_vAttach(self): + # Start the inferior, start the debug monitor, nothing is attached yet. + procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:60"]) + self.assertIsNotNone(procs) + + # Make sure the target process has been launched. + inferior = procs.get("inferior") + self.assertIsNotNone(inferior) + self.assertTrue(inferior.pid > 0) + self.assertTrue(lldbgdbserverutils.process_is_running(inferior.pid, True)) + + # Add attach packets. + self.test_sequence.add_log_lines([ + # Do the attach. + "read packet: $vAttach;{:x}#00".format(inferior.pid), + # Expect a stop notification from the attach. + { "direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})[^#]*#[0-9a-fA-F]{2}$", "capture":{1:"stop_signal_hex"} }, + ], True) + self.add_process_info_collection_packets() + + # Run the stream + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Gather process info response + process_info = self.parse_process_info_response(context) + self.assertIsNotNone(process_info) + + # Ensure the process id matches what we expected. + pid_text = process_info.get('pid', None) + self.assertIsNotNone(pid_text) + reported_pid = int(pid_text, base=16) + self.assertEqual(reported_pid, inferior.pid) + + @debugserver_test + @dsym_test + def test_attach_with_vAttach_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_attach_manually() + self.attach_with_vAttach() + + @llgs_test + @dwarf_test + def test_attach_with_vAttach_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_attach_manually() + self.attach_with_vAttach() + + +if __name__ == '__main__': + unittest2.main() diff --git a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py index 8c473d586de..15aca47d046 100644 --- a/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py +++ b/lldb/test/tools/lldb-gdbserver/gdbremote_testcase.py @@ -32,7 +32,11 @@ class GdbRemoteTestCaseBase(TestBase): _LOGGING_LEVEL = logging.WARNING # _LOGGING_LEVEL = logging.DEBUG + # Start the inferior separately, attach to the inferior on the stub command line. _STARTUP_ATTACH = "attach" + # Start the inferior separately, start the stub without attaching, allow the test to attach to the inferior however it wants (e.g. $vAttach;pid). + _STARTUP_ATTACH_MANUALLY = "attach_manually" + # Start the stub, and launch the inferior with an $A packet via the initial packet stream. _STARTUP_LAUNCH = "launch" # GDB Signal numbers that are not target-specific used for common exceptions @@ -179,6 +183,9 @@ class GdbRemoteTestCaseBase(TestBase): def set_inferior_startup_attach(self): self._inferior_startup = self._STARTUP_ATTACH + def set_inferior_startup_attach_manually(self): + self._inferior_startup = self._STARTUP_ATTACH_MANUALLY + def get_debug_monitor_command_line(self, attach_pid=None): commandline = "{}{} localhost:{}".format(self.debug_monitor_exe, self.debug_monitor_extra_args, self.port) if attach_pid: @@ -314,12 +321,14 @@ class GdbRemoteTestCaseBase(TestBase): inferior = None attach_pid = None - if self._inferior_startup == self._STARTUP_ATTACH: + if self._inferior_startup == self._STARTUP_ATTACH or self._inferior_startup == self._STARTUP_ATTACH_MANUALLY: # Launch the process that we'll use as the inferior. inferior = self.launch_process_for_attach(inferior_args=inferior_args, sleep_seconds=inferior_sleep_seconds) self.assertIsNotNone(inferior) self.assertTrue(inferior.pid > 0) - attach_pid = inferior.pid + if self._inferior_startup == self._STARTUP_ATTACH: + # In this case, we want the stub to attach via the command line, so set the command line attach pid here. + attach_pid = inferior.pid # Launch the debug monitor stub, attaching to the inferior. server = self.connect_to_debug_monitor(attach_pid=attach_pid) |

