summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp')
-rw-r--r--contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp263
1 files changed, 196 insertions, 67 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index f67e1b5..72600d8 100644
--- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -13,9 +13,11 @@
// C Includes
#include <limits.h>
#include <string.h>
+#include <sys/stat.h>
// 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"
@@ -143,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 ()
{
}
@@ -195,14 +199,14 @@ GDBRemoteCommunication::SendNack ()
return bytes_written;
}
-size_t
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
{
Mutex::Locker locker(m_sequence_mutex);
return SendPacketNoLock (payload, payload_length);
}
-size_t
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
{
if (IsConnected())
@@ -235,32 +239,32 @@ GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_le
if (bytes_written == packet.GetSize())
{
if (GetSendAcks ())
- {
- if (GetAck () != '+')
- {
- if (log)
- log->Printf("get ack failed...");
- return 0;
- }
- }
+ return GetAck ();
+ else
+ return PacketResult::Success;
}
else
{
if (log)
log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
}
- return bytes_written;
}
- return 0;
+ return PacketResult::ErrorSendFailed;
}
-char
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::GetAck ()
{
StringExtractorGDBRemote packet;
- if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1)
- return packet.GetChar();
- return 0;
+ PacketResult result = WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ());
+ if (result == PacketResult::Success)
+ {
+ if (packet.GetResponseType() == StringExtractorGDBRemote::ResponseType::eAck)
+ return PacketResult::Success;
+ else
+ return PacketResult::ErrorSendAck;
+ }
+ return result;
}
bool
@@ -280,7 +284,7 @@ GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
}
-size_t
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)
{
uint8_t buffer[8192];
@@ -290,9 +294,10 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
// Check for a packet from our cache first without trying any reading...
if (CheckForPacket (NULL, 0, packet))
- return packet.GetStringRef().size();
+ return PacketResult::Success;
bool timed_out = false;
+ bool disconnected = false;
while (IsConnected() && !timed_out)
{
lldb::ConnectionStatus status = eConnectionStatusNoConnection;
@@ -309,7 +314,7 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
if (bytes_read > 0)
{
if (CheckForPacket (buffer, bytes_read, packet))
- return packet.GetStringRef().size();
+ return PacketResult::Success;
}
else
{
@@ -326,13 +331,19 @@ GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtrac
case eConnectionStatusNoConnection:
case eConnectionStatusLostConnection:
case eConnectionStatusError:
+ disconnected = true;
Disconnect();
break;
}
}
}
- packet.Clear ();
- return 0;
+ packet.Clear ();
+ if (disconnected)
+ return PacketResult::ErrorDisconnected;
+ if (timed_out)
+ return PacketResult::ErrorReplyTimeout;
+ else
+ return PacketResult::ErrorReplyFailed;
}
bool
@@ -486,6 +497,13 @@ GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, Stri
for (int i = 0; i < repeat_count; ++i)
packet_str.push_back(char_to_repeat);
}
+ else if (*c == 0x7d)
+ {
+ // 0x7d is the escape character. The next character is to
+ // be XOR'd with 0x20.
+ char escapee = *++c ^ 0x20;
+ packet_str.push_back(escapee);
+ }
else
{
packet_str.push_back(*c);
@@ -538,18 +556,65 @@ 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)
+GDBRemoteCommunication::StartListenThread (const char *hostname, uint16_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, 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 *hostname,
+ uint16_t in_port,
+ lldb_private::ProcessLaunchInfo &launch_info,
+ uint16_t &out_port)
{
+ out_port = in_port;
Error error;
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec;
- // This function will fill in the launch information for the debugserver
- // instance that gets launched.
- launch_info.Clear();
-
char debugserver_path[PATH_MAX];
FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
@@ -591,19 +656,88 @@ 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
+ char host_and_port[128];
+ if (hostname)
+ {
+ snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port);
+ debugserver_args.AppendArgument(host_and_port);
+ }
+ else
+ {
+ host_and_port[0] = '\0';
+ }
+
// 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");
-
- if (unix_socket_name && unix_socket_name[0])
+
+ char named_pipe_path[PATH_MAX];
+ named_pipe_path[0] = '\0';
+
+ bool listen = false;
+ if (host_and_port[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"
+
+ if (in_port == 0)
+ {
+ // Binding to port zero, we need to figure out what port it ends up
+ // using using a named pipe...
+ 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 defined(_MSC_VER)
+ if ( false )
+#else
+ if (::mkfifo(named_pipe_path, 0600) == 0)
+#endif
+ {
+ debugserver_args.AppendArgument("--named-pipe");
+ debugserver_args.AppendArgument(named_pipe_path);
+ }
+ }
+ }
+ else
+ {
+ listen = true;
+ }
+ }
+ else
{
- debugserver_args.AppendArgument("--unix-socket");
- debugserver_args.AppendArgument(unix_socket_name);
+ // 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 ();
+ out_port = connection->GetBoundPort(3);
+ assert (out_port != 0);
+ char port_cstr[32];
+ snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_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)
{
@@ -617,46 +751,41 @@ 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)
+ // 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);
+
+ error = Host::LaunchProcess(launch_info);
+
+ if (named_pipe_path[0])
{
- // 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]);
+ 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');
+ out_port = Args::StringToUInt32(port_cstr, 0);
+ name_pipe_file.Close();
+ }
+ Host::Unlink(named_pipe_path);
}
- else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ else if (listen)
{
- ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
- debugserver_args.AppendArgument (arg_cstr);
+
}
- else if (attach_name && attach_name[0])
+ else
{
- if (wait_for_launch)
- debugserver_args.AppendArgument ("--waitfor");
- else
- debugserver_args.AppendArgument ("--attach");
- debugserver_args.AppendArgument (attach_name);
+ // Make sure we actually connect with the debugserver...
+ JoinListenThread();
}
-#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);
-
- error = Host::LaunchProcess(launch_info);
}
else
{
OpenPOWER on IntegriCloud