diff options
Diffstat (limited to 'source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r-- | source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp | 404 |
1 files changed, 228 insertions, 176 deletions
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 797f63d537a1..a6fdd8dd0707 100644 --- a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1,9 +1,8 @@ //===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// @@ -24,6 +23,7 @@ #include <algorithm> #include <csignal> #include <map> +#include <memory> #include <mutex> #include <sstream> @@ -41,7 +41,6 @@ #include "lldb/Host/PosixApi.h" #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/XML.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -54,6 +53,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/Property.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" @@ -111,12 +111,40 @@ void DumpProcessGDBRemotePacketHistory(void *p, const char *path) { namespace { static constexpr PropertyDefinition g_properties[] = { - {"packet-timeout", OptionValue::eTypeUInt64, true, 1, NULL, {}, + {"packet-timeout", + OptionValue::eTypeUInt64, + true, + 5 +#if defined(__has_feature) +#if __has_feature(address_sanitizer) + * 2 +#endif +#endif + , + nullptr, + {}, "Specify the default packet timeout in seconds."}, - {"target-definition-file", OptionValue::eTypeFileSpec, true, 0, NULL, {}, - "The file that provides the description for remote target registers."}}; - -enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; + {"target-definition-file", + OptionValue::eTypeFileSpec, + true, + 0, + nullptr, + {}, + "The file that provides the description for remote target registers."}, + {"use-libraries-svr4", + OptionValue::eTypeBoolean, + true, + false, + nullptr, + {}, + "If true, the libraries-svr4 feature will be used to get a hold of the " + "process's loaded modules."}}; + +enum { + ePropertyPacketTimeout, + ePropertyTargetDefinitionFile, + ePropertyUseSVR4 +}; class PluginProperties : public Properties { public: @@ -125,26 +153,32 @@ public: } PluginProperties() : Properties() { - m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); m_collection_sp->Initialize(g_properties); } - virtual ~PluginProperties() {} + ~PluginProperties() override {} uint64_t GetPacketTimeout() { const uint32_t idx = ePropertyPacketTimeout; return m_collection_sp->GetPropertyAtIndexAsUInt64( - NULL, idx, g_properties[idx].default_uint_value); + nullptr, idx, g_properties[idx].default_uint_value); } bool SetPacketTimeout(uint64_t timeout) { const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); + return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, timeout); } FileSpec GetTargetDefinitionFile() const { const uint32_t idx = ePropertyTargetDefinitionFile; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx); + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); + } + + bool GetUseSVR4() const { + const uint32_t idx = ePropertyUseSVR4; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } }; @@ -153,25 +187,27 @@ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { static ProcessKDPPropertiesSP g_settings_sp; if (!g_settings_sp) - g_settings_sp.reset(new PluginProperties()); + g_settings_sp = std::make_shared<PluginProperties>(); return g_settings_sp; } class ProcessGDBRemoteProvider : public repro::Provider<ProcessGDBRemoteProvider> { public: + struct Info { + static const char *name; + static const char *file; + }; + ProcessGDBRemoteProvider(const FileSpec &directory) : Provider(directory) { - m_info.name = "gdb-remote"; - m_info.files.push_back("gdb-remote.yaml"); } raw_ostream *GetHistoryStream() { - FileSpec history_file = - GetRoot().CopyByAppendingPathComponent("gdb-remote.yaml"); + FileSpec history_file = GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code EC; m_stream_up = llvm::make_unique<raw_fd_ostream>(history_file.GetPath(), EC, - sys::fs::OpenFlags::F_None); + sys::fs::OpenFlags::F_Text); return m_stream_up.get(); } @@ -191,6 +227,8 @@ private: }; char ProcessGDBRemoteProvider::ID = 0; +const char *ProcessGDBRemoteProvider::Info::name = "gdb-remote"; +const char *ProcessGDBRemoteProvider::Info::file = "gdb-remote.yaml"; } // namespace @@ -239,8 +277,8 @@ ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, ListenerSP listener_sp, const FileSpec *crash_file_path) { lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset(new ProcessGDBRemote(target_sp, listener_sp)); + if (crash_file_path == nullptr) + process_sp = std::make_shared<ProcessGDBRemote>(target_sp, listener_sp); return process_sp; } @@ -275,15 +313,13 @@ bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, return true; } -//---------------------------------------------------------------------- // ProcessGDBRemote constructor -//---------------------------------------------------------------------- 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_async_broadcaster(NULL, "lldb.process.gdb-remote.async-broadcaster"), + m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"), m_async_listener_sp( Listener::MakeListener("lldb.process.gdb-remote.async-listener")), m_async_thread_state_mutex(), m_thread_ids(), m_thread_pcs(), @@ -340,9 +376,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_gdb_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); } -//---------------------------------------------------------------------- // Destructor -//---------------------------------------------------------------------- ProcessGDBRemote::~ProcessGDBRemote() { // m_mach_process.UnregisterNotificationCallbacks (this); Clear(); @@ -360,9 +394,7 @@ ProcessGDBRemote::~ProcessGDBRemote() { KillDebugserverProcess(); } -//---------------------------------------------------------------------- // PluginInterface -//---------------------------------------------------------------------- ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); } uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; } @@ -370,7 +402,7 @@ uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; } bool ProcessGDBRemote::ParsePythonTargetDefinition( const FileSpec &target_definition_fspec) { ScriptInterpreter *interpreter = - GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); + GetTarget().GetDebugger().GetScriptInterpreter(); Status error; StructuredData::ObjectSP module_object_sp( interpreter->LoadPluginModule(target_definition_fspec, error)); @@ -540,8 +572,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { std::vector<uint32_t> invalidate_regs; std::vector<uint8_t> dwarf_opcode_bytes; RegisterInfo reg_info = { - NULL, // Name - NULL, // Alt name + nullptr, // Name + nullptr, // Alt name 0, // byte size reg_offset, // offset eEncodingUint, // encoding @@ -553,10 +585,10 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_num, // process plugin reg num reg_num // native register number }, - NULL, - NULL, - NULL, // Dwarf expression opcode bytes pointer - 0 // Dwarf expression opcode bytes length + nullptr, + nullptr, + nullptr, // Dwarf expression opcode bytes pointer + 0 // Dwarf expression opcode bytes length }; while (response.GetNameColonValue(name, value)) { @@ -576,7 +608,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.encoding = encoding; } else if (name.equals("format")) { Format format = eFormatInvalid; - if (OptionArgParser::ToFormat(value.str().c_str(), format, NULL) + if (OptionArgParser::ToFormat(value.str().c_str(), format, nullptr) .Success()) reg_info.format = format; else { @@ -796,9 +828,7 @@ Status ProcessGDBRemote::WillLaunchOrAttach() { return error; } -//---------------------------------------------------------------------- // Process Control -//---------------------------------------------------------------------- Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, ProcessLaunchInfo &launch_info) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); @@ -883,8 +913,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.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, NULL, 0)) { - FileSpec slave_name{pty.GetSlaveName(NULL, 0)}; + pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, nullptr, 0)) { + FileSpec slave_name{pty.GetSlaveName(nullptr, 0)}; if (!stdin_file_spec) stdin_file_spec = slave_name; @@ -928,7 +958,7 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, GetTarget().GetArchitecture().GetArchitectureName()); const char *launch_event_data = launch_info.GetLaunchEventData(); - if (launch_event_data != NULL && *launch_event_data != '\0') + if (launch_event_data != nullptr && *launch_event_data != '\0') m_gdb_comm.SendLaunchEventDataPacket(launch_event_data); if (working_dir) { @@ -1013,14 +1043,14 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { if (log) log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, connect_url.str().c_str()); - std::unique_ptr<ConnectionFileDescriptor> conn_ap( + std::unique_ptr<ConnectionFileDescriptor> conn_up( new ConnectionFileDescriptor()); - if (conn_ap.get()) { + if (conn_up) { const uint32_t max_retry_count = 50; uint32_t retry_count = 0; while (!m_gdb_comm.IsConnected()) { - if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) { - m_gdb_comm.SetConnection(conn_ap.release()); + if (conn_up->Connect(connect_url, &error) == eConnectionStatusSuccess) { + m_gdb_comm.SetConnection(conn_up.release()); break; } else if (error.WasInterrupted()) { // If we were interrupted, don't keep retrying. @@ -1702,7 +1732,7 @@ bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { - thread_sp.reset(new ThreadGDBRemote(*this, tid)); + thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.", thread_sp.get(), thread_sp->GetID()); } else { @@ -1818,7 +1848,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (!thread_sp) { // Create the thread if we need to - thread_sp.reset(new ThreadGDBRemote(*this, tid)); + thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); m_thread_list_real.AddThread(thread_sp); } } @@ -1842,7 +1872,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); } - thread_sp->SetName(thread_name.empty() ? NULL : thread_name.c_str()); + thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); gdb_thread->SetThreadDispatchQAddr(thread_dispatch_qaddr); // Check if the GDB server was able to provide the queue name, kind and @@ -2421,6 +2451,15 @@ void ProcessGDBRemote::RefreshStateAfterStop() { // Scope for the lock { + // Check to see if SetThreadStopInfo() filled in m_thread_ids? + if (m_thread_ids.empty()) { + // No, we need to fetch the thread list manually + UpdateThreadIDList(); + } + // We might set some stop info's so make sure the thread list is up to + // date before we do that or we might overwrite what was computed here. + UpdateThreadListIfNeeded(); + // Lock the thread stack while we access it std::lock_guard<std::recursive_mutex> guard(m_last_stop_packet_mutex); // Get the number of stop packets on the stack @@ -2435,13 +2474,7 @@ void ProcessGDBRemote::RefreshStateAfterStop() { // Clear the thread stop stack m_stop_packet_stack.clear(); } - - // Check to see if SetThreadStopInfo() filled in m_thread_ids? - if (m_thread_ids.empty()) { - // No, we need to fetch the thread list manually - UpdateThreadIDList(); - } - + // If we have queried for a default thread id if (m_initial_tid != LLDB_INVALID_THREAD_ID) { m_thread_list.SetSelectedThreadByID(m_initial_tid); @@ -2711,9 +2744,7 @@ void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) { Process::SetUnixSignals(std::make_shared<GDBRemoteSignals>(signals_sp)); } -//------------------------------------------------------------------ // Process Queries -//------------------------------------------------------------------ bool ProcessGDBRemote::IsAlive() { return m_gdb_comm.IsConnected() && Process::IsAlive(); @@ -2757,9 +2788,7 @@ void ProcessGDBRemote::WillPublicStop() { } } -//------------------------------------------------------------------ // Process Memory -//------------------------------------------------------------------ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, Status &error) { GetMaxMemorySize(); @@ -3120,14 +3149,12 @@ Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) { return error; } -//------------------------------------------------------------------ // Process STDIO -//------------------------------------------------------------------ size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len, Status &error) { if (m_stdio_communication.IsConnected()) { ConnectionStatus status; - m_stdio_communication.Write(src, src_len, status, NULL); + m_stdio_communication.Write(src, src_len, status, nullptr); } else if (m_stdin_forward) { m_gdb_comm.SendStdinNotification(src, src_len); } @@ -3136,7 +3163,7 @@ size_t ProcessGDBRemote::PutSTDIN(const char *src, size_t src_len, Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { Status error; - assert(bp_site != NULL); + assert(bp_site != nullptr); // Get logging info Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); @@ -3262,7 +3289,7 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { Status error; - assert(bp_site != NULL); + assert(bp_site != nullptr); addr_t addr = bp_site->GetLoadAddress(); user_id_t site_id = bp_site->GetID(); Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); @@ -3432,16 +3459,10 @@ Status ProcessGDBRemote::ConnectToReplayServer(repro::Loader *loader) { if (!loader) return Status("No loader provided."); - auto provider_info = loader->GetProviderInfo("gdb-remote"); - if (!provider_info) - return Status("No provider for gdb-remote."); - - if (provider_info->files.empty()) - return Status("Provider for gdb-remote contains no files."); - // Construct replay history path. - FileSpec history_file = loader->GetRoot().CopyByAppendingPathComponent( - provider_info->files.front()); + FileSpec history_file = loader->GetFile<ProcessGDBRemoteProvider::Info>(); + if (!history_file) + return Status("No provider for gdb-remote."); // Enable replay mode. m_replay_mode = true; @@ -3679,9 +3700,15 @@ bool ProcessGDBRemote::StartAsyncThread() { // Create a thread that watches our internal state and controls which // events make it to clients (into the DCProcess event queue). - m_async_thread = - ThreadLauncher::LaunchThread("<lldb.process.gdb-remote.async>", - ProcessGDBRemote::AsyncThread, this, NULL); + llvm::Expected<HostThread> async_thread = ThreadLauncher::LaunchThread( + "<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this); + if (!async_thread) { + LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + "failed to launch host thread: {}", + llvm::toString(async_thread.takeError())); + return false; + } + m_async_thread = *async_thread; } else if (log) log->Printf("ProcessGDBRemote::%s () - Called when Async thread was " "already running.", @@ -3775,7 +3802,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr); - if (::strstr(continue_cstr, "vAttach") == NULL) + if (::strstr(continue_cstr, "vAttach") == nullptr) process->SetPrivateState(eStateRunning); StringExtractorGDBRemote response; @@ -3841,11 +3868,11 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { // the "E87" error code from debugserver -- this indicates that // the process is not debuggable. Return a slightly more // helpful error message about why the attach failed. - if (::strstr(continue_cstr, "vAttach") != NULL && + if (::strstr(continue_cstr, "vAttach") != nullptr && response.GetError() == 0x87) { process->SetExitStatus(-1, "cannot attach to process due to " "System Integrity Protection"); - } else if (::strstr(continue_cstr, "vAttach") != NULL && + } else if (::strstr(continue_cstr, "vAttach") != nullptr && response.GetStatus().Fail()) { process->SetExitStatus(-1, response.GetStatus().AsCString()); } else { @@ -3920,7 +3947,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { ") thread exiting...", __FUNCTION__, arg, process->GetID()); - return NULL; + return {}; } // uint32_t @@ -4016,7 +4043,7 @@ bool ProcessGDBRemote::StartNoticingNewThreads() { } } } - return m_thread_create_bp_sp.get() != NULL; + return m_thread_create_bp_sp.get() != nullptr; } bool ProcessGDBRemote::StopNoticingNewThreads() { @@ -4031,9 +4058,9 @@ bool ProcessGDBRemote::StopNoticingNewThreads() { } DynamicLoader *ProcessGDBRemote::GetDynamicLoader() { - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset(DynamicLoader::FindPlugin(this, NULL)); - return m_dyld_ap.get(); + if (m_dyld_up.get() == nullptr) + m_dyld_up.reset(DynamicLoader::FindPlugin(this, nullptr)); + return m_dyld_up.get(); } Status ProcessGDBRemote::SendEventData(const char *data) { @@ -4053,17 +4080,17 @@ Status ProcessGDBRemote::SendEventData(const char *data) { return error; } -const DataBufferSP ProcessGDBRemote::GetAuxvData() { +DataExtractor ProcessGDBRemote::GetAuxvData() { DataBufferSP buf; if (m_gdb_comm.GetQXferAuxvReadSupported()) { std::string response_string; if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) - buf.reset(new DataBufferHeap(response_string.c_str(), - response_string.length())); + buf = std::make_shared<DataBufferHeap>(response_string.c_str(), + response_string.length()); } - return buf; + return DataExtractor(buf, GetByteOrder(), GetAddressByteSize()); } StructuredData::ObjectSP @@ -4212,7 +4239,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { } Status ProcessGDBRemote::ConfigureStructuredData( - const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + ConstString type_name, const StructuredData::ObjectSP &config_sp) { return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp); } @@ -4373,8 +4400,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, bool encoding_set = false; bool format_set = false; RegisterInfo reg_info = { - NULL, // Name - NULL, // Alt name + nullptr, // Name + nullptr, // Alt name 0, // byte size reg_offset, // offset eEncodingUint, // encoding @@ -4386,10 +4413,10 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, cur_reg_num, // process plugin reg num cur_reg_num // native register number }, - NULL, - NULL, - NULL, // Dwarf Expression opcode bytes pointer - 0 // Dwarf Expression opcode bytes length + nullptr, + nullptr, + nullptr, // Dwarf Expression opcode bytes pointer + 0 // Dwarf Expression opcode bytes length }; reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, @@ -4423,7 +4450,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } else if (name == "format") { format_set = true; Format format = eFormatInvalid; - if (OptionArgParser::ToFormat(value.data(), format, NULL).Success()) + if (OptionArgParser::ToFormat(value.data(), format, nullptr) + .Success()) reg_info.format = format; else if (value == "vector-sint8") reg_info.format = eFormatVectorOfSInt8; @@ -4499,8 +4527,15 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, // Only update the register set name if we didn't get a "reg_set" // attribute. "set_name" will be empty if we didn't have a "reg_set" // attribute. - if (!set_name && !gdb_group.empty()) - set_name.SetCString(gdb_group.c_str()); + if (!set_name) { + if (!gdb_group.empty()) { + set_name.SetCString(gdb_group.c_str()); + } else { + // If no register group name provided anywhere, + // we'll create a 'general' register set + set_name.SetCString("general"); + } + } reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); @@ -4525,38 +4560,33 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, } // namespace -// query the target of gdb-remote for extended target information return: -// 'true' on success -// 'false' on failure -bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { - // Make sure LLDB has an XML parser it can use first - if (!XMLDocument::XMLEnabled()) - return false; - - // redirect libxml2's error handler since the default prints to stdout - - GDBRemoteCommunicationClient &comm = m_gdb_comm; - - // check that we have extended feature read support - if (!comm.GetQXferFeaturesReadSupported()) - return false; - +// This method fetches a register description feature xml file from +// the remote stub and adds registers/register groupsets/architecture +// information to the current process. It will call itself recursively +// 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) { // request the target xml file std::string raw; lldb_private::Status lldberr; - if (!comm.ReadExtFeature(ConstString("features"), ConstString("target.xml"), + if (!m_gdb_comm.ReadExtFeature(ConstString("features"), + ConstString(xml_filename.c_str()), raw, lldberr)) { return false; } XMLDocument xml_document; - if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) { + if (xml_document.ParseMemory(raw.c_str(), raw.size(), xml_filename.c_str())) { GdbServerTargetInfo target_info; + std::vector<XMLNode> feature_nodes; + // The top level feature XML file will start with a <target> tag. XMLNode target_node = xml_document.GetRootElement("target"); if (target_node) { - std::vector<XMLNode> feature_nodes; target_node.ForEachChildElement([&target_info, &feature_nodes]( const XMLNode &node) -> bool { llvm::StringRef name = node.GetName(); @@ -4594,32 +4624,48 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { } return true; // Keep iterating through all children of the target_node }); + } else { + // In an included XML feature file, we're already "inside" the <target> + // tag of the initial XML file; this included file will likely only have + // a <feature> tag. Need to check for any more included files in this + // <feature> element. + XMLNode feature_node = xml_document.GetRootElement("feature"); + if (feature_node) { + feature_nodes.push_back(feature_node); + feature_node.ForEachChildElement([&target_info]( + const XMLNode &node) -> bool { + llvm::StringRef name = node.GetName(); + if (name == "xi:include" || name == "include") { + llvm::StringRef href = node.GetAttributeValue("href"); + if (!href.empty()) + target_info.includes.push_back(href.str()); + } + return true; + }); + } + } - // If the target.xml includes an architecture entry like - // <architecture>i386:x86-64</architecture> (seen from VMWare ESXi) - // <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board) - // use that if we don't have anything better. - if (!arch_to_use.IsValid() && !target_info.arch.empty()) { - if (target_info.arch == "i386:x86-64") { - // We don't have any information about vendor or OS. - arch_to_use.SetTriple("x86_64--"); - GetTarget().MergeArchitecture(arch_to_use); - } - - // SEGGER J-Link jtag boards send this very-generic arch name, - // we'll need to use this if we have absolutely nothing better - // to work with or the register definitions won't be accepted. - if (target_info.arch == "arm") { - arch_to_use.SetTriple("arm--"); - GetTarget().MergeArchitecture(arch_to_use); - } + // If the target.xml includes an architecture entry like + // <architecture>i386:x86-64</architecture> (seen from VMWare ESXi) + // <architecture>arm</architecture> (seen from Segger JLink on unspecified arm board) + // use that if we don't have anything better. + if (!arch_to_use.IsValid() && !target_info.arch.empty()) { + if (target_info.arch == "i386:x86-64") { + // We don't have any information about vendor or OS. + arch_to_use.SetTriple("x86_64--"); + GetTarget().MergeArchitecture(arch_to_use); } - // Initialize these outside of ParseRegisters, since they should not be - // reset inside each include feature - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; + // SEGGER J-Link jtag boards send this very-generic arch name, + // we'll need to use this if we have absolutely nothing better + // to work with or the register definitions won't be accepted. + if (target_info.arch == "arm") { + arch_to_use.SetTriple("arm--"); + GetTarget().MergeArchitecture(arch_to_use); + } + } + if (arch_to_use.IsValid()) { // Don't use Process::GetABI, this code gets called from DidAttach, and // in that context we haven't set the Target's architecture yet, so the // ABI is also potentially incorrect. @@ -4630,26 +4676,31 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { } for (const auto &include : target_info.includes) { - // request register file - std::string xml_data; - if (!comm.ReadExtFeature(ConstString("features"), ConstString(include), - xml_data, lldberr)) - continue; - - XMLDocument include_xml_document; - include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), - include.c_str()); - XMLNode include_feature_node = - include_xml_document.GetRootElement("feature"); - if (include_feature_node) { - ParseRegisters(include_feature_node, target_info, - this->m_register_info, abi_to_use_sp, cur_reg_num, - reg_offset); - } + GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, + cur_reg_num, reg_offset); } - this->m_register_info.Finalize(arch_to_use); } + } else { + return false; } + return true; +} + +// query the target of gdb-remote for extended target information returns +// true on success (got register definitions), false on failure (did not). +bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { + // Make sure LLDB has an XML parser it can use first + if (!XMLDocument::XMLEnabled()) + return false; + + // check that we have extended feature read support + 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); return m_register_info.GetNumRegisters() > 0; } @@ -4664,9 +4715,10 @@ Status ProcessGDBRemote::GetLoadedModuleList(LoadedModuleInfoList &list) { log->Printf("ProcessGDBRemote::%s", __FUNCTION__); GDBRemoteCommunicationClient &comm = m_gdb_comm; + bool can_use_svr4 = GetGlobalPluginProperties()->GetUseSVR4(); // check that we have extended feature read support - if (comm.GetQXferLibrariesSVR4ReadSupported()) { + if (can_use_svr4 && comm.GetQXferLibrariesSVR4ReadSupported()) { list.clear(); // request the loaded library list @@ -4929,7 +4981,7 @@ Status ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file, StreamString packet; packet.PutCString("qFileLoadAddress:"); - packet.PutCStringAsRawHex8(file_path.c_str()); + packet.PutStringAsRawHex8(file_path); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, @@ -5140,7 +5192,7 @@ public: "Tests packet speeds of various sizes to determine " "the performance characteristics of the GDB remote " "connection. ", - NULL), + nullptr), m_option_group(), m_num_packets(LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size " @@ -5165,7 +5217,7 @@ public: m_option_group.Finalize(); } - ~CommandObjectProcessGDBRemoteSpeedTest() {} + ~CommandObjectProcessGDBRemoteSpeedTest() override {} Options *GetOptions() override { return &m_option_group; } @@ -5214,9 +5266,9 @@ private: public: CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "process plugin packet history", - "Dumps the packet history buffer. ", NULL) {} + "Dumps the packet history buffer. ", nullptr) {} - ~CommandObjectProcessGDBRemotePacketHistory() {} + ~CommandObjectProcessGDBRemotePacketHistory() override {} bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5245,9 +5297,9 @@ public: : CommandObjectParsed( interpreter, "process plugin packet xfer-size", "Maximum size that lldb will try to read/write one one chunk.", - NULL) {} + nullptr) {} - ~CommandObjectProcessGDBRemotePacketXferSize() {} + ~CommandObjectProcessGDBRemotePacketXferSize() override {} bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5265,7 +5317,7 @@ public: if (process) { const char *packet_size = command.GetArgumentAtIndex(0); errno = 0; - uint64_t user_specified_max = strtoul(packet_size, NULL, 10); + uint64_t user_specified_max = strtoul(packet_size, nullptr, 10); if (errno == 0 && user_specified_max != 0) { process->SetUserSpecifiedMaxMemoryTransferSize(user_specified_max); result.SetStatus(eReturnStatusSuccessFinishResult); @@ -5287,9 +5339,9 @@ public: "The packet header and footer will automatically " "be added to the packet prior to sending and " "stripped from the result.", - NULL) {} + nullptr) {} - ~CommandObjectProcessGDBRemotePacketSend() {} + ~CommandObjectProcessGDBRemotePacketSend() override {} bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5315,7 +5367,7 @@ public: output_strm.Printf(" packet: %s\n", packet_cstr); std::string &response_str = response.GetStringRef(); - if (strstr(packet_cstr, "qGetProfileData") != NULL) { + if (strstr(packet_cstr, "qGetProfileData") != nullptr) { response_str = process->HarmonizeThreadIdsForProfileData(response); } @@ -5340,7 +5392,7 @@ public: "encoded into a valid 'qRcmd' packet, sent and the " "response will be printed.") {} - ~CommandObjectProcessGDBRemotePacketMonitor() {} + ~CommandObjectProcessGDBRemotePacketMonitor() override {} bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override { @@ -5383,7 +5435,7 @@ public: CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) : CommandObjectMultiword(interpreter, "process plugin packet", "Commands that deal with GDB remote packets.", - NULL) { + nullptr) { LoadSubCommand( "history", CommandObjectSP( @@ -5404,7 +5456,7 @@ public: interpreter))); } - ~CommandObjectProcessGDBRemotePacket() {} + ~CommandObjectProcessGDBRemotePacket() override {} }; class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword { @@ -5419,12 +5471,12 @@ public: CommandObjectSP(new CommandObjectProcessGDBRemotePacket(interpreter))); } - ~CommandObjectMultiwordProcessGDBRemote() {} + ~CommandObjectMultiwordProcessGDBRemote() override {} }; CommandObject *ProcessGDBRemote::GetPluginCommandObject() { if (!m_command_sp) - m_command_sp.reset(new CommandObjectMultiwordProcessGDBRemote( - GetTarget().GetDebugger().GetCommandInterpreter())); + m_command_sp = std::make_shared<CommandObjectMultiwordProcessGDBRemote>( + GetTarget().GetDebugger().GetCommandInterpreter()); return m_command_sp.get(); } |