[Lldb-commits] [lldb] r196547 - Modified local spawning in debugserver processes to use a new --reverse-connect option so that debugserver actually connects back to LLDB instead of LLDB connecting to debugserver.

Greg Clayton gclayton at apple.com
Thu Dec 5 14:58:23 PST 2013


Author: gclayton
Date: Thu Dec  5 16:58:22 2013
New Revision: 196547

URL: http://llvm.org/viewvc/llvm-project?rev=196547&view=rev
Log:
Modified local spawning in debugserver processes to use a new --reverse-connect option so that debugserver actually connects back to LLDB instead of LLDB connecting to debugserver.

This gets rid of our hacky "get_random_port()" which would grab a random port and tell debugserver to open that port. Now LLDB creates, binds, listens and accepts a connection by binding to port zero and sending the correctly bound port down as the host:port to connect back to.

Fixed the "ConnectionFileDescriptor" to be able to correctly listen for connections from a specified host, localhost, or any host. Prior to this fix "listen://" only accepted the following format:

listen://<port>

But now it can accept:

listen://<port>         // Listen for connection from localhost on port <port>
listen://<host>:<port>  // Listen for connection from <host> and <port>    
listen://*:<port>       // Listen for connection from any host on port <port>



Modified:
    lldb/trunk/include/lldb/Core/ConnectionFileDescriptor.h
    lldb/trunk/include/lldb/Host/SocketAddress.h
    lldb/trunk/source/Core/ConnectionFileDescriptor.cpp
    lldb/trunk/source/Host/common/SocketAddress.cpp
    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/GDBRemoteCommunicationServer.cpp
    lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
    lldb/trunk/tools/debugserver/source/debugserver.cpp
    lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
    lldb/trunk/tools/lldb-platform/lldb-platform.cpp

Modified: lldb/trunk/include/lldb/Core/ConnectionFileDescriptor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ConnectionFileDescriptor.h?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ConnectionFileDescriptor.h (original)
+++ lldb/trunk/include/lldb/Core/ConnectionFileDescriptor.h Thu Dec  5 16:58:22 2013
@@ -76,6 +76,9 @@ public:
     in_port_t
     GetWritePort () const;
 
+    in_port_t
+    GetBoundPort (uint32_t timeout_sec);
+
 protected:
 
     typedef enum
@@ -95,7 +98,7 @@ protected:
     BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
     
     lldb::ConnectionStatus
-    SocketListen (uint16_t listen_port_num, Error *error_ptr);
+    SocketListen (const char *host_and_port, Error *error_ptr);
 
     lldb::ConnectionStatus
     ConnectTCP (const char *host_and_port, Error *error_ptr);
@@ -117,11 +120,12 @@ protected:
     FDType m_fd_send_type;
     FDType m_fd_recv_type;
     std::unique_ptr<SocketAddress> m_udp_send_sockaddr;
-    bool m_should_close_fd;     // True if this class should close the file descriptor when it goes away.
     uint32_t m_socket_timeout_usec;
     int m_pipe_read;            // A pipe that we select on the reading end of along with
     int m_pipe_write;           // m_fd_recv so we can force ourselves out of the select.
-    Mutex m_mutex;          
+    Mutex m_mutex;
+    Predicate<in_port_t> m_port_predicate; // Used when binding to port zero to wait for the thread that creates the socket, binds and listens to resolve the port number
+    bool m_should_close_fd;     // True if this class should close the file descriptor when it goes away.
     bool m_shutting_down;       // This marks that we are shutting down so if we get woken up from BytesAvailable
                                 // to disconnect, we won't try to read again.
     

Modified: lldb/trunk/include/lldb/Host/SocketAddress.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/SocketAddress.h?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/SocketAddress.h (original)
+++ lldb/trunk/include/lldb/Host/SocketAddress.h Thu Dec  5 16:58:22 2013
@@ -121,10 +121,12 @@ public:
     // address.
     //------------------------------------------------------------------
     bool
-    SetAddress (const struct addrinfo *hints_ptr,   // Optional hints where the family, protocol and other things can be specified.
-                const char *host,                   // Hostname ("foo.bar.com" or "foo" or IP address string ("123.234.12.1" or "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
-                const char *service,                // Protocol name ("tcp", "http", etc) or a raw port number string ("81")
-                struct addrinfo *addr_info_ptr);    // If non-NULL, this will get filled in with the match
+    getaddrinfo (const char *host,          // Hostname ("foo.bar.com" or "foo" or IP address string ("123.234.12.1" or "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
+                 const char *service,       // Protocol name ("tcp", "http", etc) or a raw port number string ("81")
+                 int ai_family = PF_UNSPEC,
+                 int ai_socktype = 0,
+                 int ai_protocol = 0,
+                 int ai_flags = 0);
 
     //------------------------------------------------------------------
     // Quick way to set the SocketAddress to localhost given the family.
@@ -135,6 +137,10 @@ public:
     SetToLocalhost (sa_family_t family, 
                     in_port_t port);
 
+    bool
+    SetToAnyAddress (sa_family_t family,
+                     in_port_t port);
+
     //------------------------------------------------------------------
     // Returns true if there is a valid socket address in this object.
     //------------------------------------------------------------------

Modified: lldb/trunk/source/Core/ConnectionFileDescriptor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ConnectionFileDescriptor.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Core/ConnectionFileDescriptor.cpp (original)
+++ lldb/trunk/source/Core/ConnectionFileDescriptor.cpp Thu Dec  5 16:58:22 2013
@@ -97,11 +97,11 @@ ConnectionFileDescriptor::ConnectionFile
     m_fd_send_type (eFDTypeFile),
     m_fd_recv_type (eFDTypeFile),
     m_udp_send_sockaddr (new SocketAddress()),
-    m_should_close_fd (false), 
     m_socket_timeout_usec(0),
     m_pipe_read(-1),
     m_pipe_write(-1),
     m_mutex (Mutex::eMutexTypeRecursive),
+    m_should_close_fd (false),
     m_shutting_down (false)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION |  LIBLLDB_LOG_OBJECT));
@@ -116,11 +116,11 @@ ConnectionFileDescriptor::ConnectionFile
     m_fd_send_type (eFDTypeFile),
     m_fd_recv_type (eFDTypeFile),
     m_udp_send_sockaddr (new SocketAddress()),
-    m_should_close_fd (owns_fd),
     m_socket_timeout_usec(0),
     m_pipe_read(-1),
     m_pipe_write(-1),
     m_mutex (Mutex::eMutexTypeRecursive),
+    m_should_close_fd (owns_fd),
     m_shutting_down (false)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION |  LIBLLDB_LOG_OBJECT));
