Index: include/lldb/Target/Platform.h =================================================================== --- include/lldb/Target/Platform.h +++ include/lldb/Target/Platform.h @@ -488,11 +488,8 @@ 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); + ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse = false); //------------------------------------------------------------------ /// Attach to an existing process using a process ID. Index: include/lldb/Target/Process.h =================================================================== --- include/lldb/Target/Process.h +++ include/lldb/Target/Process.h @@ -1209,7 +1209,7 @@ /// Returns an error object. //------------------------------------------------------------------ virtual Error - ConnectRemote (Stream *strm, const char *remote_url); + ConnectRemote(Stream *strm, const char *remote_url, bool reverse = false); bool GetShouldDetach () const @@ -1461,7 +1461,7 @@ /// Returns an error object. //------------------------------------------------------------------ virtual Error - DoConnectRemote (Stream *strm, const char *remote_url) + DoConnectRemote(Stream *strm, const char *remote_url, bool reverse = false) { Error error; error.SetErrorString ("remote connections are not supported"); Index: source/Commands/CommandObjectProcess.cpp =================================================================== --- source/Commands/CommandObjectProcess.cpp +++ source/Commands/CommandObjectProcess.cpp @@ -1027,16 +1027,13 @@ std::string plugin_name; }; - CommandObjectProcessConnect (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process connect", - "Connect to a remote debug service.", - "process connect ", - 0), - m_options (interpreter) + CommandObjectProcessConnect(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process connect", "Connect to a remote debug service.", + "process connect [reverse]", 0), + m_options(interpreter) { } - + ~CommandObjectProcessConnect () override { } @@ -1052,23 +1049,39 @@ bool DoExecute (Args& command, CommandReturnObject &result) override { + bool reverse_connect = false; if (command.GetArgumentCount() != 1) { - 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 (command.GetArgumentCount() != 2) + { + result.AppendErrorWithFormat("'%s' takes either 1 or 2 arguments:\nUsage: %s\n", m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (strcmp(command.GetArgumentAtIndex(1), "reverse")) + { + result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + reverse_connect = true; } - - Process *process = m_exe_ctx.GetProcessPtr(); - if (process && process->IsAlive()) + if (!reverse_connect) { - result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n", - process->GetID()); - result.SetStatus (eReturnStatusFailed); - return false; + Process *process = m_exe_ctx.GetProcessPtr(); + if (process && process->IsAlive()) + { + result.AppendErrorWithFormat("Process %" PRIu64 " is currently being debugged, kill " + "the process before connecting.\n", + process->GetID()); + result.SetStatus(eReturnStatusFailed); + return false; + } } const char *plugin_name = nullptr; @@ -1078,11 +1091,8 @@ 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); + ProcessSP process_sp = platform_sp->ConnectProcess(command.GetArgumentAtIndex(0), plugin_name, debugger, + debugger.GetSelectedTarget().get(), error, reverse_connect); if (error.Fail() || process_sp == nullptr) { result.AppendError(error.AsCString("Error connecting to the process")); Index: source/Interpreter/CommandInterpreter.cpp =================================================================== --- source/Interpreter/CommandInterpreter.cpp +++ source/Interpreter/CommandInterpreter.cpp @@ -624,18 +624,21 @@ } } - std::unique_ptr - connect_gdb_remote_cmd_ap(new CommandObjectRegexCommand (*this, - "gdb-remote", - "Connect to a remote GDB server. If no hostname is provided, localhost is assumed.", - "gdb-remote [:]", - 2, - 0, - false)); + std::unique_ptr connect_gdb_remote_cmd_ap( + new CommandObjectRegexCommand(*this, "gdb-remote", "Connect to a remote GDB server. If no " + "hostname is provided, localhost is assumed.", + "gdb-remote [:] [reverse]", 2, 0, false)); if (connect_gdb_remote_cmd_ap.get()) { - if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin gdb-remote connect://%1") && - connect_gdb_remote_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", "process connect --plugin gdb-remote connect://localhost:%1")) + if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", + "process connect --plugin gdb-remote connect://%1") && + connect_gdb_remote_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", + "process connect --plugin gdb-remote connect://localhost:%1") && + connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+) reverse$", + "process connect --plugin gdb-remote connect://%1 reverse") && + connect_gdb_remote_cmd_ap->AddRegexCommand("^([[:digit:]]+) reverse$", + "process connect --plugin gdb-remote " + "connect://localhost:%1 reverse")) { CommandObjectSP command_sp(connect_gdb_remote_cmd_ap.release()); m_command_dict[command_sp->GetCommandName ()] = command_sp; Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -40,11 +40,8 @@ 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; + ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse = false) override; size_t ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -225,11 +225,9 @@ } lldb::ProcessSP -PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url, - const char* plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Error &error) +PlatformAndroidRemoteGDBServer::ConnectProcess(const char *connect_url, const char *plugin_name, + lldb_private::Debugger &debugger, lldb_private::Target *target, + lldb_private::Error &error, bool reverse) { // 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 @@ -252,11 +250,8 @@ if (error.Fail()) return nullptr; - return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(), - plugin_name, - debugger, - target, - error); + return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(), plugin_name, debugger, target, error, + reverse); } size_t Index: source/Plugins/Platform/POSIX/PlatformPOSIX.h =================================================================== --- source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -183,12 +183,9 @@ 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; - + ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse = false) override; + size_t ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override; Index: source/Plugins/Platform/POSIX/PlatformPOSIX.cpp =================================================================== --- source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -984,23 +984,16 @@ 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) +PlatformPOSIX::ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse) { if (m_remote_platform_sp) - return m_remote_platform_sp->ConnectProcess(connect_url, - plugin_name, - debugger, - target, - error); + return m_remote_platform_sp->ConnectProcess(connect_url, plugin_name, debugger, target, error, reverse); - return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error, reverse); } const char* Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -218,11 +218,8 @@ 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; + ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse = false) override; virtual size_t GetPendingGdbServerList(std::vector& connection_urls); Index: source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -987,18 +987,16 @@ } lldb::ProcessSP -PlatformRemoteGDBServer::ConnectProcess(const char* connect_url, - const char* plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Error &error) +PlatformRemoteGDBServer::ConnectProcess(const char *connect_url, const char *plugin_name, + lldb_private::Debugger &debugger, lldb_private::Target *target, + lldb_private::Error &error, bool reverse) { if (!IsRemote() || !IsConnected()) { error.SetErrorString("Not connected to remote gdb server"); return nullptr; } - return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error); + return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, error, reverse); } size_t Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -161,6 +161,9 @@ return m_packet_timeout * TimeValue::MicroSecPerSec; } + Error + WaitForDebugserver(const char *url); + //------------------------------------------------------------------ // Start a debugserver instance on the current host using the // supplied connection URL. @@ -339,7 +342,7 @@ DecompressPacket (); Error - StartListenThread (const char *hostname = "127.0.0.1", uint16_t port = 0); + StartListenThread(const char *listen_url = "listen://127.0.0.1:0"); bool JoinListenThread (); Index: source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp =================================================================== --- source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1066,7 +1066,7 @@ } Error -GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_t port) +GDBRemoteCommunication::StartListenThread(const char *listen_url) { Error error; if (m_listen_thread.IsJoinable()) @@ -1075,11 +1075,6 @@ } else { - char listen_url[512]; - if (hostname && hostname[0]) - snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname, port); - else - snprintf(listen_url, sizeof(listen_url), "listen://%i", port); m_listen_url = listen_url; SetConnection(new ConnectionFileDescriptor()); m_listen_thread = ThreadLauncher::LaunchThread(listen_url, GDBRemoteCommunication::ListenThread, this, &error); @@ -1112,11 +1107,41 @@ } Error -GDBRemoteCommunication::StartDebugserverProcess (const char *url, - Platform *platform, - ProcessLaunchInfo &launch_info, - uint16_t *port, - const Args& inferior_args) +GDBRemoteCommunication::WaitForDebugserver(const char *url) +{ + Error error; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + if (log) + log->Printf("GDBRemoteCommunication::%s(url=%s)", __FUNCTION__, url ? url : ""); + + std::string listen_url(url); + size_t start_replace = listen_url.find("connect"); + listen_url.replace(start_replace, start_replace + strlen("connect"), "listen"); + + error = StartListenThread(listen_url.c_str()); + if (error.Fail()) + { + if (log) + log->Printf("GDBRemoteCommunication::%s() unable to start listen thread: %s", __FUNCTION__, + error.AsCString()); + return error; + } + + // Make sure we actually connect with the debugserver... + JoinListenThread(); + + if (error.Fail()) + { + if (log) + log->Printf("GDBRemoteCommunication::%s() failed: %s", __FUNCTION__, error.AsCString()); + } + + return error; +} + +Error +GDBRemoteCommunication::StartDebugserverProcess(const char *url, Platform *platform, ProcessLaunchInfo &launch_info, + uint16_t *port, const Args &inferior_args) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -1258,7 +1283,7 @@ { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. - error = StartListenThread ("127.0.0.1", 0); + error = StartListenThread("listen://127.0.0.1:0"); if (error.Fail()) { if (log) Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.h =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -97,8 +97,8 @@ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) override; Error - DoConnectRemote (Stream *strm, const char *remote_url) override; - + DoConnectRemote(Stream *strm, const char *remote_url, bool reverse = false) override; + Error WillLaunchOrAttach (); Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -715,7 +715,7 @@ } Error -ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) +ProcessGDBRemote::DoConnectRemote(Stream *strm, const char *remote_url, bool reverse) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error (WillLaunchOrAttach ()); @@ -723,8 +723,14 @@ if (error.Fail()) return error; - error = ConnectToDebugserver (remote_url); + if (reverse) + { + error = m_gdb_comm.WaitForDebugserver(remote_url); + if (error.Fail()) + return error; + } + error = ConnectToDebugserver(remote_url); if (error.Fail()) return error; StartAsyncThread (); Index: source/Target/Platform.cpp =================================================================== --- source/Target/Platform.cpp +++ source/Target/Platform.cpp @@ -2043,11 +2043,8 @@ } lldb::ProcessSP -Platform::ConnectProcess(const char* connect_url, - const char* plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Error &error) +Platform::ConnectProcess(const char *connect_url, const char *plugin_name, lldb_private::Debugger &debugger, + lldb_private::Target *target, lldb_private::Error &error, bool reverse) { error.Clear(); @@ -2074,7 +2071,7 @@ if (!process_sp) return nullptr; - error = process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url); + error = process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url, reverse); if (error.Fail()) return nullptr; Index: source/Target/Process.cpp =================================================================== --- source/Target/Process.cpp +++ source/Target/Process.cpp @@ -3496,15 +3496,15 @@ } Error -Process::ConnectRemote (Stream *strm, const char *remote_url) +Process::ConnectRemote(Stream *strm, const char *remote_url, bool reverse) { m_abi_sp.reset(); m_process_input_reader.reset(); // Find the process and its architecture. Make sure it matches the architecture // of the current Target, and if not adjust it. - - Error error (DoConnectRemote (strm, remote_url)); + + Error error(DoConnectRemote(strm, remote_url, reverse)); if (error.Success()) { if (GetID() != LLDB_INVALID_PROCESS_ID)