diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp | 369 |
1 files changed, 363 insertions, 6 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 6a6e063e35b..e3183fca1db 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/ConnectionFileDescriptor.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" +#include "lldb/Core/StreamGDBRemote.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/Endian.h" #include "lldb/Host/Host.h" @@ -2137,21 +2138,37 @@ GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t } uint16_t -GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () +GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort (lldb::pid_t &pid) { + pid = LLDB_INVALID_PROCESS_ID; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false)) + StreamString stream; + stream.PutCString("qLaunchGDBServer:port:0;"); + std::string hostname; + if (Host::GetHostname (hostname)) + { + // Make the GDB server we launch only accept connections from this host + stream.Printf("host:%s;", hostname.c_str()); + } + else + { + // Make the GDB server we launch accept connections from any host since we can't figure out the hostname + stream.Printf("host:*;"); + } + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) { std::string name; std::string value; uint16_t port = 0; - //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { - if (name.size() == 4 && name.compare("port") == 0) + if (name.compare("port") == 0) port = Args::StringToUInt32(value.c_str(), 0, 0); -// if (name.size() == 3 && name.compare("pid") == 0) -// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); + else if (name.compare("pid") == 0) + pid = Args::StringToUInt64(value.c_str(), LLDB_INVALID_PROCESS_ID, 0); } return port; } @@ -2159,6 +2176,23 @@ GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort () } bool +GDBRemoteCommunicationClient::KillSpawnedProcess (lldb::pid_t pid) +{ + StreamString stream; + stream.Printf ("qKillSpawnedProcess:%" PRId64 , pid); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + pid = LLDB_INVALID_PROCESS_ID; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.IsOKResponse()) + return true; + } + return false; +} + +bool GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid) { if (m_curr_tid == tid) @@ -2351,3 +2385,326 @@ GDBRemoteCommunicationClient::GetShlibInfoAddr() return LLDB_INVALID_ADDRESS; } +lldb_private::Error +GDBRemoteCommunicationClient::RunShellCommand (const char *command, // Shouldn't be NULL + const char *working_dir, // Pass NULL to use the current working directory + int *status_ptr, // Pass NULL if you don't want the process exit status + int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit + std::string *command_output, // Pass NULL if you don't want the command output + uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_RunCommand:"); + stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutChar(','); + stream.PutHex32(timeout_sec); + if (working_dir && *working_dir) + { + stream.PutChar(','); + stream.PutBytesAsRawHex8(working_dir, strlen(working_dir)); + } + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return Error("malformed reply"); + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t exitcode = response.GetHexMaxU32(false, UINT32_MAX); + if (exitcode == UINT32_MAX) + return Error("unable to run remote process"); + else if (status_ptr) + *status_ptr = exitcode; + if (response.GetChar() != ',') + return Error("malformed reply"); + uint32_t signo = response.GetHexMaxU32(false, UINT32_MAX); + if (signo_ptr) + *signo_ptr = signo; + if (response.GetChar() != ',') + return Error("malformed reply"); + std::string output; + response.GetEscapedBinaryData(output); + if (command_output) + command_output->assign(output); + return Error(); + } + return Error("unable to send packet"); +} + +uint32_t +GDBRemoteCommunicationClient::MakeDirectory (const std::string &path, + mode_t mode) +{ + lldb_private::StreamString stream; + stream.PutCString("qPlatform_IO_MkDir:"); + stream.PutHex32(mode); + stream.PutChar(','); + stream.PutBytesAsRawHex8(path.c_str(), path.size()); + const char *packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return response.GetHexMaxU32(false, UINT32_MAX); + } + return UINT32_MAX; + +} + +static uint64_t +ParseHostIOPacketResponse (StringExtractorGDBRemote &response, + uint64_t fail_result, + Error &error) +{ + response.SetFilePos(0); + if (response.GetChar() != 'F') + return fail_result; + int32_t result = response.GetS32 (-2); + if (result == -2) + return fail_result; + if (response.GetChar() == ',') + { + int result_errno = response.GetS32 (-2); + if (result_errno != -2) + error.SetError(result_errno, eErrorTypePOSIX); + else + error.SetError(-1, eErrorTypeGeneric); + } + else + error.Clear(); + return result; +} +lldb::user_id_t +GDBRemoteCommunicationClient::OpenFile (const lldb_private::FileSpec& file_spec, + uint32_t flags, + mode_t mode, + Error &error) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:open:"); + std::string path (file_spec.GetPath()); + if (path.empty()) + return UINT64_MAX; + stream.PutCStringAsRawHex8(path.c_str()); + stream.PutChar(','); + const uint32_t posix_open_flags = File::ConvertOpenOptionsForPOSIXOpen(flags); + stream.PutHex32(posix_open_flags); + stream.PutChar(','); + stream.PutHex32(mode); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return ParseHostIOPacketResponse (response, UINT64_MAX, error); + } + return UINT64_MAX; +} + +bool +GDBRemoteCommunicationClient::CloseFile (lldb::user_id_t fd, + Error &error) +{ + lldb_private::StreamString stream; + stream.Printf("vFile:close:%i", (int)fd); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + return ParseHostIOPacketResponse (response, -1, error) == 0; + } + return UINT64_MAX; +} + +// Extension of host I/O packets to get the file size. +lldb::user_id_t +GDBRemoteCommunicationClient::GetFileSize (const lldb_private::FileSpec& file_spec) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:size:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return UINT64_MAX; + uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX); + return retcode; + } + return UINT64_MAX; +} + +uint32_t +GDBRemoteCommunicationClient::GetFilePermissions(const lldb_private::FileSpec& file_spec, Error &error) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:mode:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + { + error.SetErrorStringWithFormat ("invalid response to '%s' packet", packet); + return 0; + } + const uint32_t mode = response.GetS32(-1); + if (mode == -1) + { + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + else + error.SetErrorToGenericError(); + } + } + else + error.Clear(); + return mode & (S_IRWXU|S_IRWXG|S_IRWXO); + } + else + { + error.SetErrorStringWithFormat ("failed to send '%s' packet", packet); + } + return 0; +} + +uint64_t +GDBRemoteCommunicationClient::ReadFile (lldb::user_id_t fd, + uint64_t offset, + void *dst, + uint64_t dst_len, + Error &error) +{ + lldb_private::StreamString stream; + stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return 0; + uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX); + if (retcode == UINT32_MAX) + return retcode; + const char next = (response.Peek() ? *response.Peek() : 0); + if (next == ',') + return 0; + if (next == ';') + { + response.GetChar(); // skip the semicolon + std::string buffer; + if (response.GetEscapedBinaryData(buffer)) + { + const uint64_t data_to_write = std::min<uint64_t>(dst_len, buffer.size()); + if (data_to_write > 0) + memcpy(dst, &buffer[0], data_to_write); + return data_to_write; + } + } + } + return 0; +} + +uint64_t +GDBRemoteCommunicationClient::WriteFile (lldb::user_id_t fd, + uint64_t offset, + const void* src, + uint64_t src_len, + Error &error) +{ + lldb_private::StreamGDBRemote stream; + stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); + stream.PutEscapedBytes(src, src_len); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + { + error.SetErrorStringWithFormat("write file failed"); + return 0; + } + uint64_t bytes_written = response.GetU64(UINT64_MAX); + if (bytes_written == UINT64_MAX) + { + error.SetErrorToGenericError(); + if (response.GetChar() == ',') + { + int response_errno = response.GetS32(-1); + if (response_errno > 0) + error.SetError(response_errno, lldb::eErrorTypePOSIX); + } + return 0; + } + return bytes_written; + } + else + { + error.SetErrorString ("failed to send vFile:pwrite packet"); + } + return 0; +} + +// Extension of host I/O packets to get whether a file exists. +bool +GDBRemoteCommunicationClient::GetFileExists (const lldb_private::FileSpec& file_spec) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:exists:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + bool retcode = (response.GetChar() != '0'); + return retcode; + } + return false; +} + +bool +GDBRemoteCommunicationClient::CalculateMD5 (const lldb_private::FileSpec& file_spec, + uint64_t &high, + uint64_t &low) +{ + lldb_private::StreamString stream; + stream.PutCString("vFile:MD5:"); + std::string path (file_spec.GetPath()); + stream.PutCStringAsRawHex8(path.c_str()); + const char* packet = stream.GetData(); + int packet_len = stream.GetSize(); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, packet_len, response, false)) + { + if (response.GetChar() != 'F') + return false; + if (response.GetChar() != ',') + return false; + if (response.Peek() && *response.Peek() == 'x') + return false; + low = response.GetHexMaxU64(false, UINT64_MAX); + high = response.GetHexMaxU64(false, UINT64_MAX); + return true; + } + return false; +} |