@@ -218,12 +218,15 @@ ConnectionFileDescriptor::Connect (const
     
     if (s && s[0])
     {
-        char *end = NULL;
         if (strstr(s, "listen://"))
         {
             // listen://HOST:PORT
-            unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0);
-            return SocketListen (listen_port, error_ptr);
+            return SocketListen (s + strlen("listen://"), error_ptr);
+        }
+        else if (strstr(s, "accept://"))
+        {
+            // unix://SOCKNAME
+            return NamedSocketAccept (s + strlen("accept://"), error_ptr);
         }
         else if (strstr(s, "unix-accept://"))
         {
@@ -363,6 +366,9 @@ ConnectionFileDescriptor::Disconnect (Er
     if (log)
         log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this);
 
+    // Reset the port predicate when disconnecting and don't broadcast
+    m_port_predicate.SetValue(0, eBroadcastNever);
+
     ConnectionStatus status = eConnectionStatusSuccess;
 
     if (m_fd_send < 0 && m_fd_recv < 0)
@@ -1281,16 +1287,31 @@ ConnectionFileDescriptor::NamedSocketCon
 }
 
 ConnectionStatus
-ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
+ConnectionFileDescriptor::SocketListen (const char *host_and_port, Error *error_ptr)
 {
     Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
     if (log)
-        log->Printf ("%p ConnectionFileDescriptor::SocketListen (port = %i)", this, listen_port_num);
+        log->Printf ("%p ConnectionFileDescriptor::SocketListen (%s)", this, host_and_port);
 
     Disconnect (NULL);
     m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
-    int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
-    if (listen_port == -1)
+    std::string host_str;
+    std::string port_str;
+    int32_t port = INT32_MIN;
+    if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
+    {
+        // Might be just a port number
+        port = Args::StringToSInt32(host_and_port, -1);
+        if (port == -1)
+            return eConnectionStatusError;
+        else
+            host_str.clear();
+    }
+    const sa_family_t family = AF_INET;
+    const int socktype = SOCK_STREAM;
+    const int protocol = IPPROTO_TCP;
+    int listen_fd = ::socket (family, socktype, protocol);
+    if (listen_fd == -1)
     {
         if (error_ptr)
             error_ptr->SetErrorToErrno();
@@ -1298,41 +1319,114 @@ ConnectionFileDescriptor::SocketListen (
     }
 
     // enable local address reuse
-    SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
+    SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1);
+
+    SocketAddress listen_addr;
+    if (host_str.empty())
+        listen_addr.SetToLocalhost(family, port);
+    else if (host_str.compare("*") == 0)
+        listen_addr.SetToAnyAddress(family, port);
+    else
+    {
+        if (!listen_addr.getaddrinfo(host_str.c_str(), port_str.c_str(), family, socktype, protocol))
+        {
+            if (error_ptr)
+                error_ptr->SetErrorStringWithFormat("unable to resolve hostname '%s'", host_str.c_str());
+            Close (listen_fd, eFDTypeSocket, NULL);
+            return eConnectionStatusError;
+        }
+    }
 
-    SocketAddress localhost;
-    if (localhost.SetToLocalhost (AF_INET, listen_port_num))
+    SocketAddress anyaddr;
+    if (anyaddr.SetToAnyAddress (family, port))
     {
-        int err = ::bind (listen_port, localhost, localhost.GetLength());
+        int err = ::bind (listen_fd, anyaddr, anyaddr.GetLength());
         if (err == -1)
         {
             if (error_ptr)
                 error_ptr->SetErrorToErrno();
-            Close (listen_port, eFDTypeSocket, NULL);
+            Close (listen_fd, eFDTypeSocket, NULL);
             return eConnectionStatusError;
         }
 
-        err = ::listen (listen_port, 1);
+        err = ::listen (listen_fd, 1);
         if (err == -1)
         {
             if (error_ptr)
                 error_ptr->SetErrorToErrno();
-            Close (listen_port, eFDTypeSocket, NULL);
+            Close (listen_fd, eFDTypeSocket, NULL);
             return eConnectionStatusError;
         }
 
-        m_fd_send = m_fd_recv = ::accept (listen_port, NULL, 0);
+        // We were asked to listen on port zero which means we
+        // must now read the actual port that was given to us
+        // as port zero is a special code for "find an open port
+        // for me".
+        if (port == 0)
+            port = GetSocketPort(listen_fd);
+
+        // Set the port predicate since when doing a listen://<host>:<port>
+        // it often needs to accept the incoming connection which is a blocking
+        // system call. Allowing access to the bound port using a predicate allows
+        // us to wait for the port predicate to be set to a non-zero value from
+        // another thread in an efficient manor.
+        m_port_predicate.SetValue(port, eBroadcastAlways);
+        
+        
+        bool accept_connection = false;
+        
+        // Loop until we are happy with our connection
+        while (!accept_connection)
+        {
+            struct sockaddr_in accept_addr;
+            ::memset (&accept_addr, 0, sizeof accept_addr);
+            accept_addr.sin_len = sizeof accept_addr;
+            socklen_t accept_addr_len = sizeof accept_addr;
+
+            int fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len);
+            
+            if (fd == -1)
+            {
+                if (error_ptr)
+                    error_ptr->SetErrorToErrno();
+                break;
+            }
+    
+            if (listen_addr.sockaddr_in().sin_addr.s_addr == INADDR_ANY)
+            {
+                accept_connection = true;
+                m_fd_send = m_fd_recv = fd;
+            }
+            else
+            {
+                if (accept_addr_len == listen_addr.sockaddr_in().sin_len &&
+                    accept_addr.sin_addr.s_addr == listen_addr.sockaddr_in().sin_addr.s_addr)
+                {
+                    accept_connection = true;
+                    m_fd_send = m_fd_recv = fd;
+                }
+                else
+                {
+                    ::close (fd);
+                    m_fd_send = m_fd_recv = -1;
+                    const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr;
+                    const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sockaddr_in().sin_addr.s_addr;
+                    ::fprintf (stderr, "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n",
+                               accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3],
+                               listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]);
+                }
+            }
+        }
+
         if (m_fd_send == -1)
         {
-            if (error_ptr)
-                error_ptr->SetErrorToErrno();
-            Close (listen_port, eFDTypeSocket, NULL);
+            Close (listen_fd, eFDTypeSocket, NULL);
             return eConnectionStatusError;
         }
     }
 
     // We are done with the listen port
-    Close (listen_port, eFDTypeSocket, NULL);
+    Close (listen_fd, eFDTypeSocket, NULL);
 
     m_should_close_fd = true;
 
