aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/gdb-remote
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp10
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp86
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h8
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp15
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h13
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp386
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h21
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp184
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h71
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp109
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h13
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp108
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h15
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp12
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h4
16 files changed, 789 insertions, 268 deletions
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index bfacd41dc1a3..4981345d6a18 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -50,7 +50,7 @@
#include <compression.h>
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
#include <zlib.h>
#endif
@@ -284,7 +284,7 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet,
LLDB_LOGV(log,
"Read(buffer, sizeof(buffer), timeout = {0}, "
"status = {1}, error = {2}) => bytes_read = {3}",
- timeout, Communication::ConnectionStatusAsCString(status), error,
+ timeout, Communication::ConnectionStatusAsString(status), error,
bytes_read);
if (bytes_read > 0) {
@@ -582,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() {
}
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX &&
decompressed_buffer != nullptr &&
m_compression_type == CompressionType::ZlibDeflate) {
@@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
const int backlog = 5;
TCPSocket listen_socket(true, child_processes_inherit);
if (llvm::Error error =
- listen_socket.Listen("127.0.0.1:0", backlog).ToError())
+ listen_socket.Listen("localhost:0", backlog).ToError())
return error;
Socket *accept_socket;
@@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client,
llvm::SmallString<32> remote_addr;
llvm::raw_svector_ostream(remote_addr)
- << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber();
+ << "connect://localhost:" << listen_socket.GetLocalPortNumber();
std::unique_ptr<ConnectionFileDescriptor> conn_up(
new ConnectionFileDescriptor());
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index c75d5e106cd0..d375a312ae2c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1053,7 +1053,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression(
}
#endif
-#if defined(HAVE_LIBZ)
+#if LLVM_ENABLE_ZLIB
if (avail_type == CompressionType::None) {
for (auto compression : supported_compressions) {
if (compression == "zlib-deflate") {
@@ -1529,6 +1529,22 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
std::string name;
name_extractor.GetHexByteString(name);
region_info.SetName(name.c_str());
+ } else if (name.equals("flags")) {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+
+ llvm::StringRef flags = value;
+ llvm::StringRef flag;
+ while (flags.size()) {
+ flags = flags.ltrim();
+ std::tie(flag, flags) = flags.split(' ');
+ // To account for trailing whitespace
+ if (flag.size()) {
+ if (flag == "mt") {
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
+ break;
+ }
+ }
+ }
} else if (name.equals("error")) {
StringExtractorGDBRemote error_extractor(value);
std::string error_string;
@@ -1701,14 +1717,9 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) {
// Set num to 0 first.
num = 0;
if (m_supports_watchpoint_support_info != eLazyBoolNo) {
- char packet[64];
- const int packet_len =
- ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:");
- assert(packet_len < (int)sizeof(packet));
- UNUSED_IF_ASSERT_DISABLED(packet_len);
StringExtractorGDBRemote response;
- if (SendPacketAndWaitForResponse(packet, response, false) ==
- PacketResult::Success) {
+ if (SendPacketAndWaitForResponse("qWatchpointSupportInfo:", response,
+ false) == PacketResult::Success) {
m_supports_watchpoint_support_info = eLazyBoolYes;
llvm::StringRef name;
llvm::StringRef value;
@@ -2120,6 +2131,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
case llvm::Triple::COFF:
m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub);
break;
+ case llvm::Triple::GOFF:
case llvm::Triple::Wasm:
case llvm::Triple::XCOFF:
LLDB_LOGF(log, "error: not supported target architecture");
@@ -2816,7 +2828,7 @@ lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() {
}
lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
- const char *command, // Shouldn't be NULL
+ llvm::StringRef command,
const FileSpec &
working_dir, // Pass empty FileSpec to use the current working directory
int *status_ptr, // Pass NULL if you don't want the process exit status
@@ -2827,7 +2839,7 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand(
const Timeout<std::micro> &timeout) {
lldb_private::StreamString stream;
stream.PutCString("qPlatform_shell:");
- stream.PutBytesAsRawHex8(command, strlen(command));
+ stream.PutBytesAsRawHex8(command.data(), command.size());
stream.PutChar(',');
uint32_t timeout_sec = UINT32_MAX;
if (timeout) {
@@ -2981,6 +2993,31 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize(
return UINT64_MAX;
}
+void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory(
+ CompletionRequest &request, bool only_dir) {
+ lldb_private::StreamString stream;
+ stream.PutCString("qPathComplete:");
+ stream.PutHex32(only_dir ? 1 : 0);
+ stream.PutChar(',');
+ stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix());
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(stream.GetString(), response, false) ==
+ PacketResult::Success) {
+ StreamString strm;
+ char ch = response.GetChar();
+ if (ch != 'M')
+ return;
+ while (response.Peek()) {
+ strm.Clear();
+ while ((ch = response.GetHexU8(0, false)) != '\0')
+ strm.PutChar(ch);
+ request.AddCompletion(strm.GetString());
+ if (response.GetChar() != ',')
+ break;
+ }
+ }
+}
+
Status
GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions) {
@@ -3433,6 +3470,35 @@ Status GDBRemoteCommunicationClient::SendGetMetaDataPacket(
return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset);
}
+llvm::Expected<TraceTypeInfo>
+GDBRemoteCommunicationClient::SendGetSupportedTraceType() {
+ Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ StreamGDBRemote escaped_packet;
+ escaped_packet.PutCString("jLLDBTraceSupportedType");
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response,
+ true) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsErrorResponse())
+ return response.GetStatus().ToError();
+ if (response.IsUnsupportedResponse())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "jLLDBTraceSupportedType is unsupported");
+
+ if (llvm::Expected<TraceTypeInfo> type =
+ llvm::json::parse<TraceTypeInfo>(response.Peek()))
+ return *type;
+ else
+ return type.takeError();
+ }
+ LLDB_LOG(log, "failed to send packet: jLLDBTraceSupportedType");
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "failed to send packet: jLLDBTraceSupportedType");
+}
+
Status
GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid,
TraceOptions &options) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 8df08cbde735..af3755fce774 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -22,6 +22,7 @@
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/ProcessInfo.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TraceOptions.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
#endif
@@ -375,6 +376,9 @@ public:
lldb::user_id_t GetFileSize(const FileSpec &file_spec);
+ void AutoCompleteDiskFileOrDirectory(CompletionRequest &request,
+ bool only_dir);
+
Status GetFilePermissions(const FileSpec &file_spec,
uint32_t &file_permissions);
@@ -396,7 +400,7 @@ public:
bool GetFileExists(const FileSpec &file_spec);
Status RunShellCommand(
- const char *command, // Shouldn't be nullptr
+ llvm::StringRef command,
const FileSpec &working_dir, // Pass empty FileSpec to use the current
// working directory
int *status_ptr, // Pass nullptr if you don't want the process exit status
@@ -516,6 +520,8 @@ public:
Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options);
+ llvm::Expected<TraceTypeInfo> SendGetSupportedTraceType();
+
protected:
LazyBool m_supports_not_sending_acks;
LazyBool m_supports_thread_suffix;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
index b78f0916b9b9..60548efc0f33 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -12,11 +12,11 @@
#include "GDBRemoteCommunicationServer.h"
-#include <cstring>
-
#include "ProcessGDBRemoteLog.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
+#include "lldb/Utility/UnimplementedError.h"
+#include <cstring>
using namespace lldb;
using namespace lldb_private;
@@ -113,18 +113,17 @@ GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) {
GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) {
+ assert(error);
std::unique_ptr<llvm::ErrorInfoBase> EIB;
- std::unique_ptr<PacketUnimplementedError> PUE;
+ std::unique_ptr<UnimplementedError> UE;
llvm::handleAllErrors(
std::move(error),
- [&](std::unique_ptr<PacketUnimplementedError> E) { PUE = std::move(E); },
+ [&](std::unique_ptr<UnimplementedError> E) { UE = std::move(E); },
[&](std::unique_ptr<llvm::ErrorInfoBase> E) { EIB = std::move(E); });
if (EIB)
return SendErrorResponse(Status(llvm::Error(std::move(EIB))));
- if (PUE)
- return SendUnimplementedResponse(PUE->message().c_str());
- return SendErrorResponse(Status("Unknown Error"));
+ return SendUnimplementedResponse("");
}
GDBRemoteCommunication::PacketResult
@@ -152,5 +151,3 @@ GDBRemoteCommunicationServer::SendOKResponse() {
bool GDBRemoteCommunicationServer::HandshakeWithClient() {
return GetAck() == PacketResult::Success;
}
-
-char PacketUnimplementedError::ID;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
index a7c2ea47e3ba..a1cf70f9cd1a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -27,7 +27,6 @@ class ProcessGDBRemote;
class GDBRemoteCommunicationServer : public GDBRemoteCommunication {
public:
- using PortMap = std::map<uint16_t, lldb::pid_t>;
using PacketHandler =
std::function<PacketResult(StringExtractorGDBRemote &packet,
Status &error, bool &interrupt, bool &quit)>;
@@ -79,18 +78,6 @@ private:
operator=(const GDBRemoteCommunicationServer &) = delete;
};
-class PacketUnimplementedError
- : public llvm::ErrorInfo<PacketUnimplementedError, llvm::StringError> {
-public:
- static char ID;
- using llvm::ErrorInfo<PacketUnimplementedError,
- llvm::StringError>::ErrorInfo; // inherit constructors
- PacketUnimplementedError(const llvm::Twine &S)
- : ErrorInfo(S, llvm::errc::not_supported) {}
-
- PacketUnimplementedError() : ErrorInfo(llvm::errc::not_supported) {}
-};
-
} // namespace process_gdb_remote
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 08d489851799..1ca0290eda13 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -843,7 +843,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSupported(
response.PutCString(";QListThreadsInStopReply+");
response.PutCString(";qEcho+");
response.PutCString(";qXfer:features:read+");
-#if defined(__linux__) || defined(__NetBSD__)
+#if defined(__linux__) || defined(__NetBSD__) || defined(__FreeBSD__)
response.PutCString(";QPassSignals+");
response.PutCString(";qXfer:auxv:read+");
response.PutCString(";qXfer:libraries-svr4:read+");
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index ae2f4bd041c9..62a09a2a432c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -10,13 +10,12 @@
#include "lldb/Host/Config.h"
-#include "GDBRemoteCommunicationServerLLGS.h"
-#include "lldb/Utility/GDBRemote.h"
#include <chrono>
#include <cstring>
#include <thread>
+#include "GDBRemoteCommunicationServerLLGS.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Debug.h"
#include "lldb/Host/File.h"
@@ -32,11 +31,13 @@
#include "lldb/Utility/Args.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UnimplementedError.h"
#include "lldb/Utility/UriParser.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/JSON.h"
@@ -92,6 +93,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_memory_read);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M,
&GDBRemoteCommunicationServerLLGS::Handle_M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M,
+ &GDBRemoteCommunicationServerLLGS::Handle__M);
+ RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m,
+ &GDBRemoteCommunicationServerLLGS::Handle__m);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p,
&GDBRemoteCommunicationServerLLGS::Handle_p);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P,
@@ -155,6 +160,15 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
StringExtractorGDBRemote::eServerPacketType_vAttach,
&GDBRemoteCommunicationServerLLGS::Handle_vAttach);
RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported,
+ &GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_vAttachOrWait,
+ &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait);
+ RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_vCont,
&GDBRemoteCommunicationServerLLGS::Handle_vCont);
RegisterMemberFunctionHandler(
@@ -186,6 +200,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,
&GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead);
+ RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupportedType,
+ &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g,
&GDBRemoteCommunicationServerLLGS::Handle_g);
@@ -326,6 +343,75 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) {
return Status();
}
+Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess(
+ llvm::StringRef process_name, bool include_existing) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1);
+
+ // Create the matcher used to search the process list.
+ ProcessInstanceInfoList exclusion_list;
+ ProcessInstanceInfoMatch match_info;
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(
+ process_name, llvm::sys::path::Style::native);
+ match_info.SetNameMatchType(NameMatch::Equals);
+
+ if (include_existing) {
+ LLDB_LOG(log, "including existing processes in search");
+ } else {
+ // Create the excluded process list before polling begins.
+ Host::FindProcesses(match_info, exclusion_list);
+ LLDB_LOG(log, "placed '{0}' processes in the exclusion list.",
+ exclusion_list.size());
+ }
+
+ LLDB_LOG(log, "waiting for '{0}' to appear", process_name);
+
+ auto is_in_exclusion_list =
+ [&exclusion_list](const ProcessInstanceInfo &info) {
+ for (auto &excluded : exclusion_list) {
+ if (excluded.GetProcessID() == info.GetProcessID())
+ return true;
+ }
+ return false;
+ };
+
+ ProcessInstanceInfoList loop_process_list;
+ while (true) {
+ loop_process_list.clear();
+ if (Host::FindProcesses(match_info, loop_process_list)) {
+ // Remove all the elements that are in the exclusion list.
+ llvm::erase_if(loop_process_list, is_in_exclusion_list);
+
+ // One match! We found the desired process.
+ if (loop_process_list.size() == 1) {
+ auto matching_process_pid = loop_process_list[0].GetProcessID();
+ LLDB_LOG(log, "found pid {0}", matching_process_pid);
+ return AttachToProcess(matching_process_pid);
+ }
+
+ // Multiple matches! Return an error reporting the PIDs we found.
+ if (loop_process_list.size() > 1) {
+ StreamString error_stream;
+ error_stream.Format(
+ "Multiple executables with name: '{0}' found. Pids: ",
+ process_name);
+ for (size_t i = 0; i < loop_process_list.size() - 1; ++i) {
+ error_stream.Format("{0}, ", loop_process_list[i].GetProcessID());
+ }
+ error_stream.Format("{0}.", loop_process_list.back().GetProcessID());
+
+ Status error;
+ error.SetErrorString(error_stream.GetString());
+ return error;
+ }
+ }
+ // No matches, we have not found the process. Sleep until next poll.
+ LLDB_LOG(log, "sleep {0} seconds", polling_interval);
+ std::this_thread::sleep_for(polling_interval);
+ }
+}
+
void GDBRemoteCommunicationServerLLGS::InitializeDelegate(
NativeProcessProtocol *process) {
assert(process && "process cannot be NULL");
@@ -495,7 +581,7 @@ static void WriteRegisterValueInHexFixedWidth(
}
}
-static llvm::Expected<json::Object>
+static llvm::Optional<json::Object>
GetRegistersAsJSON(NativeThreadProtocol &thread) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD));
@@ -504,30 +590,16 @@ GetRegistersAsJSON(NativeThreadProtocol &thread) {
json::Object register_object;
#ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET
- // Expedite all registers in the first register set (i.e. should be GPRs)
- // that are not contained in other registers.
- const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0);
- if (!reg_set_p)
- return llvm::make_error<llvm::StringError>("failed to get registers",
- llvm::inconvertibleErrorCode());
- for (const uint32_t *reg_num_p = reg_set_p->registers;
- *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
- uint32_t reg_num = *reg_num_p;
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
#else
- // Expedite only a couple of registers until we figure out why sending
- // registers is expensive.
- static const uint32_t k_expedited_registers[] = {
- LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP,
- LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM};
-
- for (const uint32_t *generic_reg_p = k_expedited_registers;
- *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) {
- uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber(
- eRegisterKindGeneric, *generic_reg_p);
- if (reg_num == LLDB_INVALID_REGNUM)
- continue; // Target does not support the given register.
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal);
#endif
+ if (expedited_regs.empty())
+ return llvm::None;
+ for (auto &reg_num : expedited_regs) {
const RegisterInfo *const reg_info_p =
reg_ctx.GetRegisterInfoAtIndex(reg_num);
if (reg_info_p == nullptr) {
@@ -620,12 +692,8 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) {
json::Object thread_obj;
if (!abridged) {
- if (llvm::Expected<json::Object> registers =
- GetRegistersAsJSON(*thread)) {
+ if (llvm::Optional<json::Object> registers = GetRegistersAsJSON(*thread))
thread_obj.try_emplace("registers", std::move(*registers));
- } else {
- return registers.takeError();
- }
}
thread_obj.try_emplace("tid", static_cast<int64_t>(tid));
@@ -806,46 +874,27 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(
// Grab the register context.
NativeRegisterContext& reg_ctx = thread->GetRegisterContext();
- // Expedite all registers in the first register set (i.e. should be GPRs)
- // that are not contained in other registers.
- const RegisterSet *reg_set_p;
- if (reg_ctx.GetRegisterSetCount() > 0 &&
- ((reg_set_p = reg_ctx.GetRegisterSet(0)) != nullptr)) {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s expediting registers "
- "from set '%s' (registers set count: %zu)",
- __FUNCTION__, reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
- reg_set_p->num_registers);
+ const auto expedited_regs =
+ reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full);
- for (const uint32_t *reg_num_p = reg_set_p->registers;
- *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) {
- const RegisterInfo *const reg_info_p =
- reg_ctx.GetRegisterInfoAtIndex(*reg_num_p);
- if (reg_info_p == nullptr) {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s failed to get "
- "register info for register set '%s', register index "
- "%" PRIu32,
+ for (auto &reg_num : expedited_regs) {
+ const RegisterInfo *const reg_info_p =
+ reg_ctx.GetRegisterInfoAtIndex(reg_num);
+ // Only expediate registers that are not contained in other registers.
+ if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) {
+ RegisterValue reg_value;
+ Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
+ if (error.Success()) {
+ response.Printf("%.02x:", reg_num);
+ WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
+ &reg_value, lldb::eByteOrderBig);
+ response.PutChar(';');
+ } else {
+ LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read "
+ "register '%s' index %" PRIu32 ": %s",
__FUNCTION__,
- reg_set_p->name ? reg_set_p->name : "<unnamed-set>",
- *reg_num_p);
- } else if (reg_info_p->value_regs == nullptr) {
- // Only expediate registers that are not contained in other registers.
- RegisterValue reg_value;
- Status error = reg_ctx.ReadRegister(reg_info_p, reg_value);
- if (error.Success()) {
- response.Printf("%.02x:", *reg_num_p);
- WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p,
- &reg_value, lldb::eByteOrderBig);
- response.PutChar(';');
- } else {
- LLDB_LOGF(log,
- "GDBRemoteCommunicationServerLLGS::%s failed to read "
- "register '%s' index %" PRIu32 ": %s",
- __FUNCTION__,
- reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
- *reg_num_p, error.AsCString());
- }
+ reg_info_p->name ? reg_info_p->name : "<unnamed-register>",
+ reg_num, error.AsCString());
}
}
}
@@ -1222,6 +1271,33 @@ GDBRemoteCommunicationServerLLGS::Handle_jTraceStop(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupportedType(
+ StringExtractorGDBRemote &packet) {
+
+ // Fail if we don't have a current process.
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID))
+ return SendErrorResponse(Status("Process not running."));
+
+ llvm::Expected<TraceTypeInfo> supported_trace_type =
+ m_debugged_process_up->GetSupportedTraceType();
+ if (!supported_trace_type)
+ return SendErrorResponse(supported_trace_type.takeError());
+
+ StreamGDBRemote escaped_response;
+ StructuredData::Dictionary json_packet;
+
+ json_packet.AddStringItem("name", supported_trace_type->name);
+ json_packet.AddStringItem("description", supported_trace_type->description);
+
+ StreamString json_string;
+ json_packet.Dump(json_string, false);
+ escaped_response.PutEscapedBytes(json_string.GetData(),
+ json_string.GetSize());
+ return SendPacketNoLock(escaped_response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead(
StringExtractorGDBRemote &packet) {
@@ -1723,6 +1799,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState(
case eStateSuspended:
case eStateStopped:
case eStateCrashed: {
+ assert(m_debugged_process_up != nullptr);
lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID();
// Make sure we set the current thread so g and p packets return the data
// the gdb will expect.
@@ -1789,8 +1866,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo(
response.PutChar(';');
}
- response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";",
- reg_info->byte_size * 8, reg_info->byte_offset);
+ response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset);
llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info);
if (!encoding.empty())
@@ -2085,7 +2164,7 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) {
StreamGDBRemote response;
RegisterValue reg_value(
- reg_bytes, reg_size,
+ makeArrayRef(reg_bytes, reg_size),
m_debugged_process_up->GetArchitecture().GetByteOrder());
Status error = reg_context.WriteRegister(reg_info, reg_value);
if (error.Fail()) {
@@ -2321,6 +2400,84 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_M"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short _M packet");
+
+ const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (size == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+ if (packet.GetChar() != ',')
+ return SendIllFormedResponse(packet, "Bad packet");
+ Permissions perms = {};
+ while (packet.GetBytesLeft() > 0) {
+ switch (packet.GetChar()) {
+ case 'r':
+ perms |= ePermissionsReadable;
+ break;
+ case 'w':
+ perms |= ePermissionsWritable;
+ break;
+ case 'x':
+ perms |= ePermissionsExecutable;
+ break;
+ default:
+ return SendIllFormedResponse(packet, "Bad permissions");
+ }
+ }
+
+ llvm::Expected<addr_t> addr =
+ m_debugged_process_up->AllocateMemory(size, perms);
+ if (!addr)
+ return SendErrorResponse(addr.takeError());
+
+ StreamGDBRemote response;
+ response.PutHex64(*addr);
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (!m_debugged_process_up ||
+ (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) {
+ LLDB_LOGF(
+ log,
+ "GDBRemoteCommunicationServerLLGS::%s failed, no process available",
+ __FUNCTION__);
+ return SendErrorResponse(0x15);
+ }
+
+ // Parse out the memory address.
+ packet.SetFilePos(strlen("_m"));
+ if (packet.GetBytesLeft() < 1)
+ return SendIllFormedResponse(packet, "Too short m packet");
+
+ const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ return SendIllFormedResponse(packet, "Address not valid");
+
+ if (llvm::Error Err = m_debugged_process_up->DeallocateMemory(addr))
+ return SendErrorResponse(std::move(Err));
+
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
@@ -2491,6 +2648,17 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
response.PutChar(';');
}
+ // Flags
+ MemoryRegionInfo::OptionalBool memory_tagged =
+ region_info.GetMemoryTagged();
+ if (memory_tagged != MemoryRegionInfo::eDontKnow) {
+ response.PutCString("flags:");
+ if (memory_tagged == MemoryRegionInfo::eYes) {
+ response.PutCString("mt");
+ }
+ response.PutChar(';');
+ }
+
// Name
ConstString name = region_info.GetName();
if (name) {
@@ -2773,10 +2941,11 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
continue;
}
- response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" offset=\"%" PRIu32
- "\" regnum=\"%d\" ",
- reg_info->name, reg_info->byte_size * 8,
- reg_info->byte_offset, reg_index);
+ response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ",
+ reg_info->name, reg_info->byte_size * 8, reg_index);
+
+ if (!reg_context.RegisterOffsetIsDynamic())
+ response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset);
if (reg_info->alt_name && reg_info->alt_name[0])
response.Printf("altname=\"%s\" ", reg_info->alt_name);
@@ -2876,8 +3045,7 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object,
if (object == "features" && annex == "target.xml")
return BuildTargetXml();
- return llvm::make_error<PacketUnimplementedError>(
- "Xfer object not supported");
+ return llvm::make_error<UnimplementedError>();
}
GDBRemoteCommunication::PacketResult
@@ -3099,6 +3267,72 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, false);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported(
+ StringExtractorGDBRemote &packet) {
+ return SendOKResponse();
+}
+
+GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait(
+ StringExtractorGDBRemote &packet) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Consume the ';' after the identifier.
+ packet.SetFilePos(strlen("vAttachOrWait"));
+
+ if (!packet.GetBytesLeft() || packet.GetChar() != ';')
+ return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'");
+
+ // Allocate the buffer for the process name from vAttachWait.
+ std::string process_name;
+ if (!packet.GetHexByteString(process_name))
+ return SendIllFormedResponse(packet,
+ "vAttachOrWait failed to parse process name");
+
+ LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name);
+
+ Status error = AttachWaitProcess(process_name, true);
+ if (error.Fail()) {
+ LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name,
+ error);
+ return SendErrorResponse(error);
+ }
+
+ // Notify we attached by sending a stop packet.
+ return SendStopReasonForState(m_debugged_process_up->GetState());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
index 3ce285910c25..c51139924559 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h
@@ -59,6 +59,17 @@ public:
/// attach operation.
Status AttachToProcess(lldb::pid_t pid);
+ /// Wait to attach to a process with a given name.
+ ///
+ /// This method supports waiting for the next instance of a process
+ /// with a given name and attaching llgs to that via the configured
+ /// Platform.
+ ///
+ /// \return
+ /// An Status object indicating the success or failure of the
+ /// attach operation.
+ Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing);
+
// NativeProcessProtocol::NativeDelegate overrides
void InitializeDelegate(NativeProcessProtocol *process) override;
@@ -138,6 +149,8 @@ protected:
PacketResult Handle_memory_read(StringExtractorGDBRemote &packet);
PacketResult Handle_M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__M(StringExtractorGDBRemote &packet);
+ PacketResult Handle__m(StringExtractorGDBRemote &packet);
PacketResult
Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet);
@@ -162,10 +175,18 @@ protected:
PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet);
+ PacketResult Handle_jLLDBTraceSupportedType(StringExtractorGDBRemote &packet);
+
PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet);
PacketResult Handle_vAttach(StringExtractorGDBRemote &packet);
+ PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet);
+
+ PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet);
+
PacketResult Handle_D(StringExtractorGDBRemote &packet);
PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
index d14b79a03d17..3462fb7ec8b9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp
@@ -26,12 +26,14 @@
#include "lldb/Host/FileAction.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
+#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/GDBRemote.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/StructuredData.h"
+#include "lldb/Utility/TildeExpressionResolver.h"
#include "lldb/Utility/UriParser.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
@@ -40,6 +42,69 @@ using namespace lldb;
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
+GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port,
+ uint16_t max_port) {
+ for (; min_port < max_port; ++min_port)
+ m_port_map[min_port] = LLDB_INVALID_PROCESS_ID;
+}
+
+void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) {
+ // Do not modify existing mappings
+ m_port_map.insert({port, LLDB_INVALID_PROCESS_ID});
+}
+
+llvm::Expected<uint16_t>
+GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() {
+ if (m_port_map.empty())
+ return 0; // Bind to port zero and get a port, we didn't have any
+ // limitations
+
+ for (auto &pair : m_port_map) {
+ if (pair.second == LLDB_INVALID_PROCESS_ID) {
+ pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
+ return pair.first;
+ }
+ }
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No free port found in port map");
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess(
+ uint16_t port, lldb::pid_t pid) {
+ auto pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = pid;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) {
+ std::map<uint16_t, lldb::pid_t>::iterator pos = m_port_map.find(port);
+ if (pos != m_port_map.end()) {
+ pos->second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess(
+ lldb::pid_t pid) {
+ if (!m_port_map.empty()) {
+ for (auto &pair : m_port_map) {
+ if (pair.second == pid) {
+ pair.second = LLDB_INVALID_PROCESS_ID;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const {
+ return m_port_map.empty();
+}
+
// GDBRemoteCommunicationServerPlatform constructor
GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
const Socket::SocketProtocol socket_protocol, const char *socket_scheme)
@@ -69,6 +134,9 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform(
StringExtractorGDBRemote::eServerPacketType_qProcessInfo,
&GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo);
RegisterMemberFunctionHandler(
+ StringExtractorGDBRemote::eServerPacketType_qPathComplete,
+ &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete);
+ RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir,
&GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir);
RegisterMemberFunctionHandler(
@@ -89,9 +157,14 @@ GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {}
Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid,
- uint16_t &port, std::string &socket_name) {
- if (port == UINT16_MAX)
- port = GetNextAvailablePort();
+ llvm::Optional<uint16_t> &port, std::string &socket_name) {
+ if (!port) {
+ llvm::Expected<uint16_t> available_port = m_port_map.GetNextAvailablePort();
+ if (available_port)
+ port = *available_port;
+ else
+ return Status(available_port.takeError());
+ }
// Spawn a new thread to accept the port that gets bound after binding to
// port 0 (zero).
@@ -106,7 +179,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM));
LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(),
- port);
+ *port);
// Do not run in a new session so that it can not linger after the platform
// closes.
@@ -121,7 +194,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
#if !defined(__APPLE__)
url << m_socket_scheme << "://";
#endif
- uint16_t *port_ptr = &port;
+ uint16_t *port_ptr = port.getPointer();
if (m_socket_protocol == Socket::ProtocolTcp) {
llvm::StringRef platform_scheme;
llvm::StringRef platform_ip;
@@ -132,7 +205,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
platform_port, platform_path);
UNUSED_IF_ASSERT_DISABLED(ok);
assert(ok);
- url << platform_ip.str() << ":" << port;
+ url << '[' << platform_ip.str() << "]:" << *port;
} else {
socket_name = GetDomainSocketPath("gdbserver").GetPath();
url << socket_name;
@@ -146,11 +219,11 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer(
if (pid != LLDB_INVALID_PROCESS_ID) {
std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
m_spawned_pids.insert(pid);
- if (port > 0)
- AssociatePortWithProcess(port, pid);
+ if (*port > 0)
+ m_port_map.AssociatePortWithProcess(*port, pid);
} else {
- if (port > 0)
- FreePort(port);
+ if (*port > 0)
+ m_port_map.FreePort(*port);
}
return error;
}
@@ -170,12 +243,15 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
packet.SetFilePos(::strlen("qLaunchGDBServer;"));
llvm::StringRef name;
llvm::StringRef value;
- uint16_t port = UINT16_MAX;
+ llvm::Optional<uint16_t> port;
while (packet.GetNameColonValue(name, value)) {
if (name.equals("host"))
hostname = std::string(value);
- else if (name.equals("port"))
- value.getAsInteger(0, port);
+ else if (name.equals("port")) {
+ // Make the Optional valid so we can use its value
+ port = 0;
+ value.getAsInteger(0, port.getValue());
+ }
}
lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID;
@@ -196,8 +272,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer(
__FUNCTION__, debugserver_pid);
StreamGDBRemote response;
+ assert(port);
response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid,
- port + m_port_offset);
+ *port + m_port_offset);
if (!socket_name.empty()) {
response.PutCString("socket_name:");
response.PutStringAsRawHex8(socket_name);
@@ -334,6 +411,38 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo(
}
GDBRemoteCommunication::PacketResult
+GDBRemoteCommunicationServerPlatform::Handle_qPathComplete(
+ StringExtractorGDBRemote &packet) {
+ packet.SetFilePos(::strlen("qPathComplete:"));
+ const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1);
+ if (packet.GetChar() != ',')
+ return SendErrorResponse(85);
+ std::string path;
+ packet.GetHexByteString(path);
+
+ StringList matches;
+ StandardTildeExpressionResolver resolver;
+ if (only_dir)
+ CommandCompletions::DiskDirectories(path, matches, resolver);
+ else
+ CommandCompletions::DiskFiles(path, matches, resolver);
+
+ StreamString response;
+ response.PutChar('M');
+ llvm::StringRef separator;
+ std::sort(matches.begin(), matches.end());
+ for (const auto &match : matches) {
+ response << separator;
+ separator = ",";
+ // encode result strings into hex bytes to avoid unexpected error caused by
+ // special characters like '$'.
+ response.PutStringAsRawHex8(match.c_str());
+ }
+
+ return SendPacketNoLock(response.GetString());
+}
+
+GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir(
StringExtractorGDBRemote &packet) {
@@ -416,7 +525,7 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo(
bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped(
lldb::pid_t pid) {
std::lock_guard<std::recursive_mutex> guard(m_spawned_pids_mutex);
- FreePortForProcess(pid);
+ m_port_map.FreePortForProcess(pid);
m_spawned_pids.erase(pid);
return true;
}
@@ -462,51 +571,6 @@ void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) {
m_port_map = port_map;
}
-uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() {
- if (m_port_map.empty())
- return 0; // Bind to port zero and get a port, we didn't have any
- // limitations
-
- for (auto &pair : m_port_map) {
- if (pair.second == LLDB_INVALID_PROCESS_ID) {
- pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID;
- return pair.first;
- }
- }
- return UINT16_MAX;
-}
-
-bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess(
- uint16_t port, lldb::pid_t pid) {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end()) {
- pos->second = pid;
- return true;
- }
- return false;
-}
-
-bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) {
- PortMap::iterator pos = m_port_map.find(port);
- if (pos != m_port_map.end()) {
- pos->second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- return false;
-}
-
-bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) {
- if (!m_port_map.empty()) {
- for (auto &pair : m_port_map) {
- if (pair.second == pid) {
- pair.second = LLDB_INVALID_PROCESS_ID;
- return true;
- }
- }
- }
- return false;
-}
-
const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() {
static FileSpec g_domainsocket_dir;
static llvm::once_flag g_once_flag;
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
index a8cacea78835..6b964da4a279 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h
@@ -16,13 +16,61 @@
#include "GDBRemoteCommunicationServerCommon.h"
#include "lldb/Host/Socket.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/Error.h"
+
namespace lldb_private {
namespace process_gdb_remote {
class GDBRemoteCommunicationServerPlatform
: public GDBRemoteCommunicationServerCommon {
public:
- typedef std::map<uint16_t, lldb::pid_t> PortMap;
+ class PortMap {
+ public:
+ // This class is used to restrict the range of ports that
+ // platform created debugserver/gdbserver processes will
+ // communicate on.
+
+ // Construct an empty map, where empty means any port is allowed.
+ PortMap() = default;
+
+ // Make a port map with a range of free ports
+ // from min_port to max_port-1.
+ PortMap(uint16_t min_port, uint16_t max_port);
+
+ // Add a port to the map. If it is already in the map do not modify
+ // its mapping. (used ports remain used, new ports start as free)
+ void AllowPort(uint16_t port);
+
+ // If we are using a port map where we can only use certain ports,
+ // get the next available port.
+ //
+ // If we are using a port map and we are out of ports, return an error.
+ //
+ // If we aren't using a port map, return 0 to indicate we should bind to
+ // port 0 and then figure out which port we used.
+ llvm::Expected<uint16_t> GetNextAvailablePort();
+
+ // Tie a port to a process ID. Returns false if the port is not in the port
+ // map. If the port is already in use it will be moved to the given pid.
+ // FIXME: This is and GetNextAvailablePort make create a race condition if
+ // the portmap is shared between processes.
+ bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
+
+ // Free the given port. Returns false if the port is not in the map.
+ bool FreePort(uint16_t port);
+
+ // Free the port associated with the given pid. Returns false if there is
+ // no port associated with the pid.
+ bool FreePortForProcess(lldb::pid_t pid);
+
+ // Returns true if there are no ports in the map, regardless of the state
+ // of those ports. Meaning a map with 1 used port is not empty.
+ bool empty() const;
+
+ private:
+ std::map<uint16_t, lldb::pid_t> m_port_map;
+ };
GDBRemoteCommunicationServerPlatform(
const Socket::SocketProtocol socket_protocol, const char *socket_scheme);
@@ -35,27 +83,14 @@ public:
// a port chosen by the OS.
void SetPortMap(PortMap &&port_map);
- // If we are using a port map where we can only use certain ports,
- // get the next available port.
- //
- // If we are using a port map and we are out of ports, return UINT16_MAX
- //
- // If we aren't using a port map, return 0 to indicate we should bind to
- // port 0 and then figure out which port we used.
- uint16_t GetNextAvailablePort();
-
- bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid);
-
- bool FreePort(uint16_t port);
-
- bool FreePortForProcess(lldb::pid_t pid);
-
void SetPortOffset(uint16_t port_offset);
void SetInferiorArguments(const lldb_private::Args &args);
+ // Set port if you want to use a specific port number.
+ // Otherwise port will be set to the port that was chosen for you.
Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname,
- lldb::pid_t &pid, uint16_t &port,
+ lldb::pid_t &pid, llvm::Optional<uint16_t> &port,
std::string &socket_name);
void SetPendingGdbServer(lldb::pid_t pid, uint16_t port,
@@ -81,6 +116,8 @@ protected:
PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet);
+ PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet);
+
PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet);
PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
index 1f31b45d0fa9..10006616b0c6 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -31,19 +31,20 @@ using namespace lldb_private::process_gdb_remote;
// GDBRemoteRegisterContext constructor
GDBRemoteRegisterContext::GDBRemoteRegisterContext(
ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
- GDBRemoteDynamicRegisterInfo &reg_info, bool read_all_at_once,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once,
bool write_all_at_once)
- : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info),
- m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once),
+ : RegisterContext(thread, concrete_frame_idx),
+ m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(),
+ m_read_all_at_once(read_all_at_once),
m_write_all_at_once(write_all_at_once) {
// Resize our vector of bools to contain one bool for every register. We will
// use these boolean values to know when a register value is valid in
// m_reg_data.
- m_reg_valid.resize(reg_info.GetNumRegisters());
+ m_reg_valid.resize(m_reg_info_sp->GetNumRegisters());
// Make a heap based buffer that is big enough to store all registers
DataBufferSP reg_data_sp(
- new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0));
+ new DataBufferHeap(m_reg_info_sp->GetRegisterDataByteSize(), 0));
m_reg_data.SetData(reg_data_sp);
m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder());
}
@@ -62,12 +63,12 @@ void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) {
}
size_t GDBRemoteRegisterContext::GetRegisterCount() {
- return m_reg_info.GetNumRegisters();
+ return m_reg_info_sp->GetNumRegisters();
}
const RegisterInfo *
GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
- RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg);
+ RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfoAtIndex(reg);
if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) {
const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture();
@@ -78,11 +79,11 @@ GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
}
size_t GDBRemoteRegisterContext::GetRegisterSetCount() {
- return m_reg_info.GetNumRegisterSets();
+ return m_reg_info_sp->GetNumRegisterSets();
}
const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) {
- return m_reg_info.GetRegisterSet(reg_set);
+ return m_reg_info_sp->GetRegisterSet(reg_set);
}
bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info,
@@ -209,11 +210,12 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info,
SetAllRegisterValid(true);
return true;
} else if (buffer_sp->GetByteSize() > 0) {
- const int regcount = m_reg_info.GetNumRegisters();
+ const int regcount = m_reg_info_sp->GetNumRegisters();
for (int i = 0; i < regcount; i++) {
- struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i);
- if (reginfo->byte_offset + reginfo->byte_size
- <= buffer_sp->GetByteSize()) {
+ struct RegisterInfo *reginfo =
+ m_reg_info_sp->GetRegisterInfoAtIndex(i);
+ if (reginfo->byte_offset + reginfo->byte_size <=
+ buffer_sp->GetByteSize()) {
m_reg_valid[i] = true;
} else {
m_reg_valid[i] = false;
@@ -342,6 +344,15 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
if (dst == nullptr)
return false;
+ // Code below is specific to AArch64 target in SVE state
+ // If vector granule (vg) register is being written then thread's
+ // register context reconfiguration is triggered on success.
+ bool do_reconfigure_arm64_sve = false;
+ const ArchSpec &arch = process->GetTarget().GetArchitecture();
+ if (arch.IsValid() && arch.GetTriple().isAArch64())
+ if (strcmp(reg_info->name, "vg") == 0)
+ do_reconfigure_arm64_sve = true;
+
if (data.CopyByteOrderedData(data_offset, // src offset
reg_info->byte_size, // src length
dst, // dst
@@ -361,6 +372,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
{
SetAllRegisterValid(false);
+
+ if (do_reconfigure_arm64_sve)
+ AArch64SVEReconfigure();
+
return true;
}
} else {
@@ -389,6 +404,9 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info,
} else {
// This is an actual register, write it
success = SetPrimordialRegister(reg_info, gdb_comm);
+
+ if (success && do_reconfigure_arm64_sve)
+ AArch64SVEReconfigure();
}
// Check if writing this register will invalidate any other register
@@ -506,7 +524,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues(
// m_reg_data buffer
}
data_sp = std::make_shared<DataBufferHeap>(
- m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize());
+ m_reg_data.GetDataStart(), m_reg_info_sp->GetRegisterDataByteSize());
return true;
} else {
@@ -654,9 +672,8 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues(
if (m_thread.GetProcess().get()) {
const ArchSpec &arch =
m_thread.GetProcess()->GetTarget().GetArchitecture();
- if (arch.IsValid() &&
- (arch.GetMachine() == llvm::Triple::aarch64 ||
- arch.GetMachine() == llvm::Triple::aarch64_32) &&
+ if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 ||
+ arch.GetMachine() == llvm::Triple::aarch64_32) &&
arch.GetTriple().getVendor() == llvm::Triple::Apple &&
arch.GetTriple().getOS() == llvm::Triple::IOS) {
arm64_debugserver = true;
@@ -708,7 +725,63 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues(
uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber(
lldb::RegisterKind kind, uint32_t num) {
- return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num);
+ return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+}
+
+bool GDBRemoteRegisterContext::AArch64SVEReconfigure() {
+ if (!m_reg_info_sp)
+ return false;
+
+ const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("vg");
+ if (!reg_info)
+ return false;
+
+ uint64_t fail_value = LLDB_INVALID_ADDRESS;
+ uint32_t vg_reg_num = reg_info->kinds[eRegisterKindLLDB];
+ uint64_t vg_reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value);
+
+ if (vg_reg_value != fail_value && vg_reg_value <= 32) {
+ const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("p0");
+ if (!reg_info || vg_reg_value == reg_info->byte_size)
+ return false;
+
+ if (m_reg_info_sp->UpdateARM64SVERegistersInfos(vg_reg_value)) {
+ // Make a heap based buffer that is big enough to store all registers
+ m_reg_data.SetData(std::make_shared<DataBufferHeap>(
+ m_reg_info_sp->GetRegisterDataByteSize(), 0));
+ m_reg_data.SetByteOrder(GetByteOrder());
+
+ InvalidateAllRegisters();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(uint64_t vg) {
+ // SVE Z register size is vg x 8 bytes.
+ uint32_t z_reg_byte_size = vg * 8;
+
+ // SVE vector length has changed, accordingly set size of Z, P and FFR
+ // registers. Also invalidate register offsets it will be recalculated
+ // after SVE register size update.
+ for (auto &reg : m_regs) {
+ if (reg.value_regs == nullptr) {
+ if (reg.name[0] == 'z' && isdigit(reg.name[1]))
+ reg.byte_size = z_reg_byte_size;
+ else if (reg.name[0] == 'p' && isdigit(reg.name[1]))
+ reg.byte_size = vg;
+ else if (strcmp(reg.name, "ffr") == 0)
+ reg.byte_size = vg;
+ }
+ reg.byte_offset = LLDB_INVALID_INDEX32;
+ }
+
+ // Re-calculate register offsets
+ ConfigureOffsets();
+ return true;
}
void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
index 015862587103..252d7b359ee8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -27,20 +27,25 @@ namespace process_gdb_remote {
class ThreadGDBRemote;
class ProcessGDBRemote;
+class GDBRemoteDynamicRegisterInfo;
-class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo {
+typedef std::shared_ptr<GDBRemoteDynamicRegisterInfo>
+ GDBRemoteDynamicRegisterInfoSP;
+
+class GDBRemoteDynamicRegisterInfo final : public DynamicRegisterInfo {
public:
GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {}
~GDBRemoteDynamicRegisterInfo() override = default;
void HardcodeARMRegisters(bool from_scratch);
+ bool UpdateARM64SVERegistersInfos(uint64_t vg);
};
class GDBRemoteRegisterContext : public RegisterContext {
public:
GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx,
- GDBRemoteDynamicRegisterInfo &reg_info,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp,
bool read_all_at_once, bool write_all_at_once);
~GDBRemoteRegisterContext() override;
@@ -73,6 +78,8 @@ public:
uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
uint32_t num) override;
+ bool AArch64SVEReconfigure();
+
protected:
friend class ThreadGDBRemote;
@@ -106,7 +113,7 @@ protected:
m_reg_valid[reg] = valid;
}
- GDBRemoteDynamicRegisterInfo &m_reg_info;
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
std::vector<bool> m_reg_valid;
DataExtractor m_reg_data;
bool m_read_all_at_once;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1fed8e064267..aba870c42e55 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -205,7 +205,8 @@ void ProcessGDBRemote::Terminate() {
lldb::ProcessSP
ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp,
ListenerSP listener_sp,
- const FileSpec *crash_file_path) {
+ const FileSpec *crash_file_path,
+ bool can_connect) {
lldb::ProcessSP process_sp;
if (crash_file_path == nullptr)
process_sp = std::make_shared<ProcessGDBRemote>(target_sp, listener_sp);
@@ -248,7 +249,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp,
ListenerSP listener_sp)
: Process(target_sp, listener_sp),
m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(),
- m_register_info(),
+ m_register_info_sp(nullptr),
m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"),
m_async_listener_sp(
Listener::MakeListener("lldb.process.gdb-remote.async-listener")),
@@ -367,8 +368,8 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
}
- if (m_register_info.SetRegisterInfo(*target_definition_sp,
- GetTarget().GetArchitecture()) > 0) {
+ if (m_register_info_sp->SetRegisterInfo(
+ *target_definition_sp, GetTarget().GetArchitecture()) > 0) {
return true;
}
}
@@ -395,10 +396,10 @@ static size_t SplitCommaSeparatedRegisterNumberString(
}
void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
- if (!force && m_register_info.GetNumRegisters() > 0)
+ if (!force && m_register_info_sp)
return;
- m_register_info.Clear();
+ m_register_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>();
// Check if qHostInfo specified a specific packet timeout for this
// connection. If so then lets update our setting so the user knows what the
@@ -450,7 +451,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
return;
char packet[128];
- uint32_t reg_offset = 0;
+ uint32_t reg_offset = LLDB_INVALID_INDEX32;
uint32_t reg_num = 0;
for (StringExtractorGDBRemote::ResponseType response_type =
StringExtractorGDBRemote::eResponse;
@@ -563,7 +564,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
reg_info.byte_offset = reg_offset;
assert(reg_info.byte_size != 0);
- reg_offset += reg_info.byte_size;
+ reg_offset = LLDB_INVALID_INDEX32;
if (!value_regs.empty()) {
value_regs.push_back(LLDB_INVALID_REGNUM);
reg_info.value_regs = value_regs.data();
@@ -580,7 +581,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use))
abi_sp->AugmentRegisterInfo(reg_info);
- m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ m_register_info_sp->AddRegister(reg_info, reg_name, alt_name, set_name);
} else {
break; // ensure exit before reg_num is incremented
}
@@ -589,8 +590,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
}
}
- if (m_register_info.GetNumRegisters() > 0) {
- m_register_info.Finalize(GetTarget().GetArchitecture());
+ if (m_register_info_sp->GetNumRegisters() > 0) {
+ m_register_info_sp->Finalize(GetTarget().GetArchitecture());
return;
}
@@ -599,21 +600,21 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) {
// updated debugserver down on the devices. On the other hand, if the
// accumulated reg_num is positive, see if we can add composite registers to
// the existing primordial ones.
- bool from_scratch = (m_register_info.GetNumRegisters() == 0);
+ bool from_scratch = (m_register_info_sp->GetNumRegisters() == 0);
if (!target_arch.IsValid()) {
if (arch_to_use.IsValid() &&
(arch_to_use.GetMachine() == llvm::Triple::arm ||
arch_to_use.GetMachine() == llvm::Triple::thumb) &&
arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple)
- m_register_info.HardcodeARMRegisters(from_scratch);
+ m_register_info_sp->HardcodeARMRegisters(from_scratch);
} else if (target_arch.GetMachine() == llvm::Triple::arm ||
target_arch.GetMachine() == llvm::Triple::thumb) {
- m_register_info.HardcodeARMRegisters(from_scratch);
+ m_register_info_sp->HardcodeARMRegisters(from_scratch);
}
// At this point, we can finalize our register info.
- m_register_info.Finalize(GetTarget().GetArchitecture());
+ m_register_info_sp->Finalize(GetTarget().GetArchitecture());
}
Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) {
@@ -817,8 +818,8 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module,
// since 'O' packets can really slow down debugging if the inferior
// does a lot of output.
if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) &&
- pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY, nullptr, 0)) {
- FileSpec secondary_name{pty.GetSecondaryName(nullptr, 0)};
+ !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) {
+ FileSpec secondary_name(pty.GetSecondaryName());
if (!stdin_file_spec)
stdin_file_spec = secondary_name;
@@ -1224,6 +1225,10 @@ Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid,
return m_gdb_comm.SendGetTraceConfigPacket(uid, options);
}
+llvm::Expected<TraceTypeInfo> ProcessGDBRemote::GetSupportedTraceType() {
+ return m_gdb_comm.SendGetSupportedTraceType();
+}
+
void ProcessGDBRemote::DidExit() {
// When we exit, disconnect from the GDB server communications
m_gdb_comm.Disconnect();
@@ -1597,8 +1602,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() {
return true;
}
-bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) {
+bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) {
// locker will keep a mutex locked until it goes out of scope
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD));
LLDB_LOGV(log, "pid = {0}", GetID());
@@ -1758,6 +1763,19 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData());
}
+ // AArch64 SVE specific code below calls AArch64SVEReconfigure to update
+ // SVE register sizes and offsets if value of VG register has changed
+ // since last stop.
+ const ArchSpec &arch = GetTarget().GetArchitecture();
+ if (arch.IsValid() && arch.GetTriple().isAArch64()) {
+ GDBRemoteRegisterContext *reg_ctx_sp =
+ static_cast<GDBRemoteRegisterContext *>(
+ gdb_thread->GetRegisterContext().get());
+
+ if (reg_ctx_sp)
+ reg_ctx_sp->AArch64SVEReconfigure();
+ }
+
thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str());
gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr);
@@ -2647,7 +2665,7 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() {
llvm::Expected<LoadedModuleInfoList> list = GetLoadedModuleList();
if (!list) {
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
- LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}");
+ LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}.");
} else {
addr = list->m_link_map;
}
@@ -3204,14 +3222,8 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) {
break;
case BreakpointSite::eExternal: {
- GDBStoppointType stoppoint_type;
- if (bp_site->IsHardware())
- stoppoint_type = eBreakpointHardware;
- else
- stoppoint_type = eBreakpointSoftware;
-
- if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr,
- bp_op_size))
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false,
+ addr, bp_op_size))
error.SetErrorToGenericError();
} break;
}
@@ -4277,14 +4289,14 @@ struct GdbServerTargetInfo {
bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp,
- uint32_t &cur_reg_num, uint32_t &reg_offset) {
+ uint32_t &reg_num_remote, uint32_t &reg_num_local) {
if (!feature_node)
return false;
+ uint32_t reg_offset = LLDB_INVALID_INDEX32;
feature_node.ForEachChildElementWithName(
- "reg",
- [&target_info, &dyn_reg_info, &cur_reg_num, &reg_offset,
- &abi_sp](const XMLNode &reg_node) -> bool {
+ "reg", [&target_info, &dyn_reg_info, &reg_num_remote, &reg_num_local,
+ &reg_offset, &abi_sp](const XMLNode &reg_node) -> bool {
std::string gdb_group;
std::string gdb_type;
ConstString reg_name;
@@ -4306,8 +4318,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
LLDB_INVALID_REGNUM, // eh_frame reg num
LLDB_INVALID_REGNUM, // DWARF reg num
LLDB_INVALID_REGNUM, // generic reg num
- cur_reg_num, // process plugin reg num
- cur_reg_num // native register number
+ reg_num_remote, // process plugin reg num
+ reg_num_local // native register number
},
nullptr,
nullptr,
@@ -4434,7 +4446,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
reg_info.byte_offset = reg_offset;
assert(reg_info.byte_size != 0);
- reg_offset += reg_info.byte_size;
+ reg_offset = LLDB_INVALID_INDEX32;
if (!value_regs.empty()) {
value_regs.push_back(LLDB_INVALID_REGNUM);
reg_info.value_regs = value_regs.data();
@@ -4444,7 +4456,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
reg_info.invalidate_regs = invalidate_regs.data();
}
- ++cur_reg_num;
+ reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1;
+ ++reg_num_local;
reg_info.name = reg_name.AsCString();
if (abi_sp)
abi_sp->AugmentRegisterInfo(reg_info);
@@ -4463,8 +4476,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
// for nested register definition files. It returns true if it was able
// to fetch and parse an xml file.
bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
- ArchSpec &arch_to_use, std::string xml_filename, uint32_t &cur_reg_num,
- uint32_t &reg_offset) {
+ ArchSpec &arch_to_use, std::string xml_filename, uint32_t &reg_num_remote,
+ uint32_t &reg_num_local) {
// request the target xml file
std::string raw;
lldb_private::Status lldberr;
@@ -4567,13 +4580,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
// ABI is also potentially incorrect.
ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use);
for (auto &feature_node : feature_nodes) {
- ParseRegisters(feature_node, target_info, this->m_register_info,
- abi_to_use_sp, cur_reg_num, reg_offset);
+ ParseRegisters(feature_node, target_info, *this->m_register_info_sp,
+ abi_to_use_sp, reg_num_remote, reg_num_local);
}
for (const auto &include : target_info.includes) {
- GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, cur_reg_num,
- reg_offset);
+ GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include,
+ reg_num_remote, reg_num_local);
}
}
} else {
@@ -4593,12 +4606,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
return false;
- uint32_t cur_reg_num = 0;
- uint32_t reg_offset = 0;
- if (GetGDBServerRegisterInfoXMLAndProcess (arch_to_use, "target.xml", cur_reg_num, reg_offset))
- this->m_register_info.Finalize(arch_to_use);
+ uint32_t reg_num_remote = 0;
+ uint32_t reg_num_local = 0;
+ if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
+ reg_num_remote, reg_num_local))
+ this->m_register_info_sp->Finalize(arch_to_use);
- return m_register_info.GetNumRegisters() > 0;
+ return m_register_info_sp->GetNumRegisters() > 0;
}
llvm::Expected<LoadedModuleInfoList> ProcessGDBRemote::GetLoadedModuleList() {
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index ba967727ae3b..0921bf17c4e4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -55,7 +55,8 @@ public:
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
lldb::ListenerSP listener_sp,
- const FileSpec *crash_file_path);
+ const FileSpec *crash_file_path,
+ bool can_connect);
static void Initialize();
@@ -175,6 +176,8 @@ public:
llvm::MutableArrayRef<uint8_t> &buffer,
size_t offset = 0) override;
+ llvm::Expected<TraceTypeInfo> GetSupportedTraceType() override;
+
Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override;
Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override;
@@ -251,7 +254,7 @@ protected:
// the last stop
// packet variable
std::recursive_mutex m_last_stop_packet_mutex;
- GDBRemoteDynamicRegisterInfo m_register_info;
+ GDBRemoteDynamicRegisterInfoSP m_register_info_sp;
Broadcaster m_async_broadcaster;
lldb::ListenerSP m_async_listener_sp;
HostThread m_async_thread;
@@ -309,8 +312,8 @@ protected:
void Clear();
- bool UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override;
+ bool DoUpdateThreadList(ThreadList &old_thread_list,
+ ThreadList &new_thread_list) override;
Status ConnectToReplayServer();
@@ -388,8 +391,8 @@ protected:
bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use,
std::string xml_filename,
- uint32_t &cur_reg_num,
- uint32_t &reg_offset);
+ uint32_t &cur_reg_remote,
+ uint32_t &cur_reg_local);
// Query remote GDBServer for register information
bool GetGDBServerRegisterInfo(ArchSpec &arch);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
index 6deabf8d5d71..2a9896e41085 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -42,6 +42,14 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid)
Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD));
LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(),
GetID());
+ // At this point we can clone reg_info for architectures supporting
+ // run-time update to register sizes and offsets..
+ auto &gdb_process = static_cast<ProcessGDBRemote &>(process);
+ if (!gdb_process.m_register_info_sp->IsReconfigurable())
+ m_reg_info_sp = gdb_process.m_register_info_sp;
+ else
+ m_reg_info_sp = std::make_shared<GDBRemoteDynamicRegisterInfo>(
+ *gdb_process.m_register_info_sp);
}
ThreadGDBRemote::~ThreadGDBRemote() {
@@ -307,8 +315,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) {
!pSupported || gdb_process->m_use_g_packet_for_reading;
bool write_all_registers_at_once = !pSupported;
reg_ctx_sp = std::make_shared<GDBRemoteRegisterContext>(
- *this, concrete_frame_idx, gdb_process->m_register_info,
- read_all_registers_at_once, write_all_registers_at_once);
+ *this, concrete_frame_idx, m_reg_info_sp, read_all_registers_at_once,
+ write_all_registers_at_once);
}
} else {
reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
index 5ad11170fec4..b7d75021c062 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -14,6 +14,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Utility/StructuredData.h"
+#include "GDBRemoteRegisterContext.h"
+
class StringExtractor;
namespace lldb_private {
@@ -101,6 +103,8 @@ protected:
m_queue_serial_number; // Queue info from stop reply/stop info for thread
lldb_private::LazyBool m_associated_with_libdispatch_queue;
+ GDBRemoteDynamicRegisterInfoSP m_reg_info_sp;
+
bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef<uint8_t> data);
bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval);