Add domain socket support to gdb-remote protocol and lldb-server.

http://reviews.llvm.org/D13881

llvm-svn: 250933
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 0bbee85..ea95298 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -1112,17 +1112,15 @@
 }
 
 Error
-GDBRemoteCommunication::StartDebugserverProcess (const char *hostname,
-                                                 uint16_t in_port,
+GDBRemoteCommunication::StartDebugserverProcess (const char *url,
                                                  Platform *platform,
                                                  ProcessLaunchInfo &launch_info,
-                                                 uint16_t &out_port)
+                                                 uint16_t *port)
 {
     Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
     if (log)
-        log->Printf ("GDBRemoteCommunication::%s(hostname=%s, in_port=%" PRIu16 ", out_port=%" PRIu16, __FUNCTION__, hostname ? hostname : "<empty>", in_port, out_port);
+        log->Printf ("GDBRemoteCommunication::%s(url=%s, port=%" PRIu16, __FUNCTION__, url ? url : "<empty>", port ? *port : uint16_t(0));
 
-    out_port = in_port;
     Error error;
     // If we locate debugserver, keep that located version around
     static FileSpec g_debugserver_file_spec;
@@ -1193,17 +1191,9 @@
         debugserver_args.AppendArgument("gdbserver");
 #endif
 
-        // If a host and port is supplied then use it
-        char host_and_port[128];
-        if (hostname)
-        {
-            snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
-            debugserver_args.AppendArgument(host_and_port);
-        }
-        else
-        {
-            host_and_port[0] = '\0';
-        }
+        // If a url is supplied then use it
+        if (url)
+            debugserver_args.AppendArgument(url);
 
         // use native registers, not the GDB registers
         debugserver_args.AppendArgument("--native-regs");
@@ -1214,11 +1204,18 @@
         }
 
         llvm::SmallString<PATH_MAX> named_pipe_path;
-        Pipe port_pipe;
+        // socket_pipe is used by debug server to communicate back either
+        // TCP port or domain socket name which it listens on.
+        // The second purpose of the pipe to serve as a synchronization point -
+        // once data is written to the pipe, debug server is up and running.
+        Pipe socket_pipe;
 
-        if (in_port == 0)
+        // port is null when debug server should listen on domain socket -
+        // we're not interested in port value but rather waiting for debug server
+        // to become available.
+        if ((port != nullptr && *port == 0) || port == nullptr)
         {
-            if (host_and_port[0])
+            if (url)
             {
                 // Create a temporary file to get the stdout/stderr and redirect the
                 // output of the command into this file. We will later read this file
@@ -1227,7 +1224,7 @@
 #if defined(__APPLE__)
                 // Binding to port zero, we need to figure out what port it ends up
                 // using using a named pipe...
-                error = port_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
+                error = socket_pipe.CreateWithUniqueName("debugserver-named-pipe", false, named_pipe_path);
                 if (error.Fail())
                 {
                     if (log)
@@ -1241,7 +1238,7 @@
 #else
                 // Binding to port zero, we need to figure out what port it ends up
                 // using using an unnamed pipe...
-                error = port_pipe.CreateNew(true);
+                error = socket_pipe.CreateNew(true);
                 if (error.Fail())
                 {
                     if (log)
@@ -1250,10 +1247,10 @@
                                 __FUNCTION__, error.AsCString());
                     return error;
                 }
-                int write_fd = port_pipe.GetWriteFileDescriptor();
+                int write_fd = socket_pipe.GetWriteFileDescriptor();
                 debugserver_args.AppendArgument("--pipe");
                 debugserver_args.AppendArgument(std::to_string(write_fd).c_str());
-                launch_info.AppendCloseFileAction(port_pipe.GetReadFileDescriptor());
+                launch_info.AppendCloseFileAction(socket_pipe.GetReadFileDescriptor());
 #endif
             }
             else
@@ -1270,11 +1267,11 @@
     
                 ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
                 // Wait for 10 seconds to resolve the bound port
-                out_port = connection->GetListeningPort(10);
-                if (out_port > 0)
+                *port = connection->GetListeningPort(10);
+                if (*port > 0)
                 {
                     char port_cstr[32];
-                    snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", out_port);
+                    snprintf(port_cstr, sizeof(port_cstr), "127.0.0.1:%i", *port);
                     // Send the host and port down that debugserver and specify an option
                     // so that it connects back to the port we are listening to in this process
                     debugserver_args.AppendArgument("--reverse-connect");
@@ -1343,11 +1340,12 @@
         
         error = Host::LaunchProcess(launch_info);
         
-        if (error.Success() && launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+        if (error.Success() &&
+            launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
         {
             if (named_pipe_path.size() > 0)
             {
-                error = port_pipe.OpenAsReader(named_pipe_path, false);
+                error = socket_pipe.OpenAsReader(named_pipe_path, false);
                 if (error.Fail())
                     if (log)
                         log->Printf("GDBRemoteCommunication::%s() "
@@ -1355,24 +1353,24 @@
                                 __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
             }
 
-            if (port_pipe.CanWrite())
-                port_pipe.CloseWriteFileDescriptor();
-            if (port_pipe.CanRead())
+            if (socket_pipe.CanWrite())
+                socket_pipe.CloseWriteFileDescriptor();
+            if (socket_pipe.CanRead())
             {
-                char port_cstr[256];
+                char port_cstr[PATH_MAX] = {0};
                 port_cstr[0] = '\0';
                 size_t num_bytes = sizeof(port_cstr);
                 // Read port from pipe with 10 second timeout.
-                error = port_pipe.ReadWithTimeout(port_cstr, num_bytes,
+                error = socket_pipe.ReadWithTimeout(port_cstr, num_bytes,
                         std::chrono::seconds{10}, num_bytes);
-                if (error.Success())
+                if (error.Success() && (port != nullptr))
                 {
                     assert(num_bytes > 0 && port_cstr[num_bytes-1] == '\0');
-                    out_port = StringConvert::ToUInt32(port_cstr, 0);
+                    *port = StringConvert::ToUInt32(port_cstr, 0);
                     if (log)
                         log->Printf("GDBRemoteCommunication::%s() "
-                                "debugserver listens %u port",
-                                __FUNCTION__, out_port);
+                                    "debugserver listens %u port",
+                                    __FUNCTION__, *port);
                 }
                 else
                 {
@@ -1382,12 +1380,12 @@
                                 __FUNCTION__, named_pipe_path.c_str(), error.AsCString());
 
                 }
-                port_pipe.Close();
+                socket_pipe.Close();
             }
 
             if (named_pipe_path.size() > 0)
             {
-                const auto err = port_pipe.Delete(named_pipe_path);
+                const auto err = socket_pipe.Delete(named_pipe_path);
                 if (err.Fail())
                 {
                     if (log)