@@ -1446,7 +1540,7 @@ ConnectionFileDescriptor::ConnectUDP (co
     {
         // Socket was created, now lets bind to the requested port
         SocketAddress addr;
-        addr.SetToLocalhost (AF_INET, 0);
+        addr.SetToAnyAddress (AF_INET, 0);
 
         if (::bind (m_fd_recv, addr, addr.GetLength()) == -1)
         {
@@ -1585,11 +1679,13 @@ in_port_t
 ConnectionFileDescriptor::GetSocketPort (int fd)
 {
     // We bound to port zero, so we need to figure out which port we actually bound to
-    SocketAddress sock_addr;
-    socklen_t sock_addr_len = sock_addr.GetMaxLength ();
-    if (::getsockname (fd, sock_addr, &sock_addr_len) == 0)
-        return sock_addr.GetPort ();
-
+    if (fd >= 0)
+    {
+        SocketAddress sock_addr;
+        socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+        if (::getsockname (fd, sock_addr, &sock_addr_len) == 0)
+            return sock_addr.GetPort ();
+    }
     return 0;
 }
 
@@ -1609,4 +1705,17 @@ ConnectionFileDescriptor::GetWritePort (
     return ConnectionFileDescriptor::GetSocketPort (m_fd_send);
 }
 
-
+in_port_t
+ConnectionFileDescriptor::GetBoundPort (uint32_t timeout_sec)
+{
+    in_port_t bound_port = 0;
+    if (timeout_sec == UINT32_MAX)
+        m_port_predicate.WaitForValueNotEqualTo (0, bound_port);
+    else
+    {
+        TimeValue timeout = TimeValue::Now();
+        timeout.OffsetWithSeconds(timeout_sec);
+        m_port_predicate.WaitForValueNotEqualTo (0, bound_port, &timeout);
+    }
+    return bound_port;
+}

Modified: lldb/trunk/source/Host/common/SocketAddress.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/SocketAddress.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/SocketAddress.cpp (original)
+++ lldb/trunk/source/Host/common/SocketAddress.cpp Thu Dec  5 16:58:22 2013
@@ -128,8 +128,8 @@ SocketAddress::GetPort () const
 {
     switch (GetFamily())
     {
-        case AF_INET:   return m_socket_addr.sa_ipv4.sin_port;
-        case AF_INET6:  return m_socket_addr.sa_ipv6.sin6_port;
+        case AF_INET:   return ntohs(m_socket_addr.sa_ipv4.sin_port);
+        case AF_INET6:  return ntohs(m_socket_addr.sa_ipv6.sin6_port);
     }
     return 0;
 }
@@ -206,31 +206,29 @@ SocketAddress::operator=(const struct so
 }
 
 bool
-SocketAddress::SetAddress (const struct addrinfo *hints_ptr,
-                           const char *host, 
-                           const char *service,
-                           struct addrinfo *addr_info_ptr)
-{
+SocketAddress::getaddrinfo (const char *host,
+                            const char *service,
+                            int ai_family,
+                            int ai_socktype,
+                            int ai_protocol,
+                            int ai_flags)
+{
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = ai_family;
+    hints.ai_socktype = ai_socktype;
+    hints.ai_protocol = ai_protocol;
+    hints.ai_flags = ai_flags;
+
     struct addrinfo *service_info_list = NULL;
-    int err = ::getaddrinfo (host, service, hints_ptr, &service_info_list);
+    int err = ::getaddrinfo (host, service, &hints, &service_info_list);
     if (err == 0 && service_info_list)
-    {
-        if (addr_info_ptr)
-            *addr_info_ptr = *service_info_list;
         *this = service_info_list;
-    }
     else
         Clear();
     
     :: freeaddrinfo (service_info_list);
-    
-    const bool is_valid = IsValid();
-    if (!is_valid)
-    {
-        if (addr_info_ptr)
-            ::memset (addr_info_ptr, 0, sizeof(struct addrinfo));
-    }
-    return is_valid;
+    return IsValid();
 }
 
 
@@ -243,7 +241,7 @@ SocketAddress::SetToLocalhost (sa_family
             SetFamily (AF_INET);
             if (SetPort (port))
             {
-                m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY);
+                m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
                 return true;
             }
             break;
@@ -252,7 +250,7 @@ SocketAddress::SetToLocalhost (sa_family
             SetFamily (AF_INET6);
             if (SetPort (port))
             {
-                m_socket_addr.sa_ipv6.sin6_addr = in6addr_any;
+                m_socket_addr.sa_ipv6.sin6_addr = in6addr_loopback;
                 return true;
             }            
             break;
@@ -260,4 +258,32 @@ SocketAddress::SetToLocalhost (sa_family
     }
     Clear();
     return false;
+}
+
+bool
+SocketAddress::SetToAnyAddress (sa_family_t family, in_port_t port)
+{
+    switch (family)
+    {
+        case AF_INET:
+            SetFamily (AF_INET);
+            if (SetPort (port))
+            {
+                m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY);
+                return true;
+            }
+            break;
+            
+        case AF_INET6:
+            SetFamily (AF_INET6);
+            if (SetPort (port))
+            {
+                m_socket_addr.sa_ipv6.sin6_addr = in6addr_any;
+                return true;
+            }
+            break;
+            
+    }
+    Clear();
+    return false;
 }

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=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp Thu Dec  5 16:58:22 2013
@@ -17,6 +17,7 @@
 
 // C++ Includes
 // Other libraries and framework includes
+#include "lldb/Core/ConnectionFileDescriptor.h"
 #include "lldb/Core/Log.h"
 #include "lldb/Core/StreamFile.h"
 #include "lldb/Core/StreamString.h"
@@ -144,7 +145,9 @@ GDBRemoteCommunication::GDBRemoteCommuni
     m_private_is_running (false),
     m_history (512),
     m_send_acks (true),
-    m_is_platform (is_platform)
+    m_is_platform (is_platform),
+    m_listen_thread (LLDB_INVALID_HOST_THREAD),
+    m_listen_url ()
 {
 }
 
@@ -539,7 +542,56 @@ GDBRemoteCommunication::CheckForPacket (
 }
 
 Error
-GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
+GDBRemoteCommunication::StartListenThread (const char *hostname, in_port_t port)
+{
+    Error error;
+    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
+    {
+        error.SetErrorString("listen thread already running");
+    }
+    else
+    {
+        char listen_url[512];
+        if (hostname && hostname[0])
+            snprintf(listen_url, sizeof(listen_url), "listen://%s:%i", hostname ? hostname : "localhost", port);
+        else
+            snprintf(listen_url, sizeof(listen_url), "listen://%i", port);
+        m_listen_url = listen_url;
+        SetConnection(new ConnectionFileDescriptor());
+        m_listen_thread = Host::ThreadCreate (listen_url, GDBRemoteCommunication::ListenThread, this, &error);
+    }
+    return error;
+}
+
+bool
+GDBRemoteCommunication::JoinListenThread ()
+{
+    if (IS_VALID_LLDB_HOST_THREAD(m_listen_thread))
+    {
+        Host::ThreadJoin(m_listen_thread, NULL, NULL);
+        m_listen_thread = LLDB_INVALID_HOST_THREAD;
+    }
+    return true;
+}
+
+lldb::thread_result_t
+GDBRemoteCommunication::ListenThread (lldb::thread_arg_t arg)
+{
+    GDBRemoteCommunication *comm = (GDBRemoteCommunication *)arg;
+    Error error;
+    ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)comm->GetConnection ();
+    
+    if (connection)
+    {
+        // Do the listen on another thread so we can continue on...
+        if (connection->Connect(comm->m_listen_url.c_str(), &error) != eConnectionStatusSuccess)
+            comm->SetConnection(NULL);
+    }
+    return NULL;
+}
+
+Error
+GDBRemoteCommunication::StartDebugserverProcess (const char *host_and_port,
                                                  lldb_private::ProcessLaunchInfo &launch_info,
                                                  uint16_t &port)
 {
@@ -594,42 +646,69 @@ GDBRemoteCommunication::StartDebugserver
         
         // Start args with "debugserver /file/path -r --"
         debugserver_args.AppendArgument(debugserver_path);
-        debugserver_args.AppendArgument(debugserver_url);
+
+        // If a host and port is supplied then use it
+        if (host_and_port)
+            debugserver_args.AppendArgument(host_and_port);
         // use native registers, not the GDB registers
         debugserver_args.AppendArgument("--native-regs");   
         // make debugserver run in its own session so signals generated by 
         // special terminal key sequences (^C) don't affect debugserver
         debugserver_args.AppendArgument("--setsid");
-        
+
         char named_pipe_path[PATH_MAX];
-        
-        // 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
-        // if all goes well and fill the data into "command_output_ptr"
-        FileSpec tmpdir_file_spec;
-        if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
-        {
-            tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
-            strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
-        }
-        else
-        {
-            strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
-        }
 
-        if (::mktemp (named_pipe_path))
+        if (host_and_port)
         {
-            if (::mkfifo(named_pipe_path, 0600) == 0)
+            // 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
+            // if all goes well and fill the data into "command_output_ptr"
+            FileSpec tmpdir_file_spec;
+            if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
             {
-                debugserver_args.AppendArgument("--named-pipe");
-                debugserver_args.AppendArgument(named_pipe_path);
+                tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX");
+                strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path));
+            }
+            else
+            {
+                strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path));
+            }
+
+            if (::mktemp (named_pipe_path))
+            {
+                if (::mkfifo(named_pipe_path, 0600) == 0)
+                {
+                    debugserver_args.AppendArgument("--named-pipe");
+                    debugserver_args.AppendArgument(named_pipe_path);
+                }
+                else
+                    named_pipe_path[0] = '\0';
             }
             else
                 named_pipe_path[0] = '\0';
         }
         else
