aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
commitc0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch)
treef42add1021b9f2ac6a69ac7cf6c4499962739a45 /lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
parent344a3780b2e33f6ca763666c380202b18aab72a3 (diff)
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp623
1 files changed, 356 insertions, 267 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index b16aed4f5c90..78e722eee080 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -16,7 +16,6 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/HostInfo.h"
-#include "lldb/Host/StringConvert.h"
#include "lldb/Host/XML.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/MemoryRegionInfo.h"
@@ -65,6 +64,8 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true),
m_qSymbol_requests_done(false), m_supports_qModuleInfo(true),
m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true),
+ m_supports_vFileSize(true), m_supports_vFileMode(true),
+ m_supports_vFileExists(true), m_supports_vRun(true),
m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(),
m_hostname(), m_gdb_server_name(), m_default_packet_timeout(0),
@@ -82,6 +83,8 @@ bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) {
// Start the read thread after we send the handshake ack since if we fail to
// send the handshake ack, there is no reason to continue...
+ std::chrono::steady_clock::time_point start_of_handshake =
+ std::chrono::steady_clock::now();
if (SendAck()) {
// Wait for any responses that might have been queued up in the remote
// GDB server and flush them all
@@ -97,8 +100,24 @@ bool GDBRemoteCommunicationClient::HandshakeWithServer(Status *error_ptr) {
if (QueryNoAckModeSupported()) {
return true;
} else {
- if (error_ptr)
- error_ptr->SetErrorString("failed to get reply to handshake packet");
+ std::chrono::steady_clock::time_point end_of_handshake =
+ std::chrono::steady_clock::now();
+ auto handshake_timeout =
+ std::chrono::duration<double>(end_of_handshake - start_of_handshake)
+ .count();
+ if (error_ptr) {
+ if (packet_result == PacketResult::ErrorDisconnected)
+ error_ptr->SetErrorString("Connection shut down by remote side "
+ "while waiting for reply to initial "
+ "handshake packet");
+ else if (packet_result == PacketResult::ErrorReplyTimeout)
+ error_ptr->SetErrorStringWithFormat(
+ "failed to get reply to handshake packet within timeout of "
+ "%.1f seconds",
+ handshake_timeout);
+ else
+ error_ptr->SetErrorString("failed to get reply to handshake packet");
+ }
}
} else {
if (error_ptr)
@@ -257,12 +276,14 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) {
m_attach_or_wait_reply = eLazyBoolCalculate;
m_avoid_g_packets = eLazyBoolCalculate;
m_supports_multiprocess = eLazyBoolCalculate;
+ m_supports_qSaveCore = eLazyBoolCalculate;
m_supports_qXfer_auxv_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_read = eLazyBoolCalculate;
m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate;
m_supports_qXfer_features_read = eLazyBoolCalculate;
m_supports_qXfer_memory_map_read = eLazyBoolCalculate;
m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate;
+ m_uses_native_signals = eLazyBoolCalculate;
m_supports_qProcessInfoPID = true;
m_supports_qfProcessInfo = true;
m_supports_qUserName = true;
@@ -312,13 +333,16 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_qEcho = eLazyBoolNo;
m_supports_QPassSignals = eLazyBoolNo;
m_supports_memory_tagging = eLazyBoolNo;
+ m_supports_qSaveCore = eLazyBoolNo;
+ m_uses_native_signals = eLazyBoolNo;
m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
// not, we assume no limit
// build the qSupported packet
std::vector<std::string> features = {"xmlRegisters=i386,arm,mips,arc",
- "multiprocess+"};
+ "multiprocess+", "fork-events+",
+ "vfork-events+"};
StreamString packet;
packet.PutCString("qSupported");
for (uint32_t i = 0; i < features.size(); ++i) {
@@ -333,10 +357,7 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
// configuration of the transport before attaching/launching the process.
m_qSupported_response = response.GetStringRef().str();
- llvm::SmallVector<llvm::StringRef, 16> server_features;
- response.GetStringRef().split(server_features, ';');
-
- for (llvm::StringRef x : server_features) {
+ for (llvm::StringRef x : llvm::split(response.GetStringRef(), ';')) {
if (x == "qXfer:auxv:read+")
m_supports_qXfer_auxv_read = eLazyBoolYes;
else if (x == "qXfer:libraries-svr4:read+")
@@ -358,6 +379,10 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() {
m_supports_multiprocess = eLazyBoolYes;
else if (x == "memory-tagging+")
m_supports_memory_tagging = eLazyBoolYes;
+ else if (x == "qSaveCore+")
+ m_supports_qSaveCore = eLazyBoolYes;
+ else if (x == "native-signals+")
+ m_uses_native_signals = eLazyBoolYes;
// Look for a list of compressions in the features list e.g.
// qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib-
// deflate,lzma
@@ -500,6 +525,10 @@ LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported(
return eLazyBoolNo;
}
+bool GDBRemoteCommunicationClient::GetSaveCoreSupported() const {
+ return m_supports_qSaveCore == eLazyBoolYes;
+}
+
StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() {
// Get information on all threads at one using the "jThreadsInfo" packet
StructuredData::ObjectSP object_sp;
@@ -661,54 +690,6 @@ bool GDBRemoteCommunicationClient::GetxPacketSupported() {
return m_supports_x;
}
-GDBRemoteCommunicationClient::PacketResult
-GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses(
- const char *payload_prefix, std::string &response_string) {
- Lock lock(*this);
- if (!lock) {
- Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS |
- GDBR_LOG_PACKETS));
- LLDB_LOGF(log,
- "error: failed to get packet sequence mutex, not sending "
- "packets with prefix '%s'",
- payload_prefix);
- return PacketResult::ErrorNoSequenceLock;
- }
-
- response_string = "";
- std::string payload_prefix_str(payload_prefix);
- unsigned int response_size = 0x1000;
- if (response_size > GetRemoteMaxPacketSize()) { // May send qSupported packet
- response_size = GetRemoteMaxPacketSize();
- }
-
- for (unsigned int offset = 0; true; offset += response_size) {
- StringExtractorGDBRemote this_response;
- // Construct payload
- char sizeDescriptor[128];
- snprintf(sizeDescriptor, sizeof(sizeDescriptor), "%x,%x", offset,
- response_size);
- PacketResult result = SendPacketAndWaitForResponseNoLock(
- payload_prefix_str + sizeDescriptor, this_response);
- if (result != PacketResult::Success)
- return result;
-
- const std::string &this_string = std::string(this_response.GetStringRef());
-
- // Check for m or l as first character; l seems to mean this is the last
- // chunk
- char first_char = *this_string.c_str();
- if (first_char != 'm' && first_char != 'l') {
- return PacketResult::ErrorReplyInvalid;
- }
- // Concatenate the result so far (skipping 'm' or 'l')
- response_string.append(this_string, 1, std::string::npos);
- if (first_char == 'l')
- // We're done
- return PacketResult::Success;
- }
-}
-
lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) {
if (allow_lazy && m_curr_pid_is_valid == eLazyBoolYes)
return m_curr_pid;
@@ -765,6 +746,11 @@ bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) {
PacketResult::Success) {
if (response.IsOKResponse())
return true;
+ // GDB does not implement qLaunchSuccess -- but if we used vRun,
+ // then we already received a successful launch indication via stop
+ // reason.
+ if (response.IsUnsupportedResponse() && m_supports_vRun)
+ return true;
if (response.GetChar() == 'E') {
// A string the describes what failed when launching...
error_str = std::string(response.GetStringRef().substr(1));
@@ -803,6 +789,36 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket(
}
}
if (!argv.empty()) {
+ // try vRun first
+ if (m_supports_vRun) {
+ StreamString packet;
+ packet.PutCString("vRun");
+ for (const char *arg : argv) {
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(arg, strlen(arg));
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return -1;
+
+ if (response.IsErrorResponse()) {
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ return -1;
+ }
+ // vRun replies with a stop reason packet
+ // FIXME: right now we just discard the packet and LLDB queries
+ // for stop reason again
+ if (!response.IsUnsupportedResponse())
+ return 0;
+
+ m_supports_vRun = false;
+ }
+
+ // fallback to A
StreamString packet;
packet.PutChar('A');
for (size_t i = 0, n = argv.size(); i < n; ++i) {
@@ -839,7 +855,6 @@ int GDBRemoteCommunicationClient::SendEnvironment(const Environment &env) {
int GDBRemoteCommunicationClient::SendEnvironmentPacket(
char const *name_equal_value) {
if (name_equal_value && name_equal_value[0]) {
- StreamString packet;
bool send_hex_encoding = false;
for (const char *p = name_equal_value; *p != '\0' && !send_hex_encoding;
++p) {
@@ -861,33 +876,43 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket(
}
StringExtractorGDBRemote response;
- if (send_hex_encoding) {
- if (m_supports_QEnvironmentHexEncoded) {
- packet.PutCString("QEnvironmentHexEncoded:");
- packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value));
- if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
- PacketResult::Success) {
- if (response.IsOKResponse())
- return 0;
- uint8_t error = response.GetError();
- if (error)
- return error;
- if (response.IsUnsupportedResponse())
- m_supports_QEnvironmentHexEncoded = false;
- }
+ // Prefer sending unencoded, if possible and the server supports it.
+ if (!send_hex_encoding && m_supports_QEnvironment) {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return -1;
+
+ if (response.IsOKResponse())
+ return 0;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironment = false;
+ else {
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ return -1;
}
+ }
- } else if (m_supports_QEnvironment) {
- packet.Printf("QEnvironment:%s", name_equal_value);
- if (SendPacketAndWaitForResponse(packet.GetString(), response) ==
- PacketResult::Success) {
- if (response.IsOKResponse())
- return 0;
+ if (m_supports_QEnvironmentHexEncoded) {
+ StreamString packet;
+ packet.PutCString("QEnvironmentHexEncoded:");
+ packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value));
+ if (SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ PacketResult::Success)
+ return -1;
+
+ if (response.IsOKResponse())
+ return 0;
+ if (response.IsUnsupportedResponse())
+ m_supports_QEnvironmentHexEncoded = false;
+ else {
uint8_t error = response.GetError();
if (error)
return error;
- if (response.IsUnsupportedResponse())
- m_supports_QEnvironment = false;
+ return -1;
}
}
}
@@ -949,26 +974,21 @@ llvm::VersionTuple GDBRemoteCommunicationClient::GetMacCatalystVersion() {
return m_maccatalyst_version;
}
-bool GDBRemoteCommunicationClient::GetOSBuildString(std::string &s) {
+llvm::Optional<std::string> GDBRemoteCommunicationClient::GetOSBuildString() {
if (GetHostInfo()) {
- if (!m_os_build.empty()) {
- s = m_os_build;
- return true;
- }
+ if (!m_os_build.empty())
+ return m_os_build;
}
- s.clear();
- return false;
+ return llvm::None;
}
-bool GDBRemoteCommunicationClient::GetOSKernelDescription(std::string &s) {
+llvm::Optional<std::string>
+GDBRemoteCommunicationClient::GetOSKernelDescription() {
if (GetHostInfo()) {
- if (!m_os_kernel.empty()) {
- s = m_os_kernel;
- return true;
- }
+ if (!m_os_kernel.empty())
+ return m_os_kernel;
}
- s.clear();
- return false;
+ return llvm::None;
}
bool GDBRemoteCommunicationClient::GetHostname(std::string &s) {
@@ -1093,9 +1113,8 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression(
if (avail_type != CompressionType::None) {
StringExtractorGDBRemote response;
- llvm::Twine packet = "QEnableCompression:type:" + avail_name + ";";
- if (SendPacketAndWaitForResponse(packet.str(), response) !=
- PacketResult::Success)
+ std::string packet = "QEnableCompression:type:" + avail_name.str() + ";";
+ if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success)
return;
if (response.IsOKResponse()) {
@@ -1360,24 +1379,6 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) {
return m_qHostInfo_is_valid == eLazyBoolYes;
}
-int GDBRemoteCommunicationClient::SendAttach(
- lldb::pid_t pid, StringExtractorGDBRemote &response) {
- if (pid != LLDB_INVALID_PROCESS_ID) {
- char packet[64];
- const int packet_len =
- ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, pid);
- UNUSED_IF_ASSERT_DISABLED(packet_len);
- assert(packet_len < (int)sizeof(packet));
- if (SendPacketAndWaitForResponse(packet, response) ==
- PacketResult::Success) {
- if (response.IsErrorResponse())
- return response.GetError();
- return 0;
- }
- }
- return -1;
-}
-
int GDBRemoteCommunicationClient::SendStdinNotification(const char *data,
size_t data_len) {
StreamString packet;
@@ -1457,9 +1458,12 @@ bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) {
return false;
}
-Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) {
+Status GDBRemoteCommunicationClient::Detach(bool keep_stopped,
+ lldb::pid_t pid) {
Status error;
+ lldb_private::StreamString packet;
+ packet.PutChar('D');
if (keep_stopped) {
if (m_supports_detach_stay_stopped == eLazyBoolCalculate) {
char packet[64];
@@ -1481,17 +1485,27 @@ Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) {
error.SetErrorString("Stays stopped not supported by this target.");
return error;
} else {
- StringExtractorGDBRemote response;
- PacketResult packet_result = SendPacketAndWaitForResponse("D1", response);
- if (packet_result != PacketResult::Success)
- error.SetErrorString("Sending extended disconnect packet failed.");
+ packet.PutChar('1');
}
- } else {
- StringExtractorGDBRemote response;
- PacketResult packet_result = SendPacketAndWaitForResponse("D", response);
- if (packet_result != PacketResult::Success)
- error.SetErrorString("Sending disconnect packet failed.");
}
+
+ if (m_supports_multiprocess) {
+ // Some servers (e.g. qemu) require specifying the PID even if only a single
+ // process is running.
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ pid = GetCurrentProcessID();
+ packet.PutChar(';');
+ packet.PutHex64(pid);
+ } else if (pid != LLDB_INVALID_PROCESS_ID) {
+ error.SetErrorString("Multiprocess extension not supported by the server.");
+ return error;
+ }
+
+ StringExtractorGDBRemote response;
+ PacketResult packet_result =
+ SendPacketAndWaitForResponse(packet.GetString(), response);
+ if (packet_result != PacketResult::Success)
+ error.SetErrorString("Sending isconnect packet failed.");
return error;
}
@@ -1527,17 +1541,17 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
region_info.GetRange().IsValid()) {
saw_permissions = true;
if (region_info.GetRange().Contains(addr)) {
- if (value.find('r') != llvm::StringRef::npos)
+ if (value.contains('r'))
region_info.SetReadable(MemoryRegionInfo::eYes);
else
region_info.SetReadable(MemoryRegionInfo::eNo);
- if (value.find('w') != llvm::StringRef::npos)
+ if (value.contains('w'))
region_info.SetWritable(MemoryRegionInfo::eYes);
else
region_info.SetWritable(MemoryRegionInfo::eNo);
- if (value.find('x') != llvm::StringRef::npos)
+ if (value.contains('x'))
region_info.SetExecutable(MemoryRegionInfo::eYes);
else
region_info.SetExecutable(MemoryRegionInfo::eNo);
@@ -1572,6 +1586,19 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
}
}
}
+ } else if (name.equals("type")) {
+ std::string comma_sep_str = value.str();
+ size_t comma_pos;
+ while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) {
+ comma_sep_str[comma_pos] = '\0';
+ if (comma_sep_str == "stack") {
+ region_info.SetIsStackMemory(MemoryRegionInfo::eYes);
+ }
+ }
+ // handle final (or only) type of "stack"
+ if (comma_sep_str == "stack") {
+ region_info.SetIsStackMemory(MemoryRegionInfo::eYes);
+ }
} else if (name.equals("error")) {
StringExtractorGDBRemote error_extractor(value);
std::string error_string;
@@ -1580,21 +1607,12 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
error.SetErrorString(error_string.c_str());
} else if (name.equals("dirty-pages")) {
std::vector<addr_t> dirty_page_list;
- std::string comma_sep_str = value.str();
- size_t comma_pos;
- addr_t page;
- while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) {
- comma_sep_str[comma_pos] = '\0';
- page = StringConvert::ToUInt64(comma_sep_str.c_str(),
- LLDB_INVALID_ADDRESS, 16);
- if (page != LLDB_INVALID_ADDRESS)
+ for (llvm::StringRef x : llvm::split(value, ',')) {
+ addr_t page;
+ x.consume_front("0x");
+ if (llvm::to_integer(x, page, 16))
dirty_page_list.push_back(page);
- comma_sep_str.erase(0, comma_pos + 1);
}
- page = StringConvert::ToUInt64(comma_sep_str.c_str(),
- LLDB_INVALID_ADDRESS, 16);
- if (page != LLDB_INVALID_ADDRESS)
- dirty_page_list.push_back(page);
region_info.SetDirtyPageList(dirty_page_list);
}
}
@@ -1683,17 +1701,13 @@ Status GDBRemoteCommunicationClient::LoadQXferMemoryMap() {
return error;
}
- std::string xml;
- lldb_private::Status lldberr;
- if (!ReadExtFeature(ConstString("memory-map"), ConstString(""), xml,
- lldberr)) {
- error.SetErrorString("Failed to read memory map");
- return error;
- }
+ llvm::Expected<std::string> xml = ReadExtFeature("memory-map", "");
+ if (!xml)
+ return Status(xml.takeError());
XMLDocument xml_document;
- if (!xml_document.ParseMemory(xml.c_str(), xml.size())) {
+ if (!xml_document.ParseMemory(xml->c_str(), xml->size())) {
error.SetErrorString("Failed to parse memory map xml");
return error;
}
@@ -2358,24 +2372,6 @@ bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid,
return false;
}
-bool GDBRemoteCommunicationClient::SetNonStopMode(const bool enable) {
- // Form non-stop packet request
- char packet[32];
- const int packet_len =
- ::snprintf(packet, sizeof(packet), "QNonStop:%1d", (int)enable);
- assert(packet_len < (int)sizeof(packet));
- UNUSED_IF_ASSERT_DISABLED(packet_len);
-
- StringExtractorGDBRemote response;
- // Send to target
- if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success)
- if (response.IsOKResponse())
- return true;
-
- // Failed or not supported
- return false;
-}
-
static void MakeSpeedTestPacket(StreamString &packet, uint32_t send_size,
uint32_t recv_size) {
packet.Clear();
@@ -2827,8 +2823,12 @@ GDBRemoteCommunicationClient::GetCurrentProcessAndThreadIDs(
if (ch == 'm') {
do {
auto pid_tid = response.GetPidTid(LLDB_INVALID_PROCESS_ID);
+ // If we get an invalid response, break out of the loop.
+ // If there are valid tids, they have been added to ids.
+ // If there are no valid tids, we'll fall through to the
+ // bare-iron target handling below.
if (!pid_tid)
- return {};
+ break;
ids.push_back(pid_tid.getValue());
ch = response.GetChar(); // Skip the command separator
@@ -2959,7 +2959,7 @@ Status GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec,
if (response.GetChar() != 'F')
return Status("invalid response to '%s' packet", packet.str().c_str());
- return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+ return Status(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
}
Status
@@ -2980,7 +2980,18 @@ GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec,
if (response.GetChar() != 'F')
return Status("invalid response to '%s' packet", stream.GetData());
- return Status(response.GetU32(UINT32_MAX), eErrorTypePOSIX);
+ return Status(response.GetHexMaxU32(false, UINT32_MAX), eErrorTypePOSIX);
+}
+
+static int gdb_errno_to_system(int err) {
+ switch (err) {
+#define HANDLE_ERRNO(name, value) \
+ case GDB_##name: \
+ return name;
+#include "Plugins/Process/gdb-remote/GDBRemoteErrno.def"
+ default:
+ return -1;
+ }
}
static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response,
@@ -2988,12 +2999,12 @@ static uint64_t ParseHostIOPacketResponse(StringExtractorGDBRemote &response,
response.SetFilePos(0);
if (response.GetChar() != 'F')
return fail_result;
- int32_t result = response.GetS32(-2);
+ int32_t result = response.GetS32(-2, 16);
if (result == -2)
return fail_result;
if (response.GetChar() == ',') {
- int result_errno = response.GetS32(-2);
- if (result_errno != -2)
+ int result_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (result_errno != -1)
error.SetError(result_errno, eErrorTypePOSIX);
else
error.SetError(-1, eErrorTypeGeneric);
@@ -3026,7 +3037,7 @@ GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec,
bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd,
Status &error) {
lldb_private::StreamString stream;
- stream.Printf("vFile:close:%i", (int)fd);
+ stream.Printf("vFile:close:%x", (int)fd);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
@@ -3035,22 +3046,66 @@ bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd,
return false;
}
-// Extension of host I/O packets to get the file size.
-lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
- const lldb_private::FileSpec &file_spec) {
- std::string path(file_spec.GetPath(false));
+llvm::Optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::FStat(lldb::user_id_t fd) {
lldb_private::StreamString stream;
- stream.PutCString("vFile:size:");
- stream.PutStringAsRawHex8(path);
+ stream.Printf("vFile:fstat:%" PRIx64, fd);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
if (response.GetChar() != 'F')
+ return llvm::None;
+ int64_t size = response.GetS64(-1, 16);
+ if (size > 0 && response.GetChar() == ';') {
+ std::string buffer;
+ if (response.GetEscapedBinaryData(buffer)) {
+ GDBRemoteFStatData out;
+ if (buffer.size() != sizeof(out))
+ return llvm::None;
+ memcpy(&out, buffer.data(), sizeof(out));
+ return out;
+ }
+ }
+ }
+ return llvm::None;
+}
+
+llvm::Optional<GDBRemoteFStatData>
+GDBRemoteCommunicationClient::Stat(const lldb_private::FileSpec &file_spec) {
+ Status error;
+ lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
+ if (fd == UINT64_MAX)
+ return llvm::None;
+ llvm::Optional<GDBRemoteFStatData> st = FStat(fd);
+ CloseFile(fd, error);
+ return st;
+}
+
+// Extension of host I/O packets to get the file size.
+lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
+ const lldb_private::FileSpec &file_spec) {
+ if (m_supports_vFileSize) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:size:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success)
return UINT64_MAX;
- uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
- return retcode;
+
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F')
+ return UINT64_MAX;
+ uint32_t retcode = response.GetHexMaxU64(false, UINT64_MAX);
+ return retcode;
+ }
+ m_supports_vFileSize = false;
}
- return UINT64_MAX;
+
+ // Fallback to fstat.
+ llvm::Optional<GDBRemoteFStatData> st = Stat(file_spec);
+ return st ? st->gdb_st_size : UINT64_MAX;
}
void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
@@ -3081,37 +3136,50 @@ void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
Status
GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions) {
- std::string path{file_spec.GetPath(false)};
- Status error;
- lldb_private::StreamString stream;
- stream.PutCString("vFile:mode:");
- stream.PutStringAsRawHex8(path);
- StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
- PacketResult::Success) {
- if (response.GetChar() != 'F') {
- error.SetErrorStringWithFormat("invalid response to '%s' packet",
+ if (m_supports_vFileMode) {
+ std::string path{file_spec.GetPath(false)};
+ Status error;
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:mode:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success) {
+ error.SetErrorStringWithFormat("failed to send '%s' packet",
stream.GetData());
- } else {
- const uint32_t mode = response.GetS32(-1);
- if (static_cast<int32_t>(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.SetErrorToGenericError();
+ return error;
+ }
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F') {
+ error.SetErrorStringWithFormat("invalid response to '%s' packet",
+ stream.GetData());
} else {
- file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ const uint32_t mode = response.GetS32(-1, 16);
+ if (static_cast<int32_t>(mode) == -1) {
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ else
+ error.SetErrorToGenericError();
+ } else
+ error.SetErrorToGenericError();
+ } else {
+ file_permissions = mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ }
}
+ return error;
+ } else { // response.IsUnsupportedResponse()
+ m_supports_vFileMode = false;
}
- } else {
- error.SetErrorStringWithFormat("failed to send '%s' packet",
- stream.GetData());
}
- return error;
+
+ // Fallback to fstat.
+ if (llvm::Optional<GDBRemoteFStatData> st = Stat(file_spec)) {
+ file_permissions = st->gdb_st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ return Status();
+ }
+ return Status("fstat failed");
}
uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd,
@@ -3119,16 +3187,23 @@ uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd,
uint64_t dst_len,
Status &error) {
lldb_private::StreamString stream;
- stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len,
+ stream.Printf("vFile:pread:%x,%" PRIx64 ",%" PRIx64, (int)fd, dst_len,
offset);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
if (response.GetChar() != 'F')
return 0;
- uint32_t retcode = response.GetHexMaxU32(false, UINT32_MAX);
- if (retcode == UINT32_MAX)
- return retcode;
+ int64_t retcode = response.GetS64(-1, 16);
+ if (retcode == -1) {
+ error.SetErrorToGenericError();
+ if (response.GetChar() == ',') {
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
+ if (response_errno > 0)
+ error.SetError(response_errno, lldb::eErrorTypePOSIX);
+ }
+ return -1;
+ }
const char next = (response.Peek() ? *response.Peek() : 0);
if (next == ',')
return 0;
@@ -3153,7 +3228,7 @@ uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd,
uint64_t src_len,
Status &error) {
lldb_private::StreamGDBRemote stream;
- stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset);
+ stream.Printf("vFile:pwrite:%x,%" PRIx64 ",", (int)fd, offset);
stream.PutEscapedBytes(src, src_len);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
@@ -3162,15 +3237,15 @@ uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd,
error.SetErrorStringWithFormat("write file failed");
return 0;
}
- uint64_t bytes_written = response.GetU64(UINT64_MAX);
- if (bytes_written == UINT64_MAX) {
+ int64_t bytes_written = response.GetS64(-1, 16);
+ if (bytes_written == -1) {
error.SetErrorToGenericError();
if (response.GetChar() == ',') {
- int response_errno = response.GetS32(-1);
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
if (response_errno > 0)
error.SetError(response_errno, lldb::eErrorTypePOSIX);
}
- return 0;
+ return -1;
}
return bytes_written;
} else {
@@ -3194,11 +3269,11 @@ Status GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src,
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
if (response.GetChar() == 'F') {
- uint32_t result = response.GetU32(UINT32_MAX);
+ uint32_t result = response.GetHexMaxU32(false, UINT32_MAX);
if (result != 0) {
error.SetErrorToGenericError();
if (response.GetChar() == ',') {
- int response_errno = response.GetS32(-1);
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
if (response_errno > 0)
error.SetError(response_errno, lldb::eErrorTypePOSIX);
}
@@ -3225,11 +3300,11 @@ Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
PacketResult::Success) {
if (response.GetChar() == 'F') {
- uint32_t result = response.GetU32(UINT32_MAX);
+ uint32_t result = response.GetHexMaxU32(false, UINT32_MAX);
if (result != 0) {
error.SetErrorToGenericError();
if (response.GetChar() == ',') {
- int response_errno = response.GetS32(-1);
+ int response_errno = gdb_errno_to_system(response.GetS32(-1, 16));
if (response_errno > 0)
error.SetError(response_errno, lldb::eErrorTypePOSIX);
}
@@ -3247,21 +3322,33 @@ Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) {
// Extension of host I/O packets to get whether a file exists.
bool GDBRemoteCommunicationClient::GetFileExists(
const lldb_private::FileSpec &file_spec) {
- std::string path(file_spec.GetPath(false));
- lldb_private::StreamString stream;
- stream.PutCString("vFile:exists:");
- stream.PutStringAsRawHex8(path);
- StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(stream.GetString(), response) ==
- PacketResult::Success) {
- if (response.GetChar() != 'F')
- return false;
- if (response.GetChar() != ',')
+ if (m_supports_vFileExists) {
+ std::string path(file_spec.GetPath(false));
+ lldb_private::StreamString stream;
+ stream.PutCString("vFile:exists:");
+ stream.PutStringAsRawHex8(path);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response) !=
+ PacketResult::Success)
return false;
- bool retcode = (response.GetChar() != '0');
- return retcode;
+ if (!response.IsUnsupportedResponse()) {
+ if (response.GetChar() != 'F')
+ return false;
+ if (response.GetChar() != ',')
+ return false;
+ bool retcode = (response.GetChar() != '0');
+ return retcode;
+ } else
+ m_supports_vFileExists = false;
}
- return false;
+
+ // Fallback to open.
+ Status error;
+ lldb::user_id_t fd = OpenFile(file_spec, File::eOpenOptionReadOnly, 0, error);
+ if (fd == UINT64_MAX)
+ return false;
+ CloseFile(fd, error);
+ return true;
}
bool GDBRemoteCommunicationClient::CalculateMD5(
@@ -3790,15 +3877,14 @@ GDBRemoteCommunicationClient::GetModulesInfo(
// query the target remote for extended information using the qXfer packet
//
-// example: object='features', annex='target.xml', out=<xml output> return:
-// 'true' on success
-// 'false' on failure (err set)
-bool GDBRemoteCommunicationClient::ReadExtFeature(
- const lldb_private::ConstString object,
- const lldb_private::ConstString annex, std::string &out,
- lldb_private::Status &err) {
-
- std::stringstream output;
+// example: object='features', annex='target.xml'
+// return: <xml output> or error
+llvm::Expected<std::string>
+GDBRemoteCommunicationClient::ReadExtFeature(llvm::StringRef object,
+ llvm::StringRef annex) {
+
+ std::string output;
+ llvm::raw_string_ostream output_stream(output);
StringExtractorGDBRemote chunk;
uint64_t size = GetRemoteMaxPacketSize();
@@ -3812,28 +3898,22 @@ bool GDBRemoteCommunicationClient::ReadExtFeature(
while (active) {
// send query extended feature packet
- std::stringstream packet;
- packet << "qXfer:" << object.AsCString("")
- << ":read:" << annex.AsCString("") << ":" << std::hex << offset
- << "," << std::hex << size;
+ std::string packet =
+ ("qXfer:" + object + ":read:" + annex + ":" +
+ llvm::Twine::utohexstr(offset) + "," + llvm::Twine::utohexstr(size))
+ .str();
GDBRemoteCommunication::PacketResult res =
- SendPacketAndWaitForResponse(packet.str(), chunk);
+ SendPacketAndWaitForResponse(packet, chunk);
- if (res != GDBRemoteCommunication::PacketResult::Success) {
- err.SetErrorString("Error sending $qXfer packet");
- return false;
- }
-
- const std::string &str = std::string(chunk.GetStringRef());
- if (str.length() == 0) {
- // should have some data in chunk
- err.SetErrorString("Empty response from $qXfer packet");
- return false;
+ if (res != GDBRemoteCommunication::PacketResult::Success ||
+ chunk.GetStringRef().empty()) {
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "Error sending $qXfer packet");
}
// check packet code
- switch (str[0]) {
+ switch (chunk.GetStringRef()[0]) {
// last chunk
case ('l'):
active = false;
@@ -3841,21 +3921,19 @@ bool GDBRemoteCommunicationClient::ReadExtFeature(
// more chunks
case ('m'):
- if (str.length() > 1)
- output << &str[1];
- offset += str.length() - 1;
+ output_stream << chunk.GetStringRef().drop_front();
+ offset += chunk.GetStringRef().size() - 1;
break;
// unknown chunk
default:
- err.SetErrorString("Invalid continuation code from $qXfer packet");
- return false;
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Invalid continuation code from $qXfer packet");
}
}
- out = output.str();
- err.Success();
- return true;
+ return output_stream.str();
}
// Notify the target that gdb is prepared to serve symbol lookup requests.
@@ -4146,3 +4224,14 @@ void GDBRemoteCommunicationClient::OnRunPacketSent(bool first) {
GDBRemoteClientBase::OnRunPacketSent(first);
m_curr_tid = LLDB_INVALID_THREAD_ID;
}
+
+bool GDBRemoteCommunicationClient::UsesNativeSignals() {
+ if (m_uses_native_signals == eLazyBoolCalculate)
+ GetRemoteQSupported();
+ if (m_uses_native_signals == eLazyBoolYes)
+ return true;
+
+ // If the remote didn't indicate native-signal support explicitly,
+ // check whether it is an old version of lldb-server.
+ return GetThreadSuffixSupported();
+}