From 91a9b247d473cebc23cee55309aecc56a0c29f64 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Wed, 4 Dec 2013 19:19:12 +0000 Subject: [PATCH] Switch local launching of debugserver over to always use a FIFO in order to handshake with the launched debugserver. This helps ensure that the launched debugserver is ready and listening for a connection. Prior to this we had a race condition. Consolidate the launching of debugserver into a single place: a static function in GDBRemoteCommunication. llvm-svn: 196401 --- .../Process/MacOSX-Kernel/CommunicationKDP.h | 9 - .../gdb-remote/GDBRemoteCommunication.cpp | 93 ++++--- .../gdb-remote/GDBRemoteCommunication.h | 6 +- .../GDBRemoteCommunicationServer.cpp | 61 +---- .../Process/gdb-remote/ProcessGDBRemote.cpp | 228 +++--------------- .../Process/gdb-remote/ProcessGDBRemote.h | 5 +- lldb/tools/debugserver/source/RNBRemote.cpp | 1 - lldb/tools/debugserver/source/RNBSocket.cpp | 35 +-- lldb/tools/debugserver/source/debugserver.cpp | 81 ++----- 9 files changed, 134 insertions(+), 385 deletions(-) diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h index f53b190522f3..98a146d5a06d 100644 --- a/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ b/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -142,15 +142,6 @@ public: { return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec; } - //------------------------------------------------------------------ - // Start a debugserver instance on the current host using the - // supplied connection URL. - //------------------------------------------------------------------ - lldb_private::Error - StartDebugserverProcess (const char *connect_url, - const char *unix_socket_name, - lldb_private::ProcessLaunchInfo &launch_info); - //------------------------------------------------------------------ // Public Request Packets diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index f67e1b5d49c3..d53347a2e383 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -13,6 +13,7 @@ // C Includes #include #include +#include // C++ Includes // Other libraries and framework includes @@ -539,9 +540,11 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri Error GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, - const char *unix_socket_name, // For handshaking - lldb_private::ProcessLaunchInfo &launch_info) + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &port) { + port = 0; + Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; @@ -598,11 +601,34 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); - if (unix_socket_name && unix_socket_name[0]) + 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)) { - debugserver_args.AppendArgument("--unix-socket"); - debugserver_args.AppendArgument(unix_socket_name); + 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'; const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) @@ -617,46 +643,33 @@ GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } - // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); - // debugserver_args.AppendArgument("--log-flags=0x802e0e"); - - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) - { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); - } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); - } - else if (attach_name && attach_name[0]) - { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); - } -#endif // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. -// launch_info.AppendCloseFileAction (STDIN_FILENO); -// launch_info.AppendCloseFileAction (STDOUT_FILENO); -// launch_info.AppendCloseFileAction (STDERR_FILENO); + launch_info.AppendCloseFileAction (STDIN_FILENO); + launch_info.AppendCloseFileAction (STDOUT_FILENO); + launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); + + if (named_pipe_path[0]) + { + File name_pipe_file; + error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); + if (error.Success()) + { + char port_cstr[256]; + port_cstr[0] = '\0'; + size_t num_bytes = sizeof(port_cstr); + error = name_pipe_file.Read(port_cstr, num_bytes); + assert (error.Success()); + assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); + port = Args::StringToUInt32(port_cstr, 0); + name_pipe_file.Close(); + } + Host::Unlink(named_pipe_path); + } + } else { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index a1077957c6a6..98e29e4a3ece 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -108,10 +108,10 @@ public: // Start a debugserver instance on the current host using the // supplied connection URL. //------------------------------------------------------------------ - lldb_private::Error + static lldb_private::Error StartDebugserverProcess (const char *connect_url, - const char *unix_socket_name, - lldb_private::ProcessLaunchInfo &launch_info); + lldb_private::ProcessLaunchInfo &launch_info, + uint16_t &port); void DumpHistory(lldb_private::Stream &strm); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 7cc3a05304d4..d94e0a414f76 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -775,7 +775,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote { // Sleep and wait a bit for debugserver to start to listen... ConnectionFileDescriptor file_conn; - char connect_url[PATH_MAX]; Error error; std::string hostname; // TODO: /tmp/ should not be hardcoded. User might want to override /tmp @@ -796,26 +795,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote // Spawn a new thread to accept the port that gets bound after // binding to port 0 (zero). - lldb::thread_t accept_thread = LLDB_INVALID_HOST_THREAD; - const char *unix_socket_name = NULL; - char unix_socket_name_buf[PATH_MAX] = "/tmp/XXXXXXXXX"; - - if (port == 0) - { - if (::mkstemp (unix_socket_name_buf) == 0) - { - unix_socket_name = unix_socket_name_buf; - ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name); - accept_thread = Host::ThreadCreate (unix_socket_name, - AcceptPortFromInferior, - connect_url, - &error); - } - else - { - error.SetErrorStringWithFormat("failed to make temporary path for a unix socket: %s", strerror(errno)); - } - } if (error.Success()) { @@ -832,9 +811,9 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote debugserver_launch_info.SetMonitorProcessCallback(ReapDebugserverProcess, this, false); - error = StartDebugserverProcess (host_and_port_cstr, - unix_socket_name, - debugserver_launch_info); + error = GDBRemoteCommunication::StartDebugserverProcess (host_and_port_cstr, + debugserver_launch_info, + port); lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID(); @@ -856,32 +835,10 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote { bool success = false; - if (IS_VALID_LLDB_HOST_THREAD(accept_thread)) - { - thread_result_t accept_thread_result = NULL; - if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error)) - { - if (accept_thread_result) - { - port = (intptr_t)accept_thread_result; - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - } - } - } - else - { - char response[256]; - const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); - assert (response_len < sizeof(response)); - //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID(); - success = SendPacketNoLock (response, response_len) > 0; - - } - Host::Unlink (unix_socket_name); + char response[256]; + const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port + m_port_offset); + assert (response_len < sizeof(response)); + success = SendPacketNoLock (response, response_len) > 0; if (!success) { @@ -890,10 +847,6 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote } return success; } - else if (accept_thread) - { - Host::Unlink (unix_socket_name); - } } } return SendErrorResponse (9); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 7f1fbefc1b7e..45278972ec1c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -167,34 +167,6 @@ namespace { } // anonymous namespace end -static bool rand_initialized = false; - -// TODO Randomly assigning a port is unsafe. We should get an unused -// ephemeral port from the kernel and make sure we reserve it before passing -// it to debugserver. - -#if defined (__APPLE__) -#define LOW_PORT (IPPORT_RESERVED) -#define HIGH_PORT (IPPORT_HIFIRSTAUTO) -#else -#define LOW_PORT (1024u) -#define HIGH_PORT (49151u) -#endif - -static inline uint16_t -get_random_port () -{ - if (!rand_initialized) - { - time_t seed = time(NULL); - - rand_initialized = true; - srand(seed); - } - return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; -} - - lldb_private::ConstString ProcessGDBRemote::GetPluginNameStatic() { @@ -728,23 +700,10 @@ ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_ ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - error = StartDebugserverProcess (host_port, launch_info); - if (error.Fail()) - { - if (log) - log->Printf("failed to start debugserver process: %s", error.AsCString()); - return error; - } - - error = ConnectToDebugserver (connect_url); + error = LaunchAndConnectToDebugserver (launch_info); } if (error.Success()) @@ -1040,12 +999,7 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); - - error = StartDebugserverProcess (host_port, attach_info); + error = LaunchAndConnectToDebugserver (attach_info); if (error.Fail()) { @@ -1055,10 +1009,6 @@ ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const Process SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) @@ -1105,12 +1055,8 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait // Make sure we aren't already connected? if (!m_gdb_comm.IsConnected()) { - char host_port[128]; - snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ()); - char connect_url[128]; - snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port); + error = LaunchAndConnectToDebugserver (attach_info); - error = StartDebugserverProcess (host_port, attach_info); if (error.Fail()) { const char *error_string = error.AsCString(); @@ -1119,10 +1065,6 @@ ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait SetExitStatus (-1, error_string); } - else - { - error = ConnectToDebugserver (connect_url); - } } if (error.Success()) @@ -2546,157 +2488,45 @@ ProcessGDBRemote::DoSignal (int signo) } Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url) -{ - ProcessLaunchInfo launch_info; - return StartDebugserverProcess(debugserver_url, launch_info); -} - -Error -ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...") +ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) { Error error; + uint16_t port = 0; if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) { // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; ProcessLaunchInfo debugserver_launch_info; - char debugserver_path[PATH_MAX]; - FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile(); + debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); + debugserver_launch_info.SetUserID(process_info.GetUserID()); - // Always check to see if we have an environment override for the path - // to the debugserver to use and use it if we do. - const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); - if (env_debugserver_path) - debugserver_file_spec.SetFile (env_debugserver_path, false); + error = GDBRemoteCommunication::StartDebugserverProcess ("localhost:0", + debugserver_launch_info, + port); + + if (error.Success ()) + m_debugserver_pid = debugserver_launch_info.GetProcessID(); else - debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = debugserver_file_spec.Exists(); - if (!debugserver_exists) - { - // The debugserver binary is in the LLDB.framework/Resources - // directory. - if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) - { - debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); - debugserver_exists = debugserver_file_spec.Exists(); - if (debugserver_exists) - { - g_debugserver_file_spec = debugserver_file_spec; - } - else - { - g_debugserver_file_spec.Clear(); - debugserver_file_spec.Clear(); - } - } - } - - if (debugserver_exists) - { - debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); - - m_stdio_communication.Clear(); - - Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); - - Args &debugserver_args = debugserver_launch_info.GetArguments(); - char arg_cstr[PATH_MAX]; - - // Start args with "debugserver /file/path -r --" - debugserver_args.AppendArgument(debugserver_path); - debugserver_args.AppendArgument(debugserver_url); - // 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"); - - const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); - if (env_debugserver_log_file) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); - debugserver_args.AppendArgument(arg_cstr); - } - - const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); - if (env_debugserver_log_flags) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); - debugserver_args.AppendArgument(arg_cstr); - } -// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); -// debugserver_args.AppendArgument("--log-flags=0x802e0e"); - - // We currently send down all arguments, attach pids, or attach - // process names in dedicated GDB server packets, so we don't need - // to pass them as arguments. This is currently because of all the - // things we need to setup prior to launching: the environment, - // current working dir, file actions, etc. -#if 0 - // Now append the program arguments - if (inferior_argv) - { - // Terminate the debugserver args so we can now append the inferior args - debugserver_args.AppendArgument("--"); - - for (int i = 0; inferior_argv[i] != NULL; ++i) - debugserver_args.AppendArgument (inferior_argv[i]); - } - else if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); - debugserver_args.AppendArgument (arg_cstr); - } - else if (attach_name && attach_name[0]) - { - if (wait_for_launch) - debugserver_args.AppendArgument ("--waitfor"); - else - debugserver_args.AppendArgument ("--attach"); - debugserver_args.AppendArgument (attach_name); - } -#endif - - ProcessLaunchInfo::FileAction file_action; - - // Close STDIN, STDOUT and STDERR. We might need to redirect them - // to "/dev/null" if we run into any problems. - file_action.Close (STDIN_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDOUT_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - file_action.Close (STDERR_FILENO); - debugserver_launch_info.AppendFileAction (file_action); - - if (log) - { - StreamString strm; - debugserver_args.Dump (&strm); - log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData()); - } - - debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false); - debugserver_launch_info.SetUserID(process_info.GetUserID()); - - error = Host::LaunchProcess(debugserver_launch_info); - - if (error.Success ()) - m_debugserver_pid = debugserver_launch_info.GetProcessID(); - else - m_debugserver_pid = LLDB_INVALID_PROCESS_ID; - - if (error.Fail() || log) - error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path); - } - else - { - error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME); - } + m_debugserver_pid = LLDB_INVALID_PROCESS_ID; if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) StartAsyncThread (); + + if (error.Fail()) + { + Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); + + if (log) + log->Printf("failed to start debugserver process: %s", error.AsCString()); + return error; + } + + char connect_url[128]; + snprintf (connect_url, sizeof(connect_url), "connect://localhost:%u", port); + + error = ConnectToDebugserver (connect_url); + } return error; } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 35244074bab7..ca92504dbdf0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -284,10 +284,7 @@ protected: lldb_private::ThreadList &new_thread_list); lldb_private::Error - StartDebugserverProcess (const char *debugserver_url); - - lldb_private::Error - StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info); + LaunchAndConnectToDebugserver (const lldb_private::ProcessInfo &process_info); void KillDebugserverProcess (); diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 22db738cfeac..6f60839386bf 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -915,7 +915,6 @@ RNBRemote::InitializeRegisters (bool force) if (reg_entry.nub_info.value_regs == NULL) { - DNBLogThreaded("%s -> %u", reg_entry.nub_info.name, reg_data_offset); reg_data_offset += reg_entry.nub_info.size; } diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp index 67dc0093dd96..448db2575a82 100644 --- a/lldb/tools/debugserver/source/RNBSocket.cpp +++ b/lldb/tools/debugserver/source/RNBSocket.cpp @@ -120,20 +120,6 @@ RNBSocket::Listen (const char *listen_host, in_port_t port, PortBoundCallback ca return rnb_err; } - if (callback && port == 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". - socklen_t sa_len = sizeof (sa); - if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) - { - port = ntohs (sa.sin_port); - callback (callback_baton, port); - } - } - error = ::listen (listen_fd, 5); if (error == -1) err.SetError(errno, DNBError::POSIX); @@ -146,6 +132,27 @@ RNBSocket::Listen (const char *listen_host, in_port_t port, PortBoundCallback ca ClosePort (listen_fd, false); return rnb_err; } + + if (callback) + { + // 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) + { + socklen_t sa_len = sizeof (sa); + if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) + { + port = ntohs (sa.sin_port); + callback (callback_baton, port); + } + } + else + { + callback (callback_baton, port); + } + } struct sockaddr_in accept_addr; ::memset (&accept_addr, 0, sizeof accept_addr); diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index baa0fb794008..b0b694c5504a 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -625,73 +625,32 @@ RNBRunLoopPlatform (RNBRemote *remote) return eRNBRunLoopModeExit; } -//---------------------------------------------------------------------- -// Convenience function to set up the remote listening port -// Returns 1 for success 0 for failure. -//---------------------------------------------------------------------- - static void -PortWasBoundCallback (const void *baton, in_port_t port) +PortWasBoundCallbackNamedPipe (const void *baton, in_port_t port) { - //::printf ("PortWasBoundCallback (baton = %p, port = %u)\n", baton, port); - - const char *unix_socket_name = (const char *)baton; - - if (unix_socket_name && unix_socket_name[0]) + const char *named_pipe = (const char *)baton; + if (named_pipe && named_pipe[0]) { - // We were given a unix socket name to use to communicate the port - // that we ended up binding to back to our parent process - struct sockaddr_un saddr_un; - int s = ::socket (AF_UNIX, SOCK_STREAM, 0); - if (s < 0) + int fd = ::open(named_pipe, O_WRONLY); + if (fd > -1) { - perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); - exit(1); + char port_str[64]; + const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port); + // Write the port number as a C string with the NULL terminator + ::write (fd, port_str, port_str_len + 1); + close (fd); } - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; - saddr_un.sun_len = SUN_LEN (&saddr_un); - - if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) - { - perror("error: connect (socket, &saddr_un, saddr_un_len)"); - exit(1); - } - - //::printf ("connect () sucess!!\n"); - - - // We were able to connect to the socket, now write our PID so whomever - // launched us will know this process's ID - RNBLogSTDOUT ("Listening to port %i...\n", port); - - char pid_str[64]; - const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port); - const int bytes_sent = ::send (s, pid_str, pid_str_len, 0); - - if (pid_str_len != bytes_sent) - { - perror("error: send (s, pid_str, pid_str_len, 0)"); - exit (1); - } - - //::printf ("send () sucess!!\n"); - - // We are done with the socket - close (s); } } static int -StartListening (RNBRemote *remote, const char *listen_host, int listen_port, const char *unix_socket_name) +StartListening (RNBRemote *remote, const char *listen_host, int listen_port, 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, PortWasBoundCallback, unix_socket_name) != rnb_success) + if (remote->Comm().Listen(listen_host, listen_port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success) { RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); return 0; @@ -786,7 +745,7 @@ static struct option g_long_options[] = { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization { "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 + { "named-pipe", required_argument, NULL, 'P' }, { NULL, 0, NULL, 0 } }; @@ -838,7 +797,7 @@ main (int argc, char *argv[]) std::string attach_pid_name; std::string arch_name; std::string working_dir; // The new working directory to use for the inferior - std::string unix_socket_name; // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use + std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use 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; @@ -1086,8 +1045,8 @@ main (int argc, char *argv[]) start_mode = eRNBRunLoopModePlatformMode; break; - case 'u': - unix_socket_name.assign (optarg); + case 'P': + named_pipe_path.assign (optarg); break; } } @@ -1306,7 +1265,7 @@ main (int argc, char *argv[]) #endif if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str())) + if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1419,7 +1378,7 @@ main (int argc, char *argv[]) { if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str())) + if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1444,7 +1403,7 @@ main (int argc, char *argv[]) { if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str())) + if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/') @@ -1471,7 +1430,7 @@ main (int argc, char *argv[]) case eRNBRunLoopModePlatformMode: if (listen_port != INT32_MAX) { - if (!StartListening (remote, listen_host.c_str(), listen_port, unix_socket_name.c_str())) + if (!StartListening (remote, listen_host.c_str(), listen_port, named_pipe_path.c_str())) mode = eRNBRunLoopModeExit; } else if (str[0] == '/')