+        {
             named_pipe_path[0] = '\0';
+        
+            // No host and port given, so lets listen on our end and make the debugserver
+            // connect to us..
+            error = StartListenThread ("localhost", 0);
+            if (error.Fail())
+                return error;
+
+            ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection ();
+            port = connection->GetBoundPort(3);
+            assert (port != 0);
+            char port_cstr[32];
+            snprintf(port_cstr, sizeof(port_cstr), "localhost:%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");
+            debugserver_args.AppendArgument(port_cstr);
+        }
 
+        
         const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
         if (env_debugserver_log_file)
         {
@@ -669,7 +748,11 @@ GDBRemoteCommunication::StartDebugserver
             }
             Host::Unlink(named_pipe_path);
         }
-
+        else
+        {
+            // Make sure we actually connect with the debugserver...
+            JoinListenThread();
+        }
     }
     else
     {

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=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h Thu Dec  5 16:58:22 2013
@@ -108,8 +108,8 @@ public:
     // Start a debugserver instance on the current host using the
     // supplied connection URL.
     //------------------------------------------------------------------
-    static lldb_private::Error
-    StartDebugserverProcess (const char *connect_url,
+    lldb_private::Error
+    StartDebugserverProcess (const char *host_and_port,
                              lldb_private::ProcessLaunchInfo &launch_info,
                              uint16_t &port);
 
@@ -256,9 +256,22 @@ protected:
                         // a single process
     
 
+    lldb_private::Error
+    StartListenThread (const char *hostname = "localhost",
+                       in_port_t port = 0);
 
+    bool
+    JoinListenThread ();
+
+    static lldb::thread_result_t
+    ListenThread (lldb::thread_arg_t arg);
 
 private:
+    
+    lldb::thread_t m_listen_thread;
+    std::string m_listen_url;
+    
+
     //------------------------------------------------------------------
     // For GDBRemoteCommunication only
     //------------------------------------------------------------------

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp Thu Dec  5 16:58:22 2013
@@ -812,9 +812,9 @@ GDBRemoteCommunicationServer::Handle_qLa
 
             debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false);
             
-            error = GDBRemoteCommunication::StartDebugserverProcess (host_and_port_cstr,
-                                                                     debugserver_launch_info,
-                                                                     port);
+            error = StartDebugserverProcess (host_and_port_cstr,
+                                             debugserver_launch_info,
+                                             port);
 
             lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
 
@@ -1130,7 +1130,6 @@ GDBRemoteCommunicationServer::Handle_vFi
                 mode_t mode = packet.GetHexMaxU32(false, 0600);
                 Error error;
                 int fd = ::open (path.c_str(), flags, mode);
-                printf ("open('%s', flags=0x%x, mode=%o) fd = %i (%s)\n", path.c_str(), flags, mode, fd, fd == -1 ? strerror(errno) : "<success>");
                 const int save_errno = fd == -1 ? errno : 0;
                 StreamString response;
                 response.PutChar('F');

Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original)
+++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Thu Dec  5 16:58:22 2013
@@ -845,31 +845,35 @@ Error
 ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
 {
     Error error;
-    // Sleep and wait a bit for debugserver to start to listen...
-    std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-    if (conn_ap.get())
+    // Only connect if we have a valid connect URL
+    
+    if (connect_url && connect_url[0])
     {
-        const uint32_t max_retry_count = 50;
-        uint32_t retry_count = 0;
-        while (!m_gdb_comm.IsConnected())
+        std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+        if (conn_ap.get())
         {
-            if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess)
-            {
-                m_gdb_comm.SetConnection (conn_ap.release());
-                break;
-            }
-            else if (error.WasInterrupted())
+            const uint32_t max_retry_count = 50;
+            uint32_t retry_count = 0;
+            while (!m_gdb_comm.IsConnected())
             {
-                // If we were interrupted, don't keep retrying.
-                break;
-            }
-            
-            retry_count++;
-            
-            if (retry_count >= max_retry_count)
-                break;
+                if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess)
+                {
+                    m_gdb_comm.SetConnection (conn_ap.release());
+                    break;
+                }
+                else if (error.WasInterrupted())
+                {
+                    // If we were interrupted, don't keep retrying.
+                    break;
+                }
+                
+                retry_count++;
+                
+                if (retry_count >= max_retry_count)
+                    break;
 
-            usleep (100000);
+                usleep (100000);
+            }
         }
     }
 
