aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp404
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 &reg_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();
}