diff options
Diffstat (limited to 'lldb/source/Plugins/Process/gdb-remote')
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 ®_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 ®_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, + ®_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, - ®_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 ®_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 ® : 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 ®_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 ®_offset) { + uint32_t ®_num_remote, uint32_t ®_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, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", [&target_info, &dyn_reg_info, ®_num_remote, ®_num_local, + ®_offset, &abi_sp](const XMLNode ®_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 ®_offset) { + ArchSpec &arch_to_use, std::string xml_filename, uint32_t ®_num_remote, + uint32_t ®_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 ®_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); |