@@ -2501,9 +2505,9 @@ ProcessGDBRemote::LaunchAndConnectToDebu
         debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
         debugserver_launch_info.SetUserID(process_info.GetUserID());
 
-        error = GDBRemoteCommunication::StartDebugserverProcess ("localhost:0",
-                                                                 debugserver_launch_info,
-                                                                 port);
+        error = m_gdb_comm.StartDebugserverProcess (NULL,
+                                                    debugserver_launch_info,
+                                                    port);
 
         if (error.Success ())
             m_debugserver_pid = debugserver_launch_info.GetProcessID();
@@ -2522,10 +2526,17 @@ ProcessGDBRemote::LaunchAndConnectToDebu
             return error;
         }
         
-        char connect_url[128];
-        snprintf (connect_url, sizeof(connect_url), "connect://localhost:%u", port);
-        
-        error = ConnectToDebugserver (connect_url);
+        if (m_gdb_comm.IsConnected())
+        {
+            // Finish the connection process by doing the handshake without connecting (send NULL URL)
+            ConnectToDebugserver (NULL);
+        }
+        else
+        {
+            char connect_url[128];
+            snprintf (connect_url, sizeof(connect_url), "connect://localhost:%u", port);
+            error = ConnectToDebugserver (connect_url);
+        }
 
     }
     return error;

