diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
4 files changed, 163 insertions, 57 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index d53347a2e38..04de58bcd4c 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -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::GDBRemoteCommunication(const char *comm_name, 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 (const uint8_t *src, size_t src_len, Stri } 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::StartDebugserverProcess (const char *debugserver_url, // 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)) + { + 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)) { - debugserver_args.AppendArgument("--named-pipe"); - debugserver_args.AppendArgument(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::StartDebugserverProcess (const char *debugserver_url, } Host::Unlink(named_pipe_path); } - + else + { + // Make sure we actually connect with the debugserver... + JoinListenThread(); + } } else { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 98e29e4a3ec..a21679e51dc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -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 //------------------------------------------------------------------ diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index 56414e213b1..50cdd406008 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -812,9 +812,9 @@ GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote 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_vFile_Open (StringExtractorGDBRemote &packe 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'); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 45278972ec1..c6dc6cff982 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -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::LaunchAndConnectToDebugserver (const ProcessInfo &process_info 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::LaunchAndConnectToDebugserver (const ProcessInfo &process_info 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; |