diff options
author | Tamas Berghammer <tberghammer@google.com> | 2015-12-08 14:08:19 +0000 |
---|---|---|
committer | Tamas Berghammer <tberghammer@google.com> | 2015-12-08 14:08:19 +0000 |
commit | ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5 (patch) | |
tree | 47ae8040ff8d1ce1485f2789a848bd181403c605 /lldb | |
parent | 59d092f883a44c35822f3038128a11452801c7a4 (diff) | |
download | bcm5719-llvm-ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5.tar.gz bcm5719-llvm-ccd6cffba3545bec41864b0c3fa4ca7cc3e854c5.zip |
Modify "platform connect" to connect to processes as well
The standard remote debugging workflow with gdb is to start the
application on the remote host under gdbserver (e.g.: gdbserver :5039
a.out) and then connect to it with gdb.
The same workflow is supported by debugserver/lldb-gdbserver with a very
similar syntax but to access all features of lldb we need to be
connected also to an lldb-platform instance running on the target.
Before this change this had to be done manually with starting a separate
lldb-platform on the target machine and then connecting to it with lldb
before connecting to the process.
This change modifies the behavior of "platform connect" with
automatically connecting to the process instance if it was started by
the remote platform. With this command replacing gdbserver in a gdb
based worflow is usually as simple as replacing the command to execute
gdbserver with executing lldb-platform.
Differential revision: http://reviews.llvm.org/D14952
llvm-svn: 255016
Diffstat (limited to 'lldb')
25 files changed, 576 insertions, 151 deletions
diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt index d12da02dc56..f9537719c90 100644 --- a/lldb/docs/lldb-gdb-remote.txt +++ b/lldb/docs/lldb-gdb-remote.txt @@ -1597,3 +1597,29 @@ On MacOSX with debugserver, we expedite the frame pointer backchain for a thread (up to 256 entries) by reading 2 pointers worth of bytes at the frame pointer (for the previous FP and PC), and follow the backchain. Most backtraces on MacOSX and iOS now don't require us to read any memory! + +//---------------------------------------------------------------------- +// "qQueryGDBServer" +// +// BRIEF +// Ask the platform for the list of gdbservers we have to connect +// +// PRIORITY TO IMPLEMENT +// Low. The packet is required to support connecting to gdbserver started +// by the platform instance automatically. +//---------------------------------------------------------------------- + +If the remote platform automatically started one or more gdbserver instance (without +lldb asking it) then it have to return the list of port number or socket name for +each of them what can be used by lldb to connect to those instances. + +The data in this packet is a JSON array of JSON objects with the following keys: +"port": <the port number to connect> (optional) +"socket_name": <the name of the socket to connect> (optional) + +Example packet: +[ + { "port": 1234 }, + { "port": 5432 }, + { "socket_name": "foo" } +] diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 9649ccd6a76..53c17a6a66c 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -487,6 +487,13 @@ class ModuleCache; Target *target, // Can be nullptr, if nullptr create a new target, else use existing one Error &error); + virtual lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error); + //------------------------------------------------------------------ /// Attach to an existing process using a process ID. /// @@ -1034,6 +1041,25 @@ class ModuleCache; virtual Error UnloadImage (lldb_private::Process* process, uint32_t image_token); + //------------------------------------------------------------------ + /// Connect to all processes waiting for a debugger to attach + /// + /// If the platform have a list of processes waiting for a debugger + /// to connect to them then connect to all of these pending processes. + /// + /// @param[in] debugger + /// The debugger used for the connect. + /// + /// @param[out] error + /// If an error occurred during the connect then this object will + /// contain the error message. + /// + /// @return + /// The number of processes we are succesfully connected to. + //------------------------------------------------------------------ + virtual size_t + ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error); + protected: bool m_is_host; // Set to true when we are able to actually set the OS version while diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 2922445b9a4..4b0fb37ef14 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1115,7 +1115,7 @@ def skipIfLinuxClang(func): # @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 # TODO: refactor current code, to make skipIfxxx functions to call this function -def skipIf(bugnumber=None, oslist=None, compiler=None, compiler_version=None, archs=None, debug_info=None, swig_version=None, py_version=None): +def skipIf(bugnumber=None, oslist=None, compiler=None, compiler_version=None, archs=None, debug_info=None, swig_version=None, py_version=None, remote=None): def fn(self): oslist_passes = oslist is None or self.getPlatform() in oslist compiler_passes = compiler is None or (compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version)) @@ -1123,13 +1123,15 @@ def skipIf(bugnumber=None, oslist=None, compiler=None, compiler_version=None, ar debug_info_passes = debug_info is None or self.debug_info in debug_info swig_version_passes = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) py_version_passes = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) + remote_passes = (remote is None) or (remote == (lldb.remote_platform is not None)) return (oslist_passes and compiler_passes and arch_passes and debug_info_passes and swig_version_passes and - py_version_passes) + py_version_passes and + remote_passes) local_vars = locals() args = [x for x in inspect.getargspec(skipIf).args] diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py index f796c6d02ed..113e01e36ba 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -147,29 +147,30 @@ class GdbRemoteTestCaseBase(TestBase): return stub_port + def run_shell_cmd(self, cmd): + platform = self.dbg.GetSelectedPlatform() + shell_cmd = lldb.SBPlatformShellCommand(cmd) + err = platform.Run(shell_cmd) + if err.Fail() or shell_cmd.GetStatus(): + m = "remote_platform.RunShellCommand('%s') failed:\n" % cmd + m += ">>> return code: %d\n" % shell_cmd.GetStatus() + if err.Fail(): + m += ">>> %s\n" % str(err).strip() + m += ">>> %s\n" % (shell_cmd.GetOutput() or + "Command generated no output.") + raise Exception(m) + return shell_cmd.GetOutput().strip() + def init_llgs_test(self, use_named_pipe=True): if lldb.remote_platform: - def run_shell_cmd(cmd): - platform = self.dbg.GetSelectedPlatform() - shell_cmd = lldb.SBPlatformShellCommand(cmd) - err = platform.Run(shell_cmd) - if err.Fail() or shell_cmd.GetStatus(): - m = "remote_platform.RunShellCommand('%s') failed:\n" % cmd - m += ">>> return code: %d\n" % shell_cmd.GetStatus() - if err.Fail(): - m += ">>> %s\n" % str(err).strip() - m += ">>> %s\n" % (shell_cmd.GetOutput() or - "Command generated no output.") - raise Exception(m) - return shell_cmd.GetOutput().strip() # Remote platforms don't support named pipe based port negotiation use_named_pipe = False # Grab the ppid from /proc/[shell pid]/stat - shell_stat = run_shell_cmd("cat /proc/$$/stat") + shell_stat = self.run_shell_cmd("cat /proc/$$/stat") # [pid] ([executable]) [state] [*ppid*] pid = re.match(r"^\d+ \(.+\) . (\d+)", shell_stat).group(1) - ls_output = run_shell_cmd("ls -l /proc/%s/exe" % pid) + ls_output = self.run_shell_cmd("ls -l /proc/%s/exe" % pid) exe = ls_output.split()[-1] # If the binary has been deleted, the link name has " (deleted)" appended. diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile new file mode 100644 index 00000000000..314f1cb2f07 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py new file mode 100644 index 00000000000..676c154e55d --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py @@ -0,0 +1,55 @@ +from __future__ import print_function + +import gdbremote_testcase +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class TestPlatformProcessConnect(gdbremote_testcase.GdbRemoteTestCaseBase): + mydir = TestBase.compute_mydir(__file__) + + @llgs_test + @no_debug_info_test + @skipIf(remote=False) + def test_platform_process_connect(self): + self.build() + self.init_llgs_test(False) + + working_dir = lldb.remote_platform.GetWorkingDirectory() + err = lldb.remote_platform.Put(lldb.SBFileSpec(os.path.join(os.getcwd(), "a.out")), + lldb.SBFileSpec(os.path.join(working_dir, "a.out"))) + if err.Fail(): + raise RuntimeError("Unable copy '%s' to '%s'.\n>>> %s" % (f, wd, err.GetCString())) + + port_file = "%s/port" % working_dir + commandline_args = ["platform", "--listen", "*:0", "--socket-file", port_file, "--", "%s/a.out" % working_dir, "foo"] + self.spawnSubprocess(self.debug_monitor_exe, commandline_args, install_remote=False) + self.addTearDownHook(self.cleanupSubprocesses) + new_port = self.run_shell_cmd("while [ ! -f %s ]; do sleep 0.25; done && cat %s" % (port_file, port_file)) + + new_debugger = lldb.SBDebugger.Create() + new_debugger.SetAsync(False) + def del_debugger(): + del new_debugger + self.addTearDownHook(del_debugger) + + new_platform = lldb.SBPlatform(lldb.remote_platform.GetName()) + new_debugger.SetSelectedPlatform(new_platform) + new_interpreter = new_debugger.GetCommandInterpreter() + + m = re.search("(.*):[0-9]+", configuration.lldb_platform_url) + command = "platform connect %s:%s" % (m.group(1), new_port) + result = lldb.SBCommandReturnObject() + new_interpreter.HandleCommand(command, result) + self.assertTrue(result.Succeeded(), "platform process connect failed: %s" % result.GetOutput()) + + target = new_debugger.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetThreadAtIndex(0) + + breakpoint = target.BreakpointCreateByName("main") + process.Continue() + + frame = thread.GetFrameAtIndex(0) + self.assertEqual(frame.GetFunction().GetName(), "main") + self.assertEqual(frame.FindVariable("argc").GetValueAsSigned(), 2) + process.Continue() diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp new file mode 100644 index 00000000000..70ae5094fde --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp @@ -0,0 +1,7 @@ +#include <cstdio> + +int main (int argc, char **argv) +{ + printf("argc: %d\n", argc); + return argv[0][0]; +} diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index 00e291192dc..aad8bea692e 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -409,12 +409,19 @@ protected: if (error.Success()) { platform_sp->GetStatus (ostrm); - result.SetStatus (eReturnStatusSuccessFinishResult); + result.SetStatus (eReturnStatusSuccessFinishResult); + + platform_sp->ConnectToWaitingProcesses(m_interpreter.GetDebugger(), error); + if (error.Fail()) + { + result.AppendError (error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } } else { result.AppendErrorWithFormat ("%s\n", error.AsCString()); - result.SetStatus (eReturnStatusFailed); + result.SetStatus (eReturnStatusFailed); } } else diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 293b762295f..b7f894f6dcf 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -1051,78 +1051,46 @@ protected: bool DoExecute (Args& command, CommandReturnObject &result) override { - - TargetSP target_sp (m_interpreter.GetDebugger().GetSelectedTarget()); - Error error; - Process *process = m_exe_ctx.GetProcessPtr(); - if (process) + if (command.GetArgumentCount() != 1) { - if (process->IsAlive()) - { - result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n", - process->GetID()); - result.SetStatus (eReturnStatusFailed); - return false; - } + result.AppendErrorWithFormat ("'%s' takes exactly one argument:\nUsage: %s\n", + m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; } + - if (!target_sp) + Process *process = m_exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) { - // If there isn't a current target create one. - - error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(), - NULL, - NULL, - false, - NULL, // No platform options - target_sp); - if (!target_sp || error.Fail()) - { - result.AppendError(error.AsCString("Error creating target")); - result.SetStatus (eReturnStatusFailed); - return false; - } - m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target_sp.get()); + result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n", + process->GetID()); + result.SetStatus (eReturnStatusFailed); + return false; } - - if (command.GetArgumentCount() == 1) - { - const char *plugin_name = NULL; - if (!m_options.plugin_name.empty()) - plugin_name = m_options.plugin_name.c_str(); - const char *remote_url = command.GetArgumentAtIndex(0); - process = target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get(); - - if (process) - { - error = process->ConnectRemote (process->GetTarget().GetDebugger().GetOutputFile().get(), remote_url); + const char *plugin_name = nullptr; + if (!m_options.plugin_name.empty()) + plugin_name = m_options.plugin_name.c_str(); - if (error.Fail()) - { - result.AppendError(error.AsCString("Remote connect failed")); - result.SetStatus (eReturnStatusFailed); - target_sp->DeleteCurrentProcess(); - return false; - } - } - else - { - result.AppendErrorWithFormat ("Unable to find process plug-in for remote URL '%s'.\nPlease specify a process plug-in name with the --plugin option, or specify an object file using the \"file\" command.\n", - remote_url); - result.SetStatus (eReturnStatusFailed); - } - } - else + Error error; + Debugger& debugger = m_interpreter.GetDebugger(); + PlatformSP platform_sp = m_interpreter.GetPlatform(true); + ProcessSP process_sp = platform_sp->ConnectProcess(command.GetArgumentAtIndex(0), + plugin_name, + debugger, + debugger.GetSelectedTarget().get(), + error); + if (error.Fail() || process_sp == nullptr) { - result.AppendErrorWithFormat ("'%s' takes exactly one argument:\nUsage: %s\n", - m_cmd_name.c_str(), - m_cmd_syntax.c_str()); + result.AppendError(error.AsCString("Error connecting to the process")); result.SetStatus (eReturnStatusFailed); + return false; } - return result.Succeeded(); + return true; } - + CommandOptions m_options; }; diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index 9a55be64e4d..3d91dd6b7a3 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -223,3 +223,53 @@ PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid, return error; } + +lldb::ProcessSP +PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + // We don't have the pid of the remote gdbserver when it isn't started by us but we still want + // to store the list of port forwards we set up in our port forward map. Generate a fake pid for + // these cases what won't collide with any other valid pid on android. + static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL; + + int remote_port; + std::string scheme, host, path; + if (!UriParser::Parse(connect_url, scheme, host, remote_port, path)) + { + error.SetErrorStringWithFormat("Invalid URL: %s", connect_url); + return nullptr; + } + + std::string new_connect_url; + error = MakeConnectURL(s_remote_gdbserver_fake_pid--, + (remote_port < 0) ? 0 : remote_port, + path.c_str(), + new_connect_url); + if (error.Fail()) + return nullptr; + + return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(), + plugin_name, + debugger, + target, + error); +} + +size_t +PlatformAndroidRemoteGDBServer::ConnectToWaitingProcesses(Debugger& debugger, Error& error) +{ + std::vector<std::string> connection_urls; + GetPendingGdbServerList(connection_urls); + + for (size_t i = 0; i < connection_urls.size(); ++i) + { + ConnectProcess(connection_urls[i].c_str(), nullptr, debugger, nullptr, error); + if (error.Fail()) + return i; // We already connected to i process succsessfully + } + return connection_urls.size(); +} diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h index 84530ade935..3d2653812de 100644 --- a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -39,6 +39,16 @@ public: Error DisconnectRemote () override; + lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) override; + + size_t + ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; + protected: std::string m_device_id; std::map<lldb::pid_t, uint16_t> m_port_forwards; diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 6983e3d46de..c7564655a11 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -986,6 +986,23 @@ PlatformPOSIX::UnloadImage (lldb_private::Process* process, uint32_t image_token process->ResetImageToken(image_token); } return Error(); +} + +lldb::ProcessSP +PlatformPOSIX::ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->ConnectProcess(connect_url, + plugin_name, + debugger, + target, + error); + + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); } const char* @@ -998,3 +1015,11 @@ PlatformPOSIX::GetLibdlFunctionDeclarations() const extern "C" char* dlerror(void); )"; } + +size_t +PlatformPOSIX::ConnectToWaitingProcesses(Debugger& debugger, Error& error) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); + return Platform::ConnectToWaitingProcesses(debugger, error); +} diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 6dabeed0b18..60f6207d140 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -181,6 +181,16 @@ public: lldb_private::Error UnloadImage (lldb_private::Process* process, uint32_t image_token) override; + lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) override; + + size_t + ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; + protected: std::unique_ptr<lldb_private::OptionGroupOptions> m_options; lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote POSIX-compliant OS diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index ea83027bfe5..f16ea017676 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" @@ -984,3 +985,34 @@ PlatformRemoteGDBServer::MakeUrl(const char* scheme, result.Write(path, strlen(path)); return result.GetString(); } + +lldb::ProcessSP +PlatformRemoteGDBServer::ConnectProcess(const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + if (!IsRemote() || !IsConnected()) + { + error.SetErrorString("Not connected to remote gdb server"); + return nullptr; + } + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); +} + +size_t +PlatformRemoteGDBServer::GetPendingGdbServerList(std::vector<std::string>& connection_urls) +{ + std::vector<std::pair<uint16_t, std::string>> remote_servers; + m_gdb_client.QueryGDBServer(remote_servers); + for (const auto& gdbserver : remote_servers) + { + const char* socket_name_cstr = gdbserver.second.empty() ? nullptr : gdbserver.second.c_str(); + connection_urls.emplace_back(MakeGdbServerUrl(m_platform_scheme, + m_platform_hostname, + gdbserver.first, + socket_name_cstr)); + } + return connection_urls.size(); +} diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index ffba509bbfb..61136f1185e 100644 --- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -217,6 +217,16 @@ public: const lldb::UnixSignalsSP & GetRemoteUnixSignals() override; + lldb::ProcessSP + ConnectProcess (const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) override; + + virtual size_t + GetPendingGdbServerList(std::vector<std::string>& connection_urls); + protected: process_gdb_remote::GDBRemoteCommunicationClient m_gdb_client; std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index ea95298dd5c..2ea1f206008 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1115,7 +1115,8 @@ Error GDBRemoteCommunication::StartDebugserverProcess (const char *url, Platform *platform, ProcessLaunchInfo &launch_info, - uint16_t *port) + uint16_t *port, + const Args& inferior_args) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -1328,6 +1329,20 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, } } while (has_env_var); + if (inferior_args.GetArgumentCount() > 0) + { + debugserver_args.AppendArgument ("--"); + debugserver_args.AppendArguments (inferior_args); + } + + // Copy the current environment to the gdbserver/debugserver instance + StringList env; + if (Host::GetEnvironment(env)) + { + for (size_t i = 0; i < env.GetSize(); ++i) + launch_info.GetEnvironmentEntries().AppendArgument(env[i].c_str()); + } + // Close STDIN, STDOUT and STDERR. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index ccc8ef1b247..2a01bcec260 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -25,6 +25,7 @@ #include "lldb/Host/Mutex.h" #include "lldb/Host/Predicate.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Interpreter/Args.h" #include "Utility/StringExtractorGDBRemote.h" @@ -168,7 +169,8 @@ public: StartDebugserverProcess(const char *url, Platform *platform, // If non nullptr, then check with the platform for the GDB server binary if it can't be located ProcessLaunchInfo &launch_info, - uint16_t *port); + uint16_t *port, + const Args& inferior_args = Args()); void DumpHistory(Stream &strm); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 7b193f0bffb..5c7f6caca51 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3383,6 +3383,43 @@ GDBRemoteCommunicationClient::LaunchGDBServer (const char *remote_accept_hostnam return false; } +size_t +GDBRemoteCommunicationClient::QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls) +{ + connection_urls.clear(); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != PacketResult::Success) + return 0; + + StructuredData::ObjectSP data = StructuredData::ParseJSON(response.GetStringRef()); + if (!data) + return 0; + + StructuredData::Array* array = data->GetAsArray(); + if (!array) + return 0; + + for (size_t i = 0, count = array->GetSize(); i < count; ++i) + { + StructuredData::Dictionary* element = nullptr; + if (!array->GetItemAtIndexAsDictionary(i, element)) + continue; + + uint16_t port = 0; + if (StructuredData::ObjectSP port_osp = element->GetValueForKey(llvm::StringRef("port"))) + port = port_osp->GetIntegerValue(0); + + std::string socket_name; + if (StructuredData::ObjectSP socket_name_osp = element->GetValueForKey(llvm::StringRef("socket_name"))) + socket_name = socket_name_osp->GetStringValue(); + + if (port != 0 || !socket_name.empty()) + connection_urls.emplace_back(port, socket_name); + } + return connection_urls.size(); +} + bool GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 2c41d199ca5..d2df214d0db 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -119,7 +119,10 @@ public: lldb::pid_t &pid, uint16_t &port, std::string &socket_name); - + + size_t + QueryGDBServer (std::vector<std::pair<uint16_t, std::string>>& connection_urls); + bool KillSpawnedProcess (lldb::pid_t pid); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 19a29b4654a..022c558352b 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -34,6 +34,7 @@ #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/JSON.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" @@ -54,7 +55,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const m_spawned_pids_mutex (Mutex::eMutexTypeRecursive), m_platform_sp (Platform::GetHostPlatform ()), m_port_map (), - m_port_offset(0) + m_port_offset(0), + m_pending_gdb_server{ LLDB_INVALID_PROCESS_ID, 0, "" } { RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, &GDBRemoteCommunicationServerPlatform::Handle_qC); @@ -62,6 +64,8 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(const &GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer, &GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qQueryGDBServer, + &GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qKillSpawnedProcess, &GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, @@ -90,38 +94,16 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() { } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +Error +GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& args, + std::string hostname, + lldb::pid_t& pid, + uint16_t& port, + std::string& socket_name) { -#ifdef _WIN32 - return SendErrorResponse(9); -#else - // Spawn a local debugserver as a platform so we can then attach or launch - // a process... - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); - - // Sleep and wait a bit for debugserver to start to listen... - ConnectionFileDescriptor file_conn; - std::string hostname; - // TODO: /tmp/ should not be hardcoded. User might want to override /tmp - // with the TMPDIR environment variable - packet.SetFilePos(::strlen ("qLaunchGDBServer;")); - std::string name; - std::string value; - uint16_t port = UINT16_MAX; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("host") == 0) - hostname.swap(value); - else if (name.compare ("port") == 0) - port = StringConvert::ToUInt32(value.c_str(), 0, 0); - } if (port == UINT16_MAX) port = GetNextAvailablePort(); - + // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). @@ -132,6 +114,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD ProcessLaunchInfo debugserver_launch_info; if (hostname.empty()) hostname = "127.0.0.1"; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) log->Printf("Launching debugserver with: %s:%u...", hostname.c_str(), port); @@ -148,11 +132,8 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD UNUSED_IF_ASSERT_DISABLED(ok); assert(ok); - std::string socket_name; std::ostringstream url; - uint16_t* port_ptr = &port; - url << m_socket_scheme << "://"; if (m_socket_protocol == Socket::ProtocolTcp) url << platform_ip << ":" << port; else @@ -165,56 +146,108 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGD Error error = StartDebugserverProcess (url.str().c_str(), nullptr, debugserver_launch_info, - port_ptr); - - lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); - + port_ptr, + args); - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + pid = debugserver_launch_info.GetProcessID(); + if (pid != LLDB_INVALID_PROCESS_ID) { Mutex::Locker locker (m_spawned_pids_mutex); - m_spawned_pids.insert(debugserver_pid); + m_spawned_pids.insert(pid); if (port > 0) - AssociatePortWithProcess(port, debugserver_pid); + AssociatePortWithProcess(port, pid); } else { if (port > 0) - FreePort (port); + FreePort(port); } + return error; +} - if (error.Success()) +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet) +{ +#ifdef _WIN32 + return SendErrorResponse(9); +#else + // Spawn a local debugserver as a platform so we can then attach or launch + // a process... + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf ("GDBRemoteCommunicationServerPlatform::%s() called", __FUNCTION__); + + ConnectionFileDescriptor file_conn; + std::string hostname; + packet.SetFilePos(::strlen ("qLaunchGDBServer;")); + std::string name; + std::string value; + uint16_t port = UINT16_MAX; + while (packet.GetNameColonValue(name, value)) + { + if (name.compare ("host") == 0) + hostname.swap(value); + else if (name.compare ("port") == 0) + port = StringConvert::ToUInt32(value.c_str(), 0, 0); + } + + lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; + std::string socket_name; + Error error = LaunchGDBServer(Args(), hostname, debugserver_pid, port, socket_name); + if (error.Fail()) { if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); + log->Printf("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + return SendErrorResponse(9); + } - StreamGDBRemote response; - response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - if (!socket_name.empty()) - { - response.PutCString("socket_name:"); - response.PutCStringAsRawHex8(socket_name.c_str()); - response.PutChar(';'); - } + if (log) + log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launched successfully as pid %" PRIu64, __FUNCTION__, debugserver_pid); - PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); - if (packet_result != PacketResult::Success) - { - if (debugserver_pid != LLDB_INVALID_PROCESS_ID) - ::kill (debugserver_pid, SIGINT); - } - return packet_result; + StreamGDBRemote response; + response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + if (!socket_name.empty()) + { + response.PutCString("socket_name:"); + response.PutCStringAsRawHex8(socket_name.c_str()); + response.PutChar(';'); } - else + + PacketResult packet_result = SendPacketNoLock(response.GetData(), response.GetSize()); + if (packet_result != PacketResult::Success) { - if (log) - log->Printf ("GDBRemoteCommunicationServerPlatform::%s() debugserver launch failed: %s", __FUNCTION__, error.AsCString ()); + if (debugserver_pid != LLDB_INVALID_PROCESS_ID) + ::kill (debugserver_pid, SIGINT); } - return SendErrorResponse (9); + return packet_result; #endif } GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qQueryGDBServer (StringExtractorGDBRemote &packet) +{ + if (m_pending_gdb_server.pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(4); + + JSONObject::SP server_sp = std::make_shared<JSONObject>(); + server_sp->SetObject("port", std::make_shared<JSONNumber>(m_pending_gdb_server.port)); + if (!m_pending_gdb_server.socket_name.empty()) + server_sp->SetObject("socket_name", + std::make_shared<JSONString>(m_pending_gdb_server.socket_name.c_str())); + + JSONArray server_list; + server_list.AppendObject(server_sp); + + StreamGDBRemote response; + server_list.Write(response); + + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); + return SendPacketNoLock(escaped_response.GetData(), escaped_response.GetSize()); +} + +GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("qKillSpawnedProcess:")); @@ -553,7 +586,17 @@ GDBRemoteCommunicationServerPlatform::GetDomainSocketPath(const char* prefix) } void -GDBRemoteCommunicationServerPlatform::SetPortOffset (uint16_t port_offset) +GDBRemoteCommunicationServerPlatform::SetPortOffset(uint16_t port_offset) { m_port_offset = port_offset; } + +void +GDBRemoteCommunicationServerPlatform::SetPendingGdbServer(lldb::pid_t pid, + uint16_t port, + const std::string& socket_name) +{ + m_pending_gdb_server.pid = pid; + m_pending_gdb_server.port = port; + m_pending_gdb_server.socket_name = socket_name; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index 6e8f5b06e16..1fe7207d2bc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -66,6 +66,19 @@ public: void SetPortOffset (uint16_t port_offset); + void + SetInferiorArguments (const lldb_private::Args& args); + + Error + LaunchGDBServer(const lldb_private::Args& args, + std::string hostname, + lldb::pid_t& pid, + uint16_t& port, + std::string& socket_name); + + void + SetPendingGdbServer(lldb::pid_t pid, uint16_t port, const std::string& socket_name); + protected: const Socket::SocketProtocol m_socket_protocol; const std::string m_socket_scheme; @@ -75,11 +88,15 @@ protected: PortMap m_port_map; uint16_t m_port_offset; + struct { lldb::pid_t pid; uint16_t port; std::string socket_name; } m_pending_gdb_server; PacketResult Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet); PacketResult + Handle_qQueryGDBServer (StringExtractorGDBRemote &packet); + + PacketResult Handle_qKillSpawnedProcess (StringExtractorGDBRemote &packet); PacketResult diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 8a82f5e609f..5077ca23bf7 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -26,6 +26,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredData.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" @@ -2040,3 +2041,49 @@ Platform::UnloadImage(lldb_private::Process* process, uint32_t image_token) { return Error("UnloadImage is not supported on the current platform"); } + +lldb::ProcessSP +Platform::ConnectProcess(const char* connect_url, + const char* plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) +{ + error.Clear(); + + if (!target) + { + TargetSP new_target_sp; + error = debugger.GetTargetList().CreateTarget(debugger, + nullptr, + nullptr, + false, + nullptr, + new_target_sp); + target = new_target_sp.get(); + } + + if (!target || error.Fail()) + return nullptr; + + debugger.GetTargetList().SetSelectedTarget(target); + + lldb::ProcessSP process_sp = target->CreateProcess(debugger.GetListener(), + plugin_name, + nullptr); + if (!process_sp) + return nullptr; + + error = process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url); + if (error.Fail()) + return nullptr; + + return process_sp; +} + +size_t +Platform::ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) +{ + error.Clear(); + return 0; +} diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp index 7c09b7a5d04..56df0be21ed 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -163,12 +163,12 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'K': if (PACKET_STARTS_WITH ("qKillSpawnedProcess")) return eServerPacketType_qKillSpawnedProcess; break; - + case 'L': if (PACKET_STARTS_WITH ("qLaunchGDBServer")) return eServerPacketType_qLaunchGDBServer; if (PACKET_MATCHES ("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess; break; - + case 'M': if (PACKET_STARTS_WITH ("qMemoryRegionInfo:")) return eServerPacketType_qMemoryRegionInfo; if (PACKET_MATCHES ("qMemoryRegionInfo")) return eServerPacketType_qMemoryRegionInfoSupported; @@ -182,7 +182,11 @@ StringExtractorGDBRemote::GetServerPacketType () const if (PACKET_STARTS_WITH ("qPlatform_chmod:")) return eServerPacketType_qPlatform_chmod; if (PACKET_MATCHES ("qProcessInfo")) return eServerPacketType_qProcessInfo; break; - + + case 'Q': + if (PACKET_MATCHES ("qQueryGDBServer")) return eServerPacketType_qQueryGDBServer; + break; + case 'R': if (PACKET_STARTS_WITH ("qRcmd,")) return eServerPacketType_qRcmd; if (PACKET_STARTS_WITH ("qRegisterInfo")) return eServerPacketType_qRegisterInfo; diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h index b981160b557..7e2f1e7c696 100644 --- a/lldb/source/Utility/StringExtractorGDBRemote.h +++ b/lldb/source/Utility/StringExtractorGDBRemote.h @@ -54,6 +54,7 @@ public: eServerPacketType_qGroupName, eServerPacketType_qHostInfo, eServerPacketType_qLaunchGDBServer, + eServerPacketType_qQueryGDBServer, eServerPacketType_qKillSpawnedProcess, eServerPacketType_qLaunchSuccess, eServerPacketType_qModuleInfo, diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp index 8fdc472257c..3292080da63 100644 --- a/lldb/tools/lldb-server/lldb-platform.cpp +++ b/lldb/tools/lldb-server/lldb-platform.cpp @@ -285,6 +285,12 @@ main_platform (int argc, char *argv[]) exit(option_error); } + // Skip any options we consumed with getopt_long_only. + argc -= optind; + argv += optind; + lldb_private::Args inferior_arguments; + inferior_arguments.SetArguments(argc, const_cast<const char**>(argv)); + const bool children_inherit_listen_socket = false; // the test suite makes many connections in parallel, let's not miss any. // The highest this should get reasonably is a function of the number @@ -309,7 +315,7 @@ main_platform (int argc, char *argv[]) error = save_socket_id_to_file(acceptor_up->GetLocalSocketId(), socket_file); if (error.Fail()) { - fprintf(stderr, "failed to write socket id to %s: %s", socket_file.GetPath().c_str(), error.AsCString()); + fprintf(stderr, "failed to write socket id to %s: %s\n", socket_file.GetPath().c_str(), error.AsCString()); return 1; } } @@ -317,7 +323,7 @@ main_platform (int argc, char *argv[]) do { GDBRemoteCommunicationServerPlatform platform(acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); - + if (port_offset > 0) platform.SetPortOffset(port_offset); @@ -365,6 +371,22 @@ main_platform (int argc, char *argv[]) if (platform.IsConnected()) { + if (inferior_arguments.GetArgumentCount() > 0) + { + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + uint16_t port = 0; + std::string socket_name; + Error error = platform.LaunchGDBServer(inferior_arguments, + "", // hostname + pid, + port, + socket_name); + if (error.Success()) + platform.SetPendingGdbServer(pid, port, socket_name); + else + fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); + } + // After we connected, we need to get an initial ack from... if (platform.HandshakeWithClient()) { |