diff options
5 files changed, 118 insertions, 33 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 14fe8773597..d194477b504 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -1091,7 +1091,8 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, Platform *platform, ProcessLaunchInfo &launch_info, uint16_t *port, - const Args& inferior_args) + const Args* inferior_args, + int pass_comm_fd) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) @@ -1171,6 +1172,16 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, if (url) debugserver_args.AppendArgument(url); + if (pass_comm_fd >= 0) + { + StreamString fd_arg; + fd_arg.Printf("--fd=%i", pass_comm_fd); + debugserver_args.AppendArgument(fd_arg.GetData()); + // Send "pass_comm_fd" down to the inferior so it can use it to + // communicate back with this process + launch_info.AppendDuplicateFileAction(pass_comm_fd, pass_comm_fd); + } + // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); @@ -1189,7 +1200,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, // 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 (pass_comm_fd == -1 && ((port != nullptr && *port == 0) || port == nullptr)) { if (url) { @@ -1304,10 +1315,10 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, } } while (has_env_var); - if (inferior_args.GetArgumentCount() > 0) + if (inferior_args && inferior_args->GetArgumentCount() > 0) { debugserver_args.AppendArgument ("--"); - debugserver_args.AppendArguments (inferior_args); + debugserver_args.AppendArguments (*inferior_args); } // Copy the current environment to the gdbserver/debugserver instance @@ -1337,8 +1348,7 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *url, } 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) && pass_comm_fd == -1) { if (named_pipe_path.size() > 0) { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 13325410e48..623f0d16653 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -162,7 +162,8 @@ public: 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, - const Args& inferior_args = Args()); + const Args *inferior_args, + int pass_comm_fd); // Communication file descriptor to pass during fork/exec to avoid having to connect/accept void DumpHistory(Stream &strm); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index d6900c27293..1cac61277e7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -149,7 +149,8 @@ GDBRemoteCommunicationServerPlatform::LaunchGDBServer(const lldb_private::Args& nullptr, debugserver_launch_info, port_ptr, - args); + &args, + -1); pid = debugserver_launch_info.GetProcessID(); if (pid != LLDB_INVALID_PROCESS_ID) diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 07ec61f2544..eb82dc1eba3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -16,6 +16,7 @@ #include <netinet/in.h> #include <sys/mman.h> // for mmap #endif +#include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <time.h> @@ -64,6 +65,7 @@ #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/SystemRuntime.h" +#include "lldb/Utility/CleanUp.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes @@ -3602,6 +3604,23 @@ ProcessGDBRemote::EstablishConnectionIfNeeded (const ProcessInfo &process_info) } return error; } +#if defined (__APPLE__) +#define USE_SOCKETPAIR_FOR_LOCAL_CONNECTION 1 +#endif + +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION +static bool SetCloexecFlag(int fd) +{ +#if defined(FD_CLOEXEC) + int flags = ::fcntl(fd, F_GETFD); + if (flags == -1) + return false; + return (::fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == 0); +#else + return false; +#endif +} +#endif Error ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) @@ -3624,30 +3643,34 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info false); debugserver_launch_info.SetUserID(process_info.GetUserID()); -#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) - // On iOS, still do a local connection using a random port - const char *hostname = "127.0.0.1"; - uint16_t port = get_random_port (); -#else - // Set hostname being NULL to do the reverse connect where debugserver - // will bind to port zero and it will communicate back to us the port - // that we will connect to - const char *hostname = nullptr; - uint16_t port = 0; -#endif - StreamString url_str; - const char* url = nullptr; - if (hostname != nullptr) + int communication_fd = -1; +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Auto close the sockets we might open up unless everything goes OK. This + // helps us not leak file descriptors when things go wrong. + lldb_utility::CleanUp <int, int> our_socket(-1, -1, close); + lldb_utility::CleanUp <int, int> gdb_socket(-1, -1, close); + + // Use a socketpair on Apple for now until other platforms can verify it + // works and is fast enough { - url_str.Printf("%s:%u", hostname, port); - url = url_str.GetData(); + int sockets[2]; /* the pair of socket descriptors */ + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) + { + error.SetErrorToErrno(); + return error; + } + + our_socket.set(sockets[0]); + gdb_socket.set(sockets[1]); } - error = m_gdb_comm.StartDebugserverProcess (url, - GetTarget().GetPlatform().get(), - debugserver_launch_info, - &port); + // Don't let any child processes inherit our communication socket + SetCloexecFlag(our_socket.get()); + communication_fd = gdb_socket.get(); +#endif + + error = m_gdb_comm.StartDebugserverProcess(nullptr, GetTarget().GetPlatform().get(), debugserver_launch_info, nullptr, nullptr, communication_fd); if (error.Success ()) m_debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -3655,7 +3678,14 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info m_debugserver_pid = LLDB_INVALID_PROCESS_ID; if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) + { +#ifdef USE_SOCKETPAIR_FOR_LOCAL_CONNECTION + // Our process spawned correctly, we can now set our connection to use our + // end of the socket pair + m_gdb_comm.SetConnection(new ConnectionFileDescriptor(our_socket.release(), true)); +#endif StartAsyncThread (); + } if (error.Fail()) { @@ -3669,13 +3699,11 @@ ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info if (m_gdb_comm.IsConnected()) { // Finish the connection process by doing the handshake without connecting (send NULL URL) - ConnectToDebugserver (NULL); + ConnectToDebugserver(NULL); } else { - StreamString connect_url; - connect_url.Printf("connect://%s:%u", hostname, port); - error = ConnectToDebugserver (connect_url.GetString().c_str()); + error.SetErrorString("connection failed"); } } diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index a22f046771d..e9ddbf47faa 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -872,6 +872,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 { "unix-socket", required_argument, NULL, 'u' }, // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use + { "fd", required_argument, NULL, 'FDSC' }, // A file descriptor was passed to this process when spawned that is already open and ready for communication { "named-pipe", required_argument, NULL, 'P' }, { "reverse-connect", no_argument, NULL, 'R' }, { "env", required_argument, NULL, 'e' }, // When debugserver launches the process, set a single environment entry as specified by the option value ("./debugserver -e FOO=1 -e BAR=2 localhost:1234 -- /bin/ls") @@ -949,6 +950,7 @@ main (int argc, char *argv[]) int ch; int long_option_index = 0; int debug = 0; + int communication_fd = -1; std::string compile_options; std::string waitfor_pid_name; // Wait for a process that starts with this name std::string attach_pid_name; @@ -1248,6 +1250,12 @@ main (int argc, char *argv[]) remote->Context().PushEnvironment(env_entry); } break; + + case 'FDSC': + // File descriptor passed to this process during fork/exec and is already + // open and ready for communication. + communication_fd = atoi(optarg); + break; } } @@ -1324,7 +1332,7 @@ main (int argc, char *argv[]) char str[PATH_MAX]; str[0] = '\0'; - if (g_lockdown_opt == 0 && g_applist_opt == 0) + if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) { // Make sure we at least have port if (argc < 1) @@ -1475,6 +1483,15 @@ main (int argc, char *argv[]) if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } + else if (communication_fd >= 0) + { + // We were passed a file descriptor to use during fork/exec that is already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } if (mode != eRNBRunLoopModeExit) { @@ -1600,6 +1617,16 @@ main (int argc, char *argv[]) if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } + else if (communication_fd >= 0) + { + // We were passed a file descriptor to use during fork/exec that is already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + if (mode != eRNBRunLoopModeExit) RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid); } @@ -1625,6 +1652,15 @@ main (int argc, char *argv[]) if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } + else if (communication_fd >= 0) + { + // We were passed a file descriptor to use during fork/exec that is already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } if (mode != eRNBRunLoopModeExit) { @@ -1657,6 +1693,15 @@ main (int argc, char *argv[]) if (remote->Comm().OpenFile (str)) mode = eRNBRunLoopModeExit; } + else if (communication_fd >= 0) + { + // We were passed a file descriptor to use during fork/exec that is already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } if (mode != eRNBRunLoopModeExit) mode = RNBRunLoopPlatform (remote); |