Modified: lldb/trunk/tools/debugserver/source/debugserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/debugserver.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/debugserver.cpp (original)
+++ lldb/trunk/tools/debugserver/source/debugserver.cpp Thu Dec  5 16:58:22 2013
@@ -644,21 +644,34 @@ PortWasBoundCallbackNamedPipe (const voi
 }
 
 static int
-StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *named_pipe_path)
+ConnectRemote (RNBRemote *remote, const char *host, int port, bool reverse_connect, const char *named_pipe_path)
 {
     if (!remote->Comm().IsConnected())
     {
-        if (listen_port != 0)
-            RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", listen_port, listen_host ? listen_host : "localhost");
-        if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
+        if (reverse_connect)
         {
-            RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
-            return 0;
+            if (port == 0)
+            {
+                DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port);
+                return 0;
+            }
+            if (remote->Comm().Connect(host, port) != rnb_success)
+            {
+                DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port);
+                return 0;
+            }
         }
         else
         {
-            remote->StartReadRemoteDataThread();
+            if (port != 0)
+                RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "localhost");
+            if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success)
+            {
+                RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n");
+                return 0;
+            }
         }
+        remote->StartReadRemoteDataThread();
     }
     return 1;
 }
@@ -746,6 +759,7 @@ static struct option g_long_options[] =
     { "working-dir",        required_argument,  NULL,               'W' },  // The working directory that the inferior process should have (only if debugserver launches the process)
     { "platform",           required_argument,  NULL,               'p' },  // Put this executable into a remote platform mode
     { "named-pipe",         required_argument,  NULL,               'P' },
+    { "reverse-connect",    no_argument,        NULL,               'R' },
     { NULL,                 0,                  NULL,               0   }
 };
 
@@ -801,6 +815,7 @@ main (int argc, char *argv[])
     useconds_t waitfor_interval = 1000;     // Time in usecs between process lists polls when waiting for a process by name, default 1 msec.
     useconds_t waitfor_duration = 0;        // Time in seconds to wait for a process by name, 0 means wait forever.
     bool no_stdio = false;
+    bool reverse_connect = false;           // Set to true by an option to indicate we should reverse connect to the host:port supplied as the first debugserver argument
 
 #if !defined (DNBLOG_ENABLED)
     compile_options += "(no-logging) ";
@@ -997,6 +1012,9 @@ main (int argc, char *argv[])
                 // Do nothing, native regs is the default these days
                 break;
 
+            case 'R':
+                reverse_connect = true;
+                break;
             case 'v':
                 DNBLogSetVerbose(1);
                 break;
@@ -1117,8 +1135,8 @@ main (int argc, char *argv[])
                   compile_options.c_str(),
                   RNB_ARCH);
 
-    std::string listen_host;
-    int listen_port = INT32_MAX;
+    std::string host;
+    int port = INT32_MAX;
     char str[PATH_MAX];
     str[0] = '\0';
 
@@ -1131,24 +1149,24 @@ main (int argc, char *argv[])
         }
         // accept 'localhost:' prefix on port number
 
