diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp | 467 |
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) { |