aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp443
1 files changed, 352 insertions, 91 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index de8f2df52f23..b6f146fd872e 100644
--- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -53,6 +53,7 @@
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/RegisterFlags.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -84,6 +85,7 @@
#include "lldb/Utility/StringExtractorGDBRemote.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/Threading.h"
@@ -111,7 +113,7 @@ void DumpProcessGDBRemotePacketHistory(void *p, const char *path) {
return;
}
StreamFile stream(std::move(file.get()));
- ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory(stream);
+ ((Process *)p)->DumpPluginHistory(stream);
}
} // namespace lldb
@@ -140,30 +142,29 @@ public:
uint64_t GetPacketTimeout() {
const uint32_t idx = ePropertyPacketTimeout;
- return m_collection_sp->GetPropertyAtIndexAsUInt64(
- nullptr, idx, g_processgdbremote_properties[idx].default_uint_value);
+ return GetPropertyAtIndexAs<uint64_t>(
+ idx, g_processgdbremote_properties[idx].default_uint_value);
}
bool SetPacketTimeout(uint64_t timeout) {
const uint32_t idx = ePropertyPacketTimeout;
- return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, timeout);
+ return SetPropertyAtIndex(idx, timeout);
}
FileSpec GetTargetDefinitionFile() const {
const uint32_t idx = ePropertyTargetDefinitionFile;
- return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx);
+ return GetPropertyAtIndexAs<FileSpec>(idx, {});
}
bool GetUseSVR4() const {
const uint32_t idx = ePropertyUseSVR4;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(
- nullptr, idx,
- g_processgdbremote_properties[idx].default_uint_value != 0);
+ return GetPropertyAtIndexAs<bool>(
+ idx, g_processgdbremote_properties[idx].default_uint_value != 0);
}
bool GetUseGPacketForReading() const {
const uint32_t idx = ePropertyUseGPacketForReading;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
+ return GetPropertyAtIndexAs<bool>(idx, true);
}
};
@@ -204,6 +205,11 @@ lldb::ProcessSP ProcessGDBRemote::CreateInstance(
return process_sp;
}
+void ProcessGDBRemote::DumpPluginHistory(Stream &s) {
+ GDBRemoteCommunicationClient &gdb_comm(GetGDBRemote());
+ gdb_comm.DumpHistory(s);
+}
+
std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() {
return std::chrono::seconds(GetGlobalPluginProperties().GetPacketTimeout());
}
@@ -341,7 +347,7 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition(
target_definition_sp->GetValueForKey("breakpoint-pc-offset");
if (breakpoint_pc_offset_value) {
if (auto breakpoint_pc_int_value =
- breakpoint_pc_offset_value->GetAsInteger())
+ breakpoint_pc_offset_value->GetAsSignedInteger())
m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue();
}
@@ -994,9 +1000,11 @@ void ProcessGDBRemote::LoadStubBinaries() {
if (standalone_uuid.IsValid()) {
const bool force_symbol_search = true;
const bool notify = true;
+ const bool set_address_in_target = true;
DynamicLoader::LoadBinaryWithUUIDAndAddress(
this, "", standalone_uuid, standalone_value,
- standalone_value_is_offset, force_symbol_search, notify);
+ standalone_value_is_offset, force_symbol_search, notify,
+ set_address_in_target);
}
}
@@ -1024,10 +1032,11 @@ void ProcessGDBRemote::LoadStubBinaries() {
continue;
const bool force_symbol_search = true;
+ const bool set_address_in_target = true;
// Second manually load this binary into the Target.
- DynamicLoader::LoadBinaryWithUUIDAndAddress(this, llvm::StringRef(), uuid,
- addr, value_is_slide,
- force_symbol_search, notify);
+ DynamicLoader::LoadBinaryWithUUIDAndAddress(
+ this, llvm::StringRef(), uuid, addr, value_is_slide,
+ force_symbol_search, notify, set_address_in_target);
}
}
}
@@ -1749,33 +1758,60 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
} else if (reason == "trap") {
// Let the trap just use the standard signal stop reason below...
} else if (reason == "watchpoint") {
+ // We will have between 1 and 3 fields in the description.
+ //
+ // \a wp_addr which is the original start address that
+ // lldb requested be watched, or an address that the
+ // hardware reported. This address should be within the
+ // range of a currently active watchpoint region - lldb
+ // should be able to find a watchpoint with this address.
+ //
+ // \a wp_index is the hardware watchpoint register number.
+ //
+ // \a wp_hit_addr is the actual address reported by the hardware,
+ // which may be outside the range of a region we are watching.
+ //
+ // On MIPS, we may get a false watchpoint exception where an
+ // access to the same 8 byte granule as a watchpoint will trigger,
+ // even if the access was not within the range of the watched
+ // region. When we get a \a wp_hit_addr outside the range of any
+ // set watchpoint, continue execution without making it visible to
+ // the user.
+ //
+ // On ARM, a related issue where a large access that starts
+ // before the watched region (and extends into the watched
+ // region) may report a hit address before the watched region.
+ // lldb will not find the "nearest" watchpoint to
+ // disable/step/re-enable it, so one of the valid watchpoint
+ // addresses should be provided as \a wp_addr.
StringExtractor desc_extractor(description.c_str());
addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32);
addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS);
watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
- if (wp_addr != LLDB_INVALID_ADDRESS) {
- WatchpointSP wp_sp;
+ bool silently_continue = false;
+ WatchpointSP wp_sp;
+ if (wp_hit_addr != LLDB_INVALID_ADDRESS) {
+ wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr);
+ // On MIPS, \a wp_hit_addr outside the range of a watched
+ // region means we should silently continue, it is a false hit.
ArchSpec::Core core = GetTarget().GetArchitecture().GetCore();
- if ((core >= ArchSpec::kCore_mips_first &&
- core <= ArchSpec::kCore_mips_last) ||
- (core >= ArchSpec::eCore_arm_generic &&
- core <= ArchSpec::eCore_arm_aarch64))
- wp_sp =
- GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr);
- if (!wp_sp)
- wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
- if (wp_sp) {
- wp_sp->SetHardwareIndex(wp_index);
- watch_id = wp_sp->GetID();
- }
+ if (!wp_sp && core >= ArchSpec::kCore_mips_first &&
+ core <= ArchSpec::kCore_mips_last)
+ silently_continue = true;
+ }
+ if (!wp_sp && wp_addr != LLDB_INVALID_ADDRESS)
+ wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr);
+ if (wp_sp) {
+ wp_sp->SetHardwareIndex(wp_index);
+ watch_id = wp_sp->GetID();
}
if (watch_id == LLDB_INVALID_WATCH_ID) {
Log *log(GetLog(GDBRLog::Watchpoints));
LLDB_LOGF(log, "failed to find watchpoint");
}
thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithWatchpointID(
- *thread_sp, watch_id, wp_hit_addr));
+ *thread_sp, watch_id, silently_continue));
handled = true;
} else if (reason == "exception") {
thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithException(
@@ -1939,23 +1975,24 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
StructuredData::Object *object) -> bool {
if (key == g_key_tid) {
// thread in big endian hex
- tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID);
+ tid = object->GetUnsignedIntegerValue(LLDB_INVALID_THREAD_ID);
} else if (key == g_key_metype) {
// exception type in big endian hex
- exc_type = object->GetIntegerValue(0);
+ exc_type = object->GetUnsignedIntegerValue(0);
} else if (key == g_key_medata) {
// exception data in big endian hex
StructuredData::Array *array = object->GetAsArray();
if (array) {
array->ForEach([&exc_data](StructuredData::Object *object) -> bool {
- exc_data.push_back(object->GetIntegerValue());
+ exc_data.push_back(object->GetUnsignedIntegerValue());
return true; // Keep iterating through all array items
});
}
} else if (key == g_key_name) {
thread_name = std::string(object->GetStringValue());
} else if (key == g_key_qaddr) {
- thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS);
+ thread_dispatch_qaddr =
+ object->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
} else if (key == g_key_queue_name) {
queue_vars_valid = true;
queue_name = std::string(object->GetStringValue());
@@ -1969,11 +2006,11 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
queue_kind = eQueueKindConcurrent;
}
} else if (key == g_key_queue_serial_number) {
- queue_serial_number = object->GetIntegerValue(0);
+ queue_serial_number = object->GetUnsignedIntegerValue(0);
if (queue_serial_number != 0)
queue_vars_valid = true;
} else if (key == g_key_dispatch_queue_t) {
- dispatch_queue_t = object->GetIntegerValue(0);
+ dispatch_queue_t = object->GetUnsignedIntegerValue(0);
if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS)
queue_vars_valid = true;
} else if (key == g_key_associated_with_dispatch_queue) {
@@ -2034,7 +2071,7 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
}
} else if (key == g_key_signal)
- signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER);
+ signo = object->GetUnsignedIntegerValue(LLDB_INVALID_SIGNAL_NUMBER);
return true; // Keep iterating through all dictionary key/value pairs
});
@@ -2202,6 +2239,9 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
if (wp_sp)
wp_index = wp_sp->GetHardwareIndex();
+ // Rewrite gdb standard watch/rwatch/awatch to
+ // "reason:watchpoint" + "description:ADDR",
+ // which is parsed in SetThreadStopInfo.
reason = "watchpoint";
StreamString ostr;
ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index);
@@ -2226,6 +2266,13 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
StreamString ostr;
ostr.Printf("%" PRIu64 " %" PRIu64, pid_tid->first, pid_tid->second);
description = std::string(ostr.GetString());
+ } else if (key.compare("addressing_bits") == 0) {
+ uint64_t addressing_bits;
+ if (!value.getAsInteger(0, addressing_bits)) {
+ addr_t address_mask = ~((1ULL << addressing_bits) - 1);
+ SetCodeAddressMask(address_mask);
+ SetDataAddressMask(address_mask);
+ }
} else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) {
uint32_t reg = UINT32_MAX;
if (!key.getAsInteger(16, reg))
@@ -2818,16 +2865,12 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
return error;
}
-Status ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num) {
-
- Status error(m_gdb_comm.GetWatchpointSupportInfo(num));
- return error;
+std::optional<uint32_t> ProcessGDBRemote::GetWatchpointSlotCount() {
+ return m_gdb_comm.GetWatchpointSlotCount();
}
-Status ProcessGDBRemote::GetWatchpointSupportInfo(uint32_t &num, bool &after) {
- Status error(m_gdb_comm.GetWatchpointSupportInfo(
- num, after, GetTarget().GetArchitecture()));
- return error;
+std::optional<bool> ProcessGDBRemote::DoGetWatchpointReportedAfter() {
+ return m_gdb_comm.GetWatchpointReportedAfter();
}
Status ProcessGDBRemote::DoDeallocateMemory(lldb::addr_t addr) {
@@ -3372,8 +3415,7 @@ void ProcessGDBRemote::DebuggerInitialize(Debugger &debugger) {
const bool is_global_setting = true;
PluginManager::CreateSettingForProcessPlugin(
debugger, GetGlobalPluginProperties().GetValueProperties(),
- ConstString("Properties for the gdb-remote process plug-in."),
- is_global_setting);
+ "Properties for the gdb-remote process plug-in.", is_global_setting);
}
}
@@ -3393,7 +3435,7 @@ bool ProcessGDBRemote::StartAsyncThread() {
});
if (!async_thread) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Host), async_thread.takeError(),
- "failed to launch host thread: {}");
+ "failed to launch host thread: {0}");
return false;
}
m_async_thread = *async_thread;
@@ -3753,8 +3795,7 @@ ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) {
response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse) {
if (!response.Empty()) {
- object_sp =
- StructuredData::ParseJSON(std::string(response.GetStringRef()));
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
}
}
}
@@ -3786,10 +3827,8 @@ StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
StructuredData::ArraySP addresses(new StructuredData::Array);
- for (auto addr : load_addresses) {
- StructuredData::ObjectSP addr_sp(new StructuredData::Integer(addr));
- addresses->AddItem(addr_sp);
- }
+ for (auto addr : load_addresses)
+ addresses->AddIntegerItem(addr);
args_dict->GetAsDictionary()->AddItem("solib_addresses", addresses);
@@ -3825,8 +3864,7 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender(
response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse) {
if (!response.Empty()) {
- object_sp =
- StructuredData::ParseJSON(std::string(response.GetStringRef()));
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
}
}
}
@@ -3848,8 +3886,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetDynamicLoaderProcessState() {
response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse) {
if (!response.Empty()) {
- object_sp =
- StructuredData::ParseJSON(std::string(response.GetStringRef()));
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
}
}
}
@@ -3881,8 +3918,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
response.GetResponseType();
if (response_type == StringExtractorGDBRemote::eResponse) {
if (!response.Empty()) {
- object_sp =
- StructuredData::ParseJSON(std::string(response.GetStringRef()));
+ object_sp = StructuredData::ParseJSON(response.GetStringRef());
}
}
}
@@ -3891,7 +3927,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
}
Status ProcessGDBRemote::ConfigureStructuredData(
- ConstString type_name, const StructuredData::ObjectSP &config_sp) {
+ llvm::StringRef type_name, const StructuredData::ObjectSP &config_sp) {
return m_gdb_comm.ConfigureRemoteStructuredData(type_name, config_sp);
}
@@ -4033,15 +4069,212 @@ struct GdbServerTargetInfo {
RegisterSetMap reg_set_map;
};
-bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
- std::vector<DynamicRegisterInfo::Register> &registers) {
+static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node,
+ unsigned size) {
+ Log *log(GetLog(GDBRLog::Process));
+ const unsigned max_start_bit = size * 8 - 1;
+
+ // Process the fields of this set of flags.
+ std::vector<RegisterFlags::Field> fields;
+ flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit,
+ &log](const XMLNode
+ &field_node) {
+ std::optional<llvm::StringRef> name;
+ std::optional<unsigned> start;
+ std::optional<unsigned> end;
+
+ field_node.ForEachAttribute([&name, &start, &end, max_start_bit,
+ &log](const llvm::StringRef &attr_name,
+ const llvm::StringRef &attr_value) {
+ // Note that XML in general requires that each of these attributes only
+ // appears once, so we don't have to handle that here.
+ if (attr_name == "name") {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Found field node name \"{0}\"",
+ attr_value.data());
+ name = attr_value;
+ } else if (attr_name == "start") {
+ unsigned parsed_start = 0;
+ if (llvm::to_integer(attr_value, parsed_start)) {
+ if (parsed_start > max_start_bit) {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Invalid start {0} in field node, "
+ "cannot be > {1}",
+ parsed_start, max_start_bit);
+ } else
+ start = parsed_start;
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Invalid start \"{0}\" in "
+ "field node",
+ attr_value.data());
+ }
+ } else if (attr_name == "end") {
+ unsigned parsed_end = 0;
+ if (llvm::to_integer(attr_value, parsed_end))
+ if (parsed_end > max_start_bit) {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Invalid end {0} in field node, "
+ "cannot be > {1}",
+ parsed_end, max_start_bit);
+ } else
+ end = parsed_end;
+ else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Invalid end \"{0}\" in field node",
+ attr_value.data());
+ }
+ } else if (attr_name == "type") {
+ // Type is a known attribute but we do not currently use it and it is
+ // not required.
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Ignoring unknown attribute "
+ "\"{0}\" in field node",
+ attr_name.data());
+ }
+
+ return true; // Walk all attributes of the field.
+ });
+
+ if (name && start && end) {
+ if (*start > *end) {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Start {0} > end {1} in field "
+ "\"{2}\", ignoring",
+ *start, *end, name->data());
+ } else {
+ fields.push_back(RegisterFlags::Field(name->str(), *start, *end));
+ }
+ }
+
+ return true; // Iterate all "field" nodes.
+ });
+ return fields;
+}
+
+void ParseFlags(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ feature_node.ForEachChildElementWithName(
+ "flags",
+ [&log, &registers_flags_types](const XMLNode &flags_node) -> bool {
+ LLDB_LOG(log, "ProcessGDBRemote::ParseFlags Found flags node \"{0}\"",
+ flags_node.GetAttributeValue("id").c_str());
+
+ std::optional<llvm::StringRef> id;
+ std::optional<unsigned> size;
+ flags_node.ForEachAttribute(
+ [&id, &size, &log](const llvm::StringRef &name,
+ const llvm::StringRef &value) {
+ if (name == "id") {
+ id = value;
+ } else if (name == "size") {
+ unsigned parsed_size = 0;
+ if (llvm::to_integer(value, parsed_size))
+ size = parsed_size;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Invalid size \"{0}\" "
+ "in flags node",
+ value.data());
+ }
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseFlags Ignoring unknown "
+ "attribute \"{0}\" in flags node",
+ name.data());
+ }
+ return true; // Walk all attributes.
+ });
+
+ if (id && size) {
+ // Process the fields of this set of flags.
+ std::vector<RegisterFlags::Field> fields =
+ ParseFlagsFields(flags_node, *size);
+ if (fields.size()) {
+ // Sort so that the fields with the MSBs are first.
+ std::sort(fields.rbegin(), fields.rend());
+ std::vector<RegisterFlags::Field>::const_iterator overlap =
+ std::adjacent_find(fields.begin(), fields.end(),
+ [](const RegisterFlags::Field &lhs,
+ const RegisterFlags::Field &rhs) {
+ return lhs.Overlaps(rhs);
+ });
+
+ // If no fields overlap, use them.
+ if (overlap == fields.end()) {
+ if (registers_flags_types.contains(*id)) {
+ // In theory you could define some flag set, use it with a
+ // register then redefine it. We do not know if anyone does
+ // that, or what they would expect to happen in that case.
+ //
+ // LLDB chooses to take the first definition and ignore the rest
+ // as waiting until everything has been processed is more
+ // expensive and difficult. This means that pointers to flag
+ // sets in the register info remain valid if later the flag set
+ // is redefined. If we allowed redefinitions, LLDB would crash
+ // when you tried to print a register that used the original
+ // definition.
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Definition of flags "
+ "\"{0}\" shadows "
+ "previous definition, using original definition instead.",
+ id->data());
+ } else {
+ registers_flags_types.insert_or_assign(
+ *id, std::make_unique<RegisterFlags>(id->str(), *size,
+ std::move(fields)));
+ }
+ } else {
+ // If any fields overlap, ignore the whole set of flags.
+ std::vector<RegisterFlags::Field>::const_iterator next =
+ std::next(overlap);
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Ignoring flags because fields "
+ "{0} (start: {1} end: {2}) and {3} (start: {4} end: {5}) "
+ "overlap.",
+ overlap->GetName().c_str(), overlap->GetStart(),
+ overlap->GetEnd(), next->GetName().c_str(), next->GetStart(),
+ next->GetEnd());
+ }
+ } else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlags Ignoring definition of flags "
+ "\"{0}\" because it contains no fields.",
+ id->data());
+ }
+ }
+
+ return true; // Keep iterating through all "flags" elements.
+ });
+}
+
+bool ParseRegisters(
+ XMLNode feature_node, GdbServerTargetInfo &target_info,
+ std::vector<DynamicRegisterInfo::Register> &registers,
+ llvm::StringMap<std::unique_ptr<RegisterFlags>> &registers_flags_types) {
if (!feature_node)
return false;
Log *log(GetLog(GDBRLog::Process));
+ ParseFlags(feature_node, registers_flags_types);
+ for (const auto &flags : registers_flags_types)
+ flags.second->log(log);
+
feature_node.ForEachChildElementWithName(
- "reg", [&target_info, &registers, log](const XMLNode &reg_node) -> bool {
+ "reg",
+ [&target_info, &registers, &registers_flags_types,
+ log](const XMLNode &reg_node) -> bool {
std::string gdb_group;
std::string gdb_type;
DynamicRegisterInfo::Register reg_info;
@@ -4117,29 +4350,51 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info,
return true; // Keep iterating through all attributes
});
- if (!gdb_type.empty() && !(encoding_set || format_set)) {
- if (llvm::StringRef(gdb_type).startswith("int")) {
- reg_info.format = eFormatHex;
- reg_info.encoding = eEncodingUint;
- } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") {
- reg_info.format = eFormatAddressInfo;
- reg_info.encoding = eEncodingUint;
- } else if (gdb_type == "float") {
- reg_info.format = eFormatFloat;
- reg_info.encoding = eEncodingIEEE754;
- } else if (gdb_type == "aarch64v" ||
- llvm::StringRef(gdb_type).startswith("vec") ||
- gdb_type == "i387_ext" || gdb_type == "uint128") {
- // lldb doesn't handle 128-bit uints correctly (for ymm*h), so treat
- // them as vector (similarly to xmm/ymm)
- reg_info.format = eFormatVectorOfUInt8;
- reg_info.encoding = eEncodingVector;
- } else {
- LLDB_LOGF(
- log,
- "ProcessGDBRemote::ParseRegisters Could not determine lldb"
- "format and encoding for gdb type %s",
- gdb_type.c_str());
+ if (!gdb_type.empty()) {
+ // gdb_type could reference some flags type defined in XML.
+ llvm::StringMap<std::unique_ptr<RegisterFlags>>::iterator it =
+ registers_flags_types.find(gdb_type);
+ if (it != registers_flags_types.end()) {
+ auto flags_type = it->second.get();
+ if (reg_info.byte_size == flags_type->GetSize())
+ reg_info.flags_type = flags_type;
+ else
+ LLDB_LOGF(log,
+ "ProcessGDBRemote::ParseRegisters Size of register "
+ "flags %s (%d bytes) for "
+ "register %s does not match the register size (%d "
+ "bytes). Ignoring this set of flags.",
+ flags_type->GetID().c_str(), flags_type->GetSize(),
+ reg_info.name.AsCString(), reg_info.byte_size);
+ }
+
+ // There's a slim chance that the gdb_type name is both a flags type
+ // and a simple type. Just in case, look for that too (setting both
+ // does no harm).
+ if (!gdb_type.empty() && !(encoding_set || format_set)) {
+ if (llvm::StringRef(gdb_type).startswith("int")) {
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") {
+ reg_info.format = eFormatAddressInfo;
+ reg_info.encoding = eEncodingUint;
+ } else if (gdb_type == "float") {
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ } else if (gdb_type == "aarch64v" ||
+ llvm::StringRef(gdb_type).startswith("vec") ||
+ gdb_type == "i387_ext" || gdb_type == "uint128") {
+ // lldb doesn't handle 128-bit uints correctly (for ymm*h), so
+ // treat them as vector (similarly to xmm/ymm)
+ reg_info.format = eFormatVectorOfUInt8;
+ reg_info.encoding = eEncodingVector;
+ } else {
+ LLDB_LOGF(
+ log,
+ "ProcessGDBRemote::ParseRegisters Could not determine lldb"
+ "format and encoding for gdb type %s",
+ gdb_type.c_str());
+ }
}
}
@@ -4271,8 +4526,8 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
if (arch_to_use.IsValid()) {
for (auto &feature_node : feature_nodes) {
- ParseRegisters(feature_node, target_info,
- registers);
+ ParseRegisters(feature_node, target_info, registers,
+ m_registers_flags_types);
}
for (const auto &include : target_info.includes) {
@@ -4337,6 +4592,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
if (!m_gdb_comm.GetQXferFeaturesReadSupported())
return false;
+ // This holds register flags information for the whole of target.xml.
+ // target.xml may include further documents that
+ // GetGDBServerRegisterInfoXMLAndProcess will recurse to fetch and process.
+ // That's why we clear the cache here, and not in
+ // GetGDBServerRegisterInfoXMLAndProcess. To prevent it being cleared on every
+ // include read.
+ m_registers_flags_types.clear();
std::vector<DynamicRegisterInfo::Register> registers;
if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
registers))
@@ -4844,8 +5106,7 @@ ParseStructuredDataPacket(llvm::StringRef packet) {
}
// This is an asynchronous JSON packet, destined for a StructuredDataPlugin.
- StructuredData::ObjectSP json_sp =
- StructuredData::ParseJSON(std::string(packet));
+ StructuredData::ObjectSP json_sp = StructuredData::ParseJSON(packet);
if (log) {
if (json_sp) {
StreamString json_str;
@@ -4961,7 +5222,7 @@ public:
ProcessGDBRemote *process =
(ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
if (process) {
- process->GetGDBRemote().DumpHistory(result.GetOutputStream());
+ process->DumpPluginHistory(result.GetOutputStream());
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}