[Lldb-commits] [lldb] r255016 - Modify "platform connect" to connect to processes as well

Tamas Berghammer via lldb-commits lldb-commits at lists.llvm.org
Tue Dec 8 06:08:20 PST 2015


Author: tberghammer
Date: Tue Dec  8 08:08:19 2015
New Revision: 255016

URL: http://llvm.org/viewvc/llvm-project?rev=255016&view=rev
Log:
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

Added:
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp
Modified:
    lldb/trunk/docs/lldb-gdb-remote.txt
    lldb/trunk/include/lldb/Target/Platform.h
    lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py
    lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
    lldb/trunk/source/Commands/CommandObjectPlatform.cpp
    lldb/trunk/source/Commands/CommandObjectProcess.cpp
    lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
    lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
    lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
    lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h
    lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
    lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
    lldb/trunk/source/Target/Platform.cpp
    lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
    lldb/trunk/source/Utility/StringExtractorGDBRemote.h
    lldb/trunk/tools/lldb-server/lldb-platform.cpp

Modified: lldb/trunk/docs/lldb-gdb-remote.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/docs/lldb-gdb-remote.txt?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/docs/lldb-gdb-remote.txt (original)
+++ lldb/trunk/docs/lldb-gdb-remote.txt Tue Dec  8 08:08:19 2015
@@ -1597,3 +1597,29 @@ On MacOSX with debugserver, we expedite
 (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" }
+]

Modified: lldb/trunk/include/lldb/Target/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Platform.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Platform.h (original)
+++ lldb/trunk/include/lldb/Target/Platform.h Tue Dec  8 08:08:19 2015
@@ -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

Modified: lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lldbtest.py Tue Dec  8 08:08:19 2015
@@ -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,
         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]

Modified: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py Tue Dec  8 08:08:19 2015
@@ -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.

Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile?rev=255016&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/Makefile Tue Dec  8 08:08:19 2015
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py?rev=255016&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py Tue Dec  8 08:08:19 2015
@@ -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()

Added: lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp?rev=255016&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/main.cpp Tue Dec  8 08:08:19 2015
@@ -0,0 +1,7 @@
+#include <cstdio>
+
+int main (int argc, char **argv)
+{
+    printf("argc: %d\n", argc);
+    return argv[0][0];
+}

Modified: lldb/trunk/source/Commands/CommandObjectPlatform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectPlatform.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectPlatform.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectPlatform.cpp Tue Dec  8 08:08:19 2015
@@ -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

Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Tue Dec  8 08:08:19 2015
@@ -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;
 };
 

Modified: lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp Tue Dec  8 08:08:19 2015
@@ -223,3 +223,53 @@ PlatformAndroidRemoteGDBServer::MakeConn
 
     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();
+}

Modified: lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h (original)
+++ lldb/trunk/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h Tue Dec  8 08:08:19 2015
@@ -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;

Modified: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp Tue Dec  8 08:08:19 2015
@@ -986,6 +986,23 @@ PlatformPOSIX::UnloadImage (lldb_private
         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::GetLibdlFunctionDeclarati
               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);
+}

Modified: lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h (original)
+++ lldb/trunk/source/Plugins/Platform/POSIX/PlatformPOSIX.h Tue Dec  8 08:08:19 2015
@@ -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

Modified: lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp Tue Dec  8 08:08:19 2015
@@ -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 c
         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();
+}

Modified: lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h (original)
+++ lldb/trunk/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h Tue Dec  8 08:08:19 2015
@@ -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

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp Tue Dec  8 08:08:19 2015
@@ -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::StartDebugserver
             }
         } 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);

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h Tue Dec  8 08:08:19 2015
@@ -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);

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp Tue Dec  8 08:08:19 2015
@@ -3383,6 +3383,43 @@ GDBRemoteCommunicationClient::LaunchGDBS
     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)
 {

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h Tue Dec  8 08:08:19 2015
@@ -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);
 

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp Tue Dec  8 08:08:19 2015
@@ -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::GD
     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::GD
                                   &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::~G
 {
 }
 
-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::Ha
     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::Ha
     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::Ha
     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::Ge
 }
 
 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;
+}

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h Tue Dec  8 08:08:19 2015
@@ -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

Modified: lldb/trunk/source/Target/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Platform.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Target/Platform.cpp (original)
+++ lldb/trunk/source/Target/Platform.cpp Tue Dec  8 08:08:19 2015
@@ -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::Proc
 {
     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;
+}

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.cpp Tue Dec  8 08:08:19 2015
@@ -163,12 +163,12 @@ StringExtractorGDBRemote::GetServerPacke
         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::GetServerPacke
             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;

Modified: lldb/trunk/source/Utility/StringExtractorGDBRemote.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/StringExtractorGDBRemote.h?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/source/Utility/StringExtractorGDBRemote.h (original)
+++ lldb/trunk/source/Utility/StringExtractorGDBRemote.h Tue Dec  8 08:08:19 2015
@@ -54,6 +54,7 @@ public:
         eServerPacketType_qGroupName,
         eServerPacketType_qHostInfo,
         eServerPacketType_qLaunchGDBServer,
+        eServerPacketType_qQueryGDBServer,
         eServerPacketType_qKillSpawnedProcess,
         eServerPacketType_qLaunchSuccess,
         eServerPacketType_qModuleInfo,

Modified: lldb/trunk/tools/lldb-server/lldb-platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-server/lldb-platform.cpp?rev=255016&r1=255015&r2=255016&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-server/lldb-platform.cpp (original)
+++ lldb/trunk/tools/lldb-server/lldb-platform.cpp Tue Dec  8 08:08:19 2015
@@ -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())
             {




More information about the lldb-commits mailing list