[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