summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp467
1 files changed, 413 insertions, 54 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index c2431380fd9..9379077335d 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
// Project includes
#include "Utility/StringExtractorGDBRemote.h"
@@ -33,9 +34,15 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// GDBRemoteCommunicationServer constructor
//----------------------------------------------------------------------
-GDBRemoteCommunicationServer::GDBRemoteCommunicationServer() :
- GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet"),
- m_async_thread (LLDB_INVALID_HOST_THREAD)
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
+ GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_process_launch_info (),
+ m_process_launch_error (),
+ m_proc_infos (),
+ m_proc_infos_index (0),
+ m_lo_port_num (0),
+ m_hi_port_num (0)
{
}
@@ -82,45 +89,76 @@ GDBRemoteCommunicationServer::GetPacketAndSendResponse (const TimeValue* timeout
const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
switch (packet_type)
{
- case StringExtractorGDBRemote::eServerPacketType_nack:
- case StringExtractorGDBRemote::eServerPacketType_ack:
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_invalid:
- error.SetErrorString("invalid packet");
- quit = true;
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_interrupt:
- error.SetErrorString("interrupt received");
- interrupt = true;
- break;
-
- case StringExtractorGDBRemote::eServerPacketType_unimplemented:
- return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;
-
- case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
- return Handle_qHostInfo (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
- return Handle_qProcessInfoPID (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
- return Handle_qfProcessInfo (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
- return Handle_qsProcessInfo (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qUserName:
- return Handle_qUserName (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qGroupName:
- return Handle_qGroupName (packet);
-
- case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
- return Handle_qSpeedTest (packet);
- case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
- return Handle_QStartNoAckMode (packet);
+ case StringExtractorGDBRemote::eServerPacketType_nack:
+ case StringExtractorGDBRemote::eServerPacketType_ack:
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_invalid:
+ error.SetErrorString("invalid packet");
+ quit = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_interrupt:
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_unimplemented:
+ return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;
+
+ case StringExtractorGDBRemote::eServerPacketType_A:
+ return Handle_A (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
+ return Handle_qfProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
+ return Handle_qsProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qC:
+ return Handle_qC (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
+ return Handle_qHostInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
+ return Handle_qLaunchGDBServer (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
+ return Handle_qLaunchSuccess (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qGroupName:
+ return Handle_qGroupName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
+ return Handle_qProcessInfoPID (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
+ return Handle_qSpeedTest (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qUserName:
+ return Handle_qUserName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
+ return Handle_QEnvironment (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
+ return Handle_QSetDisableASLR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
+ return Handle_QSetSTDIN (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
+ return Handle_QSetSTDOUT (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
+ return Handle_QSetSTDERR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
+ return Handle_QSetWorkingDir (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
+ return Handle_QStartNoAckMode (packet);
}
return true;
}
@@ -236,13 +274,13 @@ GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet
}
static void
-CreateProcessInfoResponse (const ProcessInfo &proc_info, StreamString &response)
+CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
{
response.Printf ("pid:%i;ppid:%i;uid:%i;gid:%i;euid:%i;egid:%i;",
proc_info.GetProcessID(),
proc_info.GetParentProcessID(),
- proc_info.GetRealUserID(),
- proc_info.GetRealGroupID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
proc_info.GetEffectiveUserID(),
proc_info.GetEffectiveGroupID());
response.PutCString ("name:");
@@ -262,11 +300,11 @@ bool
GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
{
// Packet format: "qProcessInfoPID:%i" where %i is the pid
- packet.SetFilePos(strlen ("qProcessInfoPID:"));
+ packet.SetFilePos(::strlen ("qProcessInfoPID:"));
lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
if (pid != LLDB_INVALID_PROCESS_ID)
{
- ProcessInfo proc_info;
+ ProcessInstanceInfo proc_info;
if (Host::GetProcessInfo(pid, proc_info))
{
StreamString response;
@@ -283,8 +321,8 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa
m_proc_infos_index = 0;
m_proc_infos.Clear();
- ProcessInfoMatch match_info;
- packet.SetFilePos(strlen ("qfProcessInfo"));
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
if (packet.GetChar() == ':')
{
@@ -337,11 +375,11 @@ GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &pa
}
else if (key.compare("uid") == 0)
{
- match_info.GetProcessInfo().SetRealUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
}
else if (key.compare("gid") == 0)
{
- match_info.GetProcessInfo().SetRealGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
}
else if (key.compare("euid") == 0)
{
@@ -395,7 +433,7 @@ bool
GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
{
// Packet format: "qUserName:%i" where %i is the uid
- packet.SetFilePos(strlen ("qUserName:"));
+ packet.SetFilePos(::strlen ("qUserName:"));
uint32_t uid = packet.GetU32 (UINT32_MAX);
if (uid != UINT32_MAX)
{
@@ -415,7 +453,7 @@ bool
GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
{
// Packet format: "qGroupName:%i" where %i is the gid
- packet.SetFilePos(strlen ("qGroupName:"));
+ packet.SetFilePos(::strlen ("qGroupName:"));
uint32_t gid = packet.GetU32 (UINT32_MAX);
if (gid != UINT32_MAX)
{
@@ -433,7 +471,7 @@ GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packe
bool
GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
{
- packet.SetFilePos(strlen ("qSpeedTest:"));
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
std::string key;
std::string value;
@@ -466,6 +504,327 @@ GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packe
}
return SendErrorResponse (7);
}
+
+
+static void *
+AcceptPortFromInferior (void *arg)
+{
+ const char *connect_url = (const char *)arg;
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
+ {
+ char pid_str[256];
+ ::memset (pid_str, 0, sizeof(pid_str));
+ ConnectionStatus status;
+ const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), status, NULL);
+ if (pid_str_len > 0)
+ {
+ int pid = atoi (pid_str);
+ return (void *)(intptr_t)pid;
+ }
+ }
+ return NULL;
+}
+//
+//static bool
+//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+//{
+// const int time_delta_usecs = 100000;
+// const int num_retries = timeout_in_seconds/time_delta_usecs;
+// for (int i=0; i<num_retries; i++)
+// {
+// struct proc_bsdinfo bsd_info;
+// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+// (uint64_t) 0,
+// &bsd_info,
+// PROC_PIDTBSDINFO_SIZE);
+//
+// switch (error)
+// {
+// case EINVAL:
+// case ENOTSUP:
+// case ESRCH:
+// case EPERM:
+// return false;
+//
+// default:
+// break;
+//
+// case 0:
+// if (bsd_info.pbi_status == SSTOP)
+// return true;
+// }
+// ::usleep (time_delta_usecs);
+// }
+// return false;
+//}
+
+bool
+GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // separated hex encoded argument value list, but we will stay true to the
+ // documented version of the 'A' packet here...
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument index. We ignore this really becuase
+ // who would really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteString(arg) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes lft
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+ m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
+ m_process_launch_error = Host::LaunchProcess (m_process_launch_info);
+ if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ return SendOKResponse ();
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ StreamString response;
+ response.Printf("QC%x", pid);
+ if (m_is_platform)
+ {
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
+ }
+ return SendPacket (response);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ char connect_url[PATH_MAX];
+ Error error;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ if (::mktemp (unix_socket_name) == NULL)
+ {
+ error.SetErrorString ("failed to make temporary path for a unix socket");
+ }
+ else
+ {
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+ lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
+ AcceptPortFromInferior,
+ connect_url,
+ &error);
+
+ if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
+ {
+ // Spawn a debugserver and try to get
+ ProcessLaunchInfo debugserver_launch_info;
+ error = StartDebugserverProcess ("localhost:0",
+ unix_socket_name,
+ debugserver_launch_info);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+ if (error.Success())
+ {
+ bool success = false;
+
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ {
+ if (accept_thread_result)
+ {
+ uint16_t port = (intptr_t)accept_thread_result;
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%u;port:%u;", debugserver_pid, port);
+ assert (response_len < sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacket (response, response_len) > 0;
+ }
+ }
+ ::unlink (unix_socket_name);
+
+ if (!success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
+ }
+ return success;
+ }
+ }
+ }
+ }
+ return SendErrorResponse (13);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacket (response);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (9);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ m_process_launch_info.SwapWorkingDirectory (path);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (10);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
bool
GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
{
OpenPOWER on IntegriCloud