Index: lldb/include/lldb/Utility/StringExtractorGDBRemote.h =================================================================== --- lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -136,6 +136,7 @@ eServerPacketType_vAttachName, eServerPacketType_vCont, eServerPacketType_vCont_actions, // vCont? + eServerPacketType_vRun, eServerPacketType_stop_reason, // '?' 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 @@ -598,7 +598,8 @@ m_supports_qSymbol : 1, m_qSymbol_requests_done : 1, m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1, m_supports_jModulesInfo : 1, m_supports_vFileSize : 1, - m_supports_vFileMode : 1, m_supports_vFileExists : 1; + m_supports_vFileMode : 1, m_supports_vFileExists : 1, + m_supports_vRun : 1; /// Current gdb remote protocol process identifier for all other operations lldb::pid_t m_curr_pid = LLDB_INVALID_PROCESS_ID; 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 @@ -66,7 +66,7 @@ m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true), m_supports_vFileSize(true), m_supports_vFileMode(true), - m_supports_vFileExists(true), + m_supports_vFileExists(true), m_supports_vRun(true), m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(), m_hostname(), m_gdb_server_name(), m_default_packet_timeout(0), @@ -805,6 +805,33 @@ } } if (!argv.empty()) { + // try vRun first + if (m_supports_vRun) { + StreamString packet; + packet.PutCString("vRun"); + for (const char *arg : argv) { + packet.PutChar(';'); + packet.PutBytesAsRawHex8(arg, strlen(arg)); + } + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response) != + PacketResult::Success) + return -1; + + if (response.IsOKResponse()) + return 0; + if (!response.IsUnsupportedResponse()) { + uint8_t error = response.GetError(); + if (error) + return error; + return -1; + } + + m_supports_vRun = false; + } + + // fallback to A StreamString packet; packet.PutChar('A'); for (size_t i = 0, n = argv.size(); i < n; ++i) { Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -39,6 +39,8 @@ PacketResult Handle_A(StringExtractorGDBRemote &packet); + PacketResult Handle_vRun(StringExtractorGDBRemote &packet); + PacketResult Handle_qHostInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qProcessInfoPID(StringExtractorGDBRemote &packet); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -1077,6 +1077,38 @@ return SendErrorResponse(8); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerCommon::Handle_vRun( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + llvm::StringRef s = packet.GetStringRef(); + if (!s.consume_front("vRun;")) + return SendErrorResponse(8); + + llvm::SmallVector argv; + s.split(argv, ';'); + + for (llvm::StringRef hex_arg : argv) { + StringExtractor arg_ext{hex_arg}; + std::string arg; + arg_ext.GetHexByteString(arg); + m_process_launch_info.GetArguments().AppendArgument(arg); + LLDB_LOGF(log, "LLGSPacketHandler::%s added arg: \"%s\"", __FUNCTION__, + arg.c_str()); + } + + if (!argv.empty()) { + m_process_launch_info.GetExecutableFile().SetFile( + m_process_launch_info.GetArguments()[0].ref(), FileSpec::Style::native); + m_process_launch_error = LaunchProcess(); + if (m_process_launch_error.Success()) + return SendOKResponse(); + LLDB_LOG(log, "failed to launch exe: {0}", m_process_launch_error); + } + return SendErrorResponse(8); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qEcho( StringExtractorGDBRemote &packet) { Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -182,6 +182,9 @@ RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_vCont_actions, &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vRun, + &GDBRemoteCommunicationServerLLGS::Handle_vRun); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_x, &GDBRemoteCommunicationServerLLGS::Handle_memory_read); Index: lldb/source/Utility/StringExtractorGDBRemote.cpp =================================================================== --- lldb/source/Utility/StringExtractorGDBRemote.cpp +++ lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -363,6 +363,8 @@ return eServerPacketType_vCont; if (PACKET_MATCHES("vCont?")) return eServerPacketType_vCont_actions; + if (PACKET_STARTS_WITH("vRun;")) + return eServerPacketType_vRun; } break; case '_': Index: lldb/test/API/tools/lldb-server/TestLldbGdbServer.py =================================================================== --- lldb/test/API/tools/lldb-server/TestLldbGdbServer.py +++ lldb/test/API/tools/lldb-server/TestLldbGdbServer.py @@ -10,6 +10,9 @@ the initial set of tests implemented. """ +import binascii +import itertools + import unittest2 import gdbremote_testcase import lldbgdbserverutils @@ -1246,3 +1249,59 @@ # Make sure we read back what we wrote. self.assertEqual(read_value, expected_reg_values[thread_index]) thread_index += 1 + + def test_launch_via_A(self): + self.build() + exe_path = self.getBuildArtifact("a.out") + args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"] + hex_args = [binascii.b2a_hex(x.encode()).decode() for x in args] + + server = self.connect_to_debug_monitor() + self.assertIsNotNone(server) + self.do_handshake() + # NB: strictly speaking we should use %x here but this packet + # is deprecated, so no point in changing lldb-server's expectations + self.test_sequence.add_log_lines( + ["read packet: $A %d,0,%s,%d,1,%s,%d,2,%s,%d,3,%s#00" % + tuple(itertools.chain.from_iterable( + [(len(x), x) for x in hex_args])), + "send packet: $OK#00", + "read packet: $C00#00", + "send packet: $W00#00"], + True) + context = self.expect_gdbremote_sequence() + self.assertEqual(context["O_content"], + b'arg1\r\narg2\r\narg3\r\n') + + def test_launch_via_vRun(self): + self.build() + exe_path = self.getBuildArtifact("a.out") + args = [exe_path, "stderr:arg1", "stderr:arg2", "stderr:arg3"] + hex_args = [binascii.b2a_hex(x.encode()).decode() for x in args] + + server = self.connect_to_debug_monitor() + self.assertIsNotNone(server) + self.do_handshake() + self.test_sequence.add_log_lines( + ["read packet: $vRun;%s;%s;%s;%s#00" % tuple(hex_args), + "send packet: $OK#00", + "read packet: $C00#00", + "send packet: $W00#00"], + True) + context = self.expect_gdbremote_sequence() + + def test_launch_via_vRun_no_args(self): + self.build() + exe_path = self.getBuildArtifact("a.out") + hex_path = binascii.b2a_hex(exe_path.encode()).decode() + + server = self.connect_to_debug_monitor() + self.assertIsNotNone(server) + self.do_handshake() + self.test_sequence.add_log_lines( + ["read packet: $vRun;%s#00" % (hex_path,), + "send packet: $OK#00", + "read packet: $C00#00", + "send packet: $W00#00"], + True) + self.expect_gdbremote_sequence()