-        int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &listen_port);
+        int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port);
         if (items_scanned == 2)
         {
-            listen_host = str;
-            DNBLogDebug("host = '%s'  port = %i", listen_host.c_str(), listen_port);
+            host = str;
+            DNBLogDebug("host = '%s'  port = %i", host.c_str(), port);
         }
         else
         {
             // No hostname means "localhost"
-            int items_scanned = ::sscanf (argv[0], "%i", &listen_port);
+            int items_scanned = ::sscanf (argv[0], "%i", &port);
             if (items_scanned == 1)
             {
-                listen_host = "localhost";
-                DNBLogDebug("host = '%s'  port = %i", listen_host.c_str(), listen_port);
+                host = "localhost";
+                DNBLogDebug("host = '%s'  port = %i", host.c_str(), port);
             }
             else if (argv[0][0] == '/')
             {
-                listen_port = INT32_MAX;
+                port = INT32_MAX;
                 strncpy(str, argv[0], sizeof(str));
             }
             else
@@ -1263,9 +1281,9 @@ main (int argc, char *argv[])
                 }
                 else
 #endif
-                if (listen_port != INT32_MAX)
+                if (port != INT32_MAX)
                 {
-                    if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
+                    if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str()))
                         mode = eRNBRunLoopModeExit;
                 }
                 else if (str[0] == '/')
@@ -1376,9 +1394,9 @@ main (int argc, char *argv[])
 
                 if (mode != eRNBRunLoopModeExit)
                 {
-                    if (listen_port != INT32_MAX)
+                    if (port != INT32_MAX)
                     {
-                        if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
+                        if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str()))
                             mode = eRNBRunLoopModeExit;
                     }
                     else if (str[0] == '/')
@@ -1401,9 +1419,9 @@ main (int argc, char *argv[])
 
                     if (mode == eRNBRunLoopModeInferiorExecuting)
                     {
-                        if (listen_port != INT32_MAX)
+                        if (port != INT32_MAX)
                         {
-                            if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
+                            if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str()))
                                 mode = eRNBRunLoopModeExit;
                         }
                         else if (str[0] == '/')
@@ -1428,9 +1446,9 @@ main (int argc, char *argv[])
                 break;
 
             case eRNBRunLoopModePlatformMode:
-                if (listen_port != INT32_MAX)
+                if (port != INT32_MAX)
                 {
-                    if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str()))
+                    if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str()))
                         mode = eRNBRunLoopModeExit;
                 }
                 else if (str[0] == '/')

Modified: lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp (original)
+++ lldb/trunk/tools/lldb-gdbserver/lldb-gdbserver.cpp Thu Dec  5 16:58:22 2013
@@ -221,18 +221,14 @@ main (int argc, char *argv[])
         std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
         if (conn_ap.get())
         {
-            std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-            if (conn_ap.get())
-            {
-                std::string connect_url ("listen://");
-                connect_url.append(host_and_port);
+            std::string connect_url ("listen://");
+            connect_url.append(host_and_port);
 
-                printf ("Listening for a connection on %s...\n", host_and_port);
-                if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
-                {
-                    printf ("Connection established.\n");
-                    gdb_server.SetConnection (conn_ap.release());
-                }
+            printf ("Listening for a connection on %s...\n", host_and_port);
+            if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
+            {
+                printf ("Connection established.\n");
+                gdb_server.SetConnection (conn_ap.release());
             }
         }
 

Modified: lldb/trunk/tools/lldb-platform/lldb-platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-platform/lldb-platform.cpp?rev=196547&r1=196546&r2=196547&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-platform/lldb-platform.cpp (original)
+++ lldb/trunk/tools/lldb-platform/lldb-platform.cpp Thu Dec  5 16:58:22 2013
@@ -262,24 +262,18 @@ main (int argc, char *argv[])
             std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
             if (conn_ap.get())
             {
-                for (int j = 0; j < listen_host_port.size(); j++)
+                std::string connect_url ("listen://");
+                connect_url.append(listen_host_port.c_str());
+
+                printf ("Listening for a connection from %s...\n", listen_host_port.c_str());
+                if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
                 {
-                    char c = listen_host_port[j];
-                    if (c > '9' || c < '0')
-                        printf("WARNING: passing anything but a number as argument to --listen will most probably make connecting impossible.\n");
+                    printf ("Connection established.\n");
+                    gdb_server.SetConnection (conn_ap.release());
                 }
-                std::auto_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
-                if (conn_ap.get())
+                else
                 {
-                    std::string connect_url ("listen://");
-                    connect_url.append(listen_host_port.c_str());
-
-                    printf ("Listening for a connection on %s...\n", listen_host_port.c_str());
-                    if (conn_ap->Connect(connect_url.c_str(), &error) == eConnectionStatusSuccess)
-                    {
-                        printf ("Connection established.\n");
-                        gdb_server.SetConnection (conn_ap.release());
-                    }
+                    printf ("error: %s\n", error.AsCString());
                 }
             }
 





More information about the lldb-commits mailing list