[Lldb-commits] [lldb] [llvm] [lldb] Support register vector and union types (draft, no not commit!) (PR #196032)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Wed May 6 02:23:19 PDT 2026
https://github.com/DavidSpickett created https://github.com/llvm/llvm-project/pull/196032
Part of work for https://github.com/llvm/llvm-project/issues/87471.
This is a WIP branch so we can compare and contrast with https://github.com/llvm/llvm-project/pull/195887.
The main changes are, in this order:
* Fix the "hack" that reverses field order for `flags` (should eventually be done by https://github.com/llvm/llvm-project/pull/189590).
* Add a base class for all register types created from XML.
* Parse and generate `union` types from XML.
* Parse and generate `vector` types from XML.
* Add some random types to existing registers for demo purposes.
My original intent was to solve the first bit and then upstream the rest but with interest in this feature from others, I think we can probably do some of this out of order and use the code from the other author's PR for parts of it.
>From a99f275254f1a6f124339a9d35a741c1f4c4935a Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Fri, 27 Mar 2026 11:23:50 +0000
Subject: [PATCH 01/16] [lldb] Override default struct layout when building
register types
When printing register "flags" types (basically C bitfield structs),
we have 2 goals:
1. Extract the values (the fields) correctly.
2. Display the fields in most significant to least significant order
(to match architecture manuals).
Currently LLDB achieves these by:
* Putting the most significant field as the first member of the
struct type. Though we know it is the MSB, it will in fact be
put at bit 0 by Clang.
* To compensate for that, we reverse the order of the fields
within the register value. If the original was [a][b][c],
we change that to [c][b][a].
This works when the only type we have is "flags" aka a bitfield
struct. I have been trying to implement "union" types (which act like C unions),
and found that this method is not compatible with "union".
Consider a union of two sets of flags:
```
some_union
|
-> big_little: wwww_wwww_wwww_wwww_wwww_xxxx_xxxx_xxxx
-> little_big: yyyy_yyyy_yyyy_zzzz_zzzz_zzzz_zzzz_zzzz
```
w is bigger than x, and y is smaller than z. Therefore these two
bitfield structs have different layouts.
We cannot modify the value using both field layouts, we must pick one.
Whichever one we pick results in us displaying the other one
incorrectly because it has a different layouts.
In other words: the current method only works when there is 1,
and only one, field layout. For unions, this is not true.
We need to achieve goals 1 and 2 without relying on details of
the register's type.
The first method I prototyped was to build the struct types in reverse
(so field values are correct), then print them in reverse with a Synthetic
Child Provider (so the display order is correct).
This works but it has the small downside that the underlying type
would be backwards if a user were to inspect it. This is not possible
today but eventually I want to allow register types in expressions,
and with that you could make use of the underlying type.
Users are very unlikely to do this, but I wondered if it was a sign
that I was pursuing a half baked solution.
This PR implements an alternative. The types are still built with the
most significant field first, so they are visually correct even if the
raw type is printed.
Then an ExternalASTSource is used to tell Clang to lay out the struct
in an MSB to LSB order. This means the fields will have correct values.
This method will work for unions because the only change we have to
make to the register value is an endian swap in some cases. This endian
swap does not rely on any type information, all it needs is the size
of the register.
This method will not result in any user visible changes at this time.
What it does is fix a fundemental issue blocking the implementation
of "union", and later "vector" (see https://github.com/llvm/llvm-project/issues/87471).
I also think that this method is much cleaner and easier to explain
than my previous attempt. So it is worth switching to it regardless
of future plans.
---
lldb/include/lldb/Target/RegisterFlags.h | 22 ---------
lldb/source/Core/DumpRegisterValue.cpp | 16 ++----
.../RegisterTypeBuilderClang.cpp | 19 +++++--
.../RegisterTypeBuilderClang.h | 49 +++++++++++++++++++
.../TypeSystem/Clang/TypeSystemClang.cpp | 4 ++
.../TypeSystem/Clang/TypeSystemClang.h | 5 +-
lldb/unittests/Target/RegisterFlagsTest.cpp | 21 --------
7 files changed, 76 insertions(+), 60 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterFlags.h b/lldb/include/lldb/Target/RegisterFlags.h
index 1250fd0330958..f2d3ea0d43e4d 100644
--- a/lldb/include/lldb/Target/RegisterFlags.h
+++ b/lldb/include/lldb/Target/RegisterFlags.h
@@ -86,11 +86,6 @@ class RegisterFlags {
/// Identical to GetMaxValue but for the GDB client to use.
static uint64_t GetMaxValue(unsigned start, unsigned end);
- /// Extract value of the field from a whole register value.
- uint64_t GetValue(uint64_t register_value) const {
- return (register_value & GetMask()) >> m_start;
- }
-
const std::string &GetName() const { return m_name; }
unsigned GetStart() const { return m_start; }
unsigned GetEnd() const { return m_end; }
@@ -145,23 +140,6 @@ class RegisterFlags {
/// enum values, and lists what those values are.
std::string DumpEnums(uint32_t max_width) const;
- // Reverse the order of the fields, keeping their values the same.
- // For example a field from bit 31 to 30 with value 0b10 will become bits
- // 1 to 0, with the same 0b10 value.
- // Use this when you are going to show the register using a bitfield struct
- // type. If that struct expects MSB first and you are on little endian where
- // LSB would be first, this corrects that (and vice versa for big endian).
- template <typename T> T ReverseFieldOrder(T value) const {
- T ret = 0;
- unsigned shift = 0;
- for (auto field : GetFields()) {
- ret |= field.GetValue(value) << shift;
- shift += field.GetSizeInBits();
- }
-
- return ret;
- }
-
const std::vector<Field> &GetFields() const { return m_fields; }
const std::string &GetID() const { return m_id; }
unsigned GetSize() const { return m_size; }
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index aff4d2c621d7e..b12e3821ea9b2 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -28,21 +28,13 @@ static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
lldb_private::Stream &strm) {
lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder();
- // For the bitfield types we generate, it is expected that the fields are
- // in what is usually a big endian order. Most significant field first.
- // This is also clang's internal ordering and the order we want to print
- // them. On a big endian host this all matches up, for a little endian
- // host we have to swap the order of the fields before display.
- if (target_order == lldb::ByteOrder::eByteOrderLittle) {
- value = reg_info.flags_type->ReverseFieldOrder(value);
- }
-
- // Then we need to match the target's endian on a byte level as well.
+ // The type will be rendered in the target's type system, so it must match
+ // its endian.
if (lldb_private::endian::InlHostByteOrder() != target_order)
value = llvm::byteswap(value);
- lldb_private::DataExtractor data_extractor{
- &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8};
+ lldb_private::DataExtractor data_extractor{&value, sizeof(T), target_order,
+ 8};
lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create(
exe_scope, fields_type, lldb_private::ConstString(), data_extractor);
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index 80d5289178ed0..e809973766604 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -38,10 +38,15 @@ RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
CompilerType RegisterTypeBuilderClang::GetRegisterType(
const std::string &name, const lldb_private::RegisterFlags &flags,
uint32_t byte_size) {
- lldb::TypeSystemClangSP type_system =
- ScratchTypeSystemClang::GetForTarget(m_target);
+ lldb::TypeSystemClangSP type_system = ScratchTypeSystemClang::GetForTarget(
+ m_target, ScratchTypeSystemClang::IsolatedASTKind::Registers);
assert(type_system);
+ if (!m_external_ast) {
+ m_external_ast = llvm::makeIntrusiveRefCnt<RegisterExternalASTSource>();
+ type_system->SetExternalSource(m_external_ast);
+ }
+
std::string register_type_name = "__lldb_register_fields_" + name;
// See if we have made this type before and can reuse it.
CompilerType fields_type =
@@ -60,6 +65,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
nullptr, OptionalClangModuleID(), register_type_name,
llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
type_system->StartTagDeclarationDefinition(fields_type);
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
// We assume that RegisterFlags has padded and sorted the fields
// already.
@@ -104,10 +110,15 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
}
}
- type_system->AddFieldToRecordType(fields_type, field.GetName(),
- field_type, field.GetSizeInBits());
+ clang::FieldDecl *field_decl = type_system->AddFieldToRecordType(
+ fields_type, field.GetName(), field_type, field.GetSizeInBits());
+ field_offsets.insert({field_decl, field.GetStart()});
}
+ m_external_ast->m_struct_layouts.insert(
+ {type_system->GetAsRecordDecl(fields_type),
+ RegisterExternalASTSource::LayoutInfo{byte_size, field_offsets}});
+
type_system->CompleteTagDeclarationDefinition(fields_type);
// So that the size of the type matches the size of the register.
type_system->SetIsPacked(fields_type);
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index 611e2e60436ec..d346f79acceb8 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -9,6 +9,8 @@
#ifndef LLDB_SOURCE_PLUGINS_REGISTERTYPEBUILDER_REGISTERTYPEBUILDERCLANG_H
#define LLDB_SOURCE_PLUGINS_REGISTERTYPEBUILDER_REGISTERTYPEBUILDERCLANG_H
+#include "clang/AST/ExternalASTSource.h"
+
#include "lldb/Target/RegisterTypeBuilder.h"
#include "lldb/Target/Target.h"
@@ -33,6 +35,53 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
uint32_t byte_size) override;
private:
+ /// This external AST is used to override the layout of bitfield structs
+ /// created from sets of register "flags".
+ ///
+ /// We have two goals with register display:
+ /// 1. Most significant to least significant display order, to match
+ /// architecure
+ /// manuals.
+ /// 2. Correctly extracting field values.
+ ///
+ /// Goal 1 is achieved by building the struct with the most significant field
+ /// as the first member and the least significant as the last member.
+ ///
+ /// The default bit position of those fields is that the first member is bit
+ /// 0, and the last is bit N. This is LSB to MSB, so the replacement layouts
+ /// in this external AST reverse that to be MSB to LSB. This achieves goal 2.
+ class RegisterExternalASTSource : public clang::ExternalASTSource {
+ public:
+ struct LayoutInfo {
+ uint64_t size_bytes = 0;
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+ };
+ llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> m_struct_layouts;
+
+ bool layoutRecordType(
+ const clang::RecordDecl *record, uint64_t &size, uint64_t &align,
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &base_offsets,
+ llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+ &vbase_offsets) override {
+ auto it = m_struct_layouts.find(record);
+ if (it == m_struct_layouts.end())
+ return false;
+
+ size = it->second.size_bytes * 8;
+ align = size;
+ field_offsets = it->second.field_offsets;
+ base_offsets.clear();
+ vbase_offsets.clear();
+ return true;
+ }
+ };
+
+ // This is created the first time a register type is requested, then handed
+ // to the type system. We keep a reference to it so we can add more layouts
+ // as more register types are requested.
+ llvm::IntrusiveRefCntPtr<RegisterExternalASTSource> m_external_ast;
Target &m_target;
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 62c3742652537..5886616262612 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9631,6 +9631,8 @@ GetNameForIsolatedASTKind(ScratchTypeSystemClang::IsolatedASTKind kind) {
switch (kind) {
case ScratchTypeSystemClang::IsolatedASTKind::CppModules:
return "C++ modules";
+ case ScratchTypeSystemClang::IsolatedASTKind::Registers:
+ return "Registers";
}
llvm_unreachable("Unimplemented IsolatedASTKind?");
}
@@ -9722,6 +9724,8 @@ GetSpecializedASTName(ScratchTypeSystemClang::IsolatedASTKind feature) {
switch (feature) {
case ScratchTypeSystemClang::IsolatedASTKind::CppModules:
return "scratch ASTContext for C++ module types";
+ case ScratchTypeSystemClang::IsolatedASTKind::Registers:
+ return "scratch ASContext for register types";
}
llvm_unreachable("Unimplemented ASTFeature kind?");
}
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
index 59805085873fe..21f0961610223 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h
@@ -1274,7 +1274,10 @@ class ScratchTypeSystemClang : public TypeSystemClang {
/// type information from a C++ module. The templates from a C++ module
/// often conflict with the templates we generate from debug information,
/// so we put these types in their own AST.
- CppModules
+ CppModules,
+ /// Register "flags" types are converted into structures but their layout
+ /// does not follow the ABI of the target.
+ Registers
};
/// Alias for requesting the default scratch TypeSystemClang in GetForTarget.
diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterFlagsTest.cpp
index ecffdd0fe44e6..003ed9bbf0ae0 100644
--- a/lldb/unittests/Target/RegisterFlagsTest.cpp
+++ b/lldb/unittests/Target/RegisterFlagsTest.cpp
@@ -22,24 +22,18 @@ TEST(RegisterFlagsTest, Field) {
// start == end means a 1 bit field.
ASSERT_EQ(f1.GetSizeInBits(), (unsigned)1);
ASSERT_EQ(f1.GetMask(), (uint64_t)1);
- ASSERT_EQ(f1.GetValue(0), (uint64_t)0);
- ASSERT_EQ(f1.GetValue(3), (uint64_t)1);
// End is inclusive meaning that start 0 to end 1 includes bit 1
// to make a 2 bit field.
RegisterFlags::Field f2("", 0, 1);
ASSERT_EQ(f2.GetSizeInBits(), (unsigned)2);
ASSERT_EQ(f2.GetMask(), (uint64_t)3);
- ASSERT_EQ(f2.GetValue(UINT64_MAX), (uint64_t)3);
- ASSERT_EQ(f2.GetValue(UINT64_MAX & ~(uint64_t)3), (uint64_t)0);
// If the field doesn't start at 0 we need to shift up/down
// to account for it.
RegisterFlags::Field f3("", 2, 5);
ASSERT_EQ(f3.GetSizeInBits(), (unsigned)4);
ASSERT_EQ(f3.GetMask(), (uint64_t)0x3c);
- ASSERT_EQ(f3.GetValue(UINT64_MAX), (uint64_t)0xf);
- ASSERT_EQ(f3.GetValue(UINT64_MAX & ~(uint64_t)0x3c), (uint64_t)0);
// Fields are sorted lowest starting bit first.
ASSERT_TRUE(f2 < f3);
@@ -127,21 +121,6 @@ TEST(RegisterFlagsTest, RegisterFlagsPadding) {
make_field(0, 7)});
}
-TEST(RegisterFieldsTest, ReverseFieldOrder) {
- // Unchanged
- RegisterFlags rf("", 4, {make_field(0, 31)});
- ASSERT_EQ(0x12345678ULL, (unsigned long long)rf.ReverseFieldOrder(0x12345678));
-
- // Swap the two halves around.
- RegisterFlags rf2("", 4, {make_field(16, 31), make_field(0, 15)});
- ASSERT_EQ(0x56781234ULL, (unsigned long long)rf2.ReverseFieldOrder(0x12345678));
-
- // Many small fields.
- RegisterFlags rf3(
- "", 4, {make_field(31), make_field(30), make_field(29), make_field(28)});
- ASSERT_EQ(0x00000005ULL, rf3.ReverseFieldOrder(0xA0000000));
-}
-
TEST(RegisterFlagsTest, AsTable) {
// Anonymous fields are shown with an empty name cell,
// whether they are known up front or added during construction.
>From 8bf81eef1fdac910b5697d6d5d2995e64452b192 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Mon, 30 Mar 2026 13:49:19 +0000
Subject: [PATCH 02/16] [lldb] Do not add padding fields to RegisterFlags
We used to rely on Clang to decide the layout of the struct types
that we built using RegisterFlags. Now we supply an external layout.
This means we do not need the anonyous padding fields.
We still need to know about these gaps when printing "register info"
tables, so I have basically moved the padding logic into there.
---
.../DataFormatters/DumpValueObjectOptions.h | 5 -
lldb/include/lldb/Target/RegisterFlags.h | 2 +-
lldb/source/Core/DumpRegisterValue.cpp | 7 +-
.../DataFormatters/DumpValueObjectOptions.cpp | 8 +-
.../DataFormatters/ValueObjectPrinter.cpp | 6 -
lldb/source/Target/RegisterFlags.cpp | 131 ++++++++----------
.../gdb_remote_client/TestXMLRegisterFlags.py | 2 +-
lldb/unittests/Target/RegisterFlagsTest.cpp | 45 +-----
8 files changed, 65 insertions(+), 141 deletions(-)
diff --git a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
index 70166f33cfc45..4d5249dd26665 100644
--- a/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
+++ b/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
@@ -52,8 +52,6 @@ class DumpValueObjectOptions {
const DumpValueObjectOptions &, Stream &)>
DeclPrintingHelper;
- typedef std::function<bool(ConstString)> ChildPrintingDecider;
-
static const DumpValueObjectOptions DefaultOptions() {
static DumpValueObjectOptions g_default_options;
@@ -70,8 +68,6 @@ class DumpValueObjectOptions {
DumpValueObjectOptions &SetDeclPrintingHelper(DeclPrintingHelper helper);
- DumpValueObjectOptions &SetChildPrintingDecider(ChildPrintingDecider decider);
-
DumpValueObjectOptions &SetShowTypes(bool show = false);
DumpValueObjectOptions &SetShowLocation(bool show = false);
@@ -142,7 +138,6 @@ class DumpValueObjectOptions {
lldb::LanguageType m_varformat_language = lldb::eLanguageTypeUnknown;
PointerDepth m_max_ptr_depth;
DeclPrintingHelper m_decl_printing_helper;
- ChildPrintingDecider m_child_printing_decider;
PointerAsArraySettings m_pointer_as_array;
unsigned m_expand_ptr_type_flags = 0;
// The following flags commonly default to false.
diff --git a/lldb/include/lldb/Target/RegisterFlags.h b/lldb/include/lldb/Target/RegisterFlags.h
index f2d3ea0d43e4d..44356decaa6bf 100644
--- a/lldb/include/lldb/Target/RegisterFlags.h
+++ b/lldb/include/lldb/Target/RegisterFlags.h
@@ -127,7 +127,7 @@ class RegisterFlags {
/// This assumes that:
/// * There is at least one field.
/// * The fields are sorted in descending order.
- /// Gaps are allowed, they will be filled with anonymous padding fields.
+ /// Gaps are allowed.
RegisterFlags(std::string id, unsigned size,
const std::vector<Field> &fields);
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index b12e3821ea9b2..37ce1496131fe 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -39,12 +39,7 @@ static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create(
exe_scope, fields_type, lldb_private::ConstString(), data_extractor);
lldb_private::DumpValueObjectOptions dump_options;
- lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider =
- [](lldb_private::ConstString varname) {
- // Unnamed bit-fields are padding that we don't want to show.
- return varname.GetLength();
- };
- dump_options.SetChildPrintingDecider(decider).SetHideRootType(true);
+ dump_options.SetHideRootType(true);
if (llvm::Error error = vobj_sp->Dump(strm, dump_options))
strm << "error: " << toString(std::move(error));
diff --git a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
index e1df9522256fa..3ba4a4ab3f9f5 100644
--- a/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
+++ b/lldb/source/DataFormatters/DumpValueObjectOptions.cpp
@@ -15,7 +15,7 @@ using namespace lldb_private;
DumpValueObjectOptions::DumpValueObjectOptions()
: m_summary_sp(), m_root_valobj_name(), m_decl_printing_helper(),
- m_child_printing_decider(), m_pointer_as_array(), m_use_synthetic(true),
+ m_pointer_as_array(), m_use_synthetic(true),
m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
m_show_types(false), m_show_location(false), m_use_object_desc(false),
m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
@@ -49,12 +49,6 @@ DumpValueObjectOptions::SetDeclPrintingHelper(DeclPrintingHelper helper) {
return *this;
}
-DumpValueObjectOptions &
-DumpValueObjectOptions::SetChildPrintingDecider(ChildPrintingDecider decider) {
- m_child_printing_decider = decider;
- return *this;
-}
-
DumpValueObjectOptions &DumpValueObjectOptions::SetShowTypes(bool show) {
m_show_types = show;
return *this;
diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
index 002638024c64b..e1b88135bc5b4 100644
--- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -729,9 +729,6 @@ void ValueObjectPrinter::PrintChildren(
for (size_t idx = 0; idx < num_children; ++idx) {
if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) {
- if (m_options.m_child_printing_decider &&
- !m_options.m_child_printing_decider(child_sp->GetName()))
- continue;
if (!any_children_printed) {
PrintChildrenPreamble(value_printed, summary_printed);
any_children_printed = true;
@@ -789,9 +786,6 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {
child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
m_options.m_use_dynamic, m_options.m_use_synthetic);
if (child_sp) {
- if (m_options.m_child_printing_decider &&
- !m_options.m_child_printing_decider(child_sp->GetName()))
- continue;
if (idx && did_print_children)
m_stream->PutCString(", ");
did_print_children = true;
diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterFlags.cpp
index 976e03870ad9e..f070e8896b9ee 100644
--- a/lldb/source/Target/RegisterFlags.cpp
+++ b/lldb/source/Target/RegisterFlags.cpp
@@ -110,40 +110,7 @@ uint64_t RegisterFlags::Field::GetMask() const {
void RegisterFlags::SetFields(const std::vector<Field> &fields) {
// We expect that these are unsorted but do not overlap.
// They could fill the register but may have gaps.
- std::vector<Field> provided_fields = fields;
-
- m_fields.clear();
- m_fields.reserve(provided_fields.size());
-
- // ProcessGDBRemote should have sorted these in descending order already.
- assert(std::is_sorted(provided_fields.rbegin(), provided_fields.rend()));
-
- // Build a new list of fields that includes anonymous (empty name) fields
- // wherever there is a gap. This will simplify processing later.
- std::optional<Field> previous_field;
- unsigned register_msb = (m_size * 8) - 1;
- for (auto field : provided_fields) {
- if (previous_field) {
- unsigned padding = previous_field->PaddingDistance(field);
- if (padding) {
- // -1 to end just before the previous field.
- unsigned end = previous_field->GetStart() - 1;
- // +1 because if you want to pad 1 bit you want to start and end
- // on the same bit.
- m_fields.push_back(Field("", field.GetEnd() + 1, end));
- }
- } else {
- // This is the first field. Check that it starts at the register's MSB.
- if (field.GetEnd() != register_msb)
- m_fields.push_back(Field("", field.GetEnd() + 1, register_msb));
- }
- m_fields.push_back(field);
- previous_field = field;
- }
-
- // The last field may not extend all the way to bit 0.
- if (previous_field && previous_field->GetStart() != 0)
- m_fields.push_back(Field("", 0, previous_field->GetStart() - 1));
+ m_fields = fields;
}
RegisterFlags::RegisterFlags(std::string id, unsigned size,
@@ -185,54 +152,76 @@ static void EmitTable(std::string &out, std::array<std::string, 3> &table) {
});
}
+static void EmitField(const RegisterFlags::Field &field, uint32_t max_width,
+ uint32_t ¤t_width, std::string &table,
+ std::array<std::string, 3> &lines) {
+ StreamString position;
+ if (field.GetEnd() == field.GetStart())
+ position.Printf(" %d ", field.GetEnd());
+ else
+ position.Printf(" %d-%d ", field.GetEnd(), field.GetStart());
+
+ StreamString name;
+ name.Printf(" %s ", field.GetName().c_str());
+
+ unsigned column_width = position.GetString().size();
+ unsigned name_width = name.GetString().size();
+ if (name_width > column_width)
+ column_width = name_width;
+
+ // If the next column would overflow and we have already formatted at least
+ // one column, put out what we have and move to a new table on the next line
+ // (+1 here because we need to cap the ends with '|'). If this is the first
+ // column, just let it overflow and we'll wrap next time around. There's not
+ // much we can do with a very small terminal.
+ if (current_width && ((current_width + column_width + 1) >= max_width)) {
+ EmitTable(table, lines);
+ // Blank line between each.
+ table += "\n\n";
+
+ for (std::string &line : lines)
+ line.clear();
+ current_width = 0;
+ }
+
+ StreamString aligned_position = FormatCell(position, column_width);
+ lines[0] += aligned_position.GetString();
+ StreamString grid;
+ grid << '|' << std::string(column_width, '-');
+ lines[1] += grid.GetString();
+ StreamString aligned_name = FormatCell(name, column_width);
+ lines[2] += aligned_name.GetString();
+
+ // +1 for the left side '|'.
+ current_width += column_width + 1;
+}
+
std::string RegisterFlags::AsTable(uint32_t max_width) const {
std::string table;
// position / gridline / name
std::array<std::string, 3> lines;
uint32_t current_width = 0;
+ std::optional<RegisterFlags::Field> previous_field = std::nullopt;
for (const RegisterFlags::Field &field : m_fields) {
- StreamString position;
- if (field.GetEnd() == field.GetStart())
- position.Printf(" %d ", field.GetEnd());
- else
- position.Printf(" %d-%d ", field.GetEnd(), field.GetStart());
-
- StreamString name;
- name.Printf(" %s ", field.GetName().c_str());
-
- unsigned column_width = position.GetString().size();
- unsigned name_width = name.GetString().size();
- if (name_width > column_width)
- column_width = name_width;
-
- // If the next column would overflow and we have already formatted at least
- // one column, put out what we have and move to a new table on the next line
- // (+1 here because we need to cap the ends with '|'). If this is the first
- // column, just let it overflow and we'll wrap next time around. There's not
- // much we can do with a very small terminal.
- if (current_width && ((current_width + column_width + 1) >= max_width)) {
- EmitTable(table, lines);
- // Blank line between each.
- table += "\n\n";
-
- for (std::string &line : lines)
- line.clear();
- current_width = 0;
+ if (previous_field) {
+ // If there is a gap between this field and the last, fill it with an
+ // anonymous field.
+ if (previous_field->PaddingDistance(field))
+ EmitField(RegisterFlags::Field("", field.GetEnd() + 1,
+ previous_field->GetStart() - 1),
+ max_width, current_width, table, lines);
}
- StreamString aligned_position = FormatCell(position, column_width);
- lines[0] += aligned_position.GetString();
- StreamString grid;
- grid << '|' << std::string(column_width, '-');
- lines[1] += grid.GetString();
- StreamString aligned_name = FormatCell(name, column_width);
- lines[2] += aligned_name.GetString();
-
- // +1 for the left side '|'.
- current_width += column_width + 1;
+ EmitField(field, max_width, current_width, table, lines);
+ previous_field = field;
}
+ // If the last field did not extend to bit 0, pad down to bit 0.
+ if (previous_field && previous_field->GetStart() != 0)
+ EmitField(RegisterFlags::Field("", 0, previous_field->GetStart() - 1),
+ max_width, current_width, table, lines);
+
// If we didn't overflow and still have table to print out.
if (lines[0].size())
EmitTable(table, lines);
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
index 1d0fd00ede3f0..cfd0bd638a1f8 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
@@ -464,7 +464,7 @@ def test_flags_multiple_lines(self):
@skipIfRemote
def test_flags_child_limit(self):
# Flags print like C types so they should follow the child limit setting.
- self.runCmd("settings set target.max-children-count 3")
+ self.runCmd("settings set target.max-children-count 2")
self.setup_flags_test(
'<field name="field_0" start="0" end="0"/>'
'<field name="field_1" start="1" end="1"/>'
diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterFlagsTest.cpp
index 003ed9bbf0ae0..188a723113878 100644
--- a/lldb/unittests/Target/RegisterFlagsTest.cpp
+++ b/lldb/unittests/Target/RegisterFlagsTest.cpp
@@ -79,51 +79,8 @@ TEST(RegisterFlagsTest, PaddingDistance) {
ASSERT_EQ(make_field(31, 31).PaddingDistance(make_field(0)), 30ULL);
}
-static void test_padding(const std::vector<RegisterFlags::Field> &fields,
- const std::vector<RegisterFlags::Field> &expected) {
- RegisterFlags rf("", 4, fields);
- EXPECT_THAT(expected, ::testing::ContainerEq(rf.GetFields()));
-}
-
-TEST(RegisterFlagsTest, RegisterFlagsPadding) {
- // When creating a set of flags we assume that:
- // * There are >= 1 fields.
- // * They are sorted in descending order.
- // * There may be gaps between each field.
-
- // Needs no padding
- auto fields =
- std::vector<RegisterFlags::Field>{make_field(16, 31), make_field(0, 15)};
- test_padding(fields, fields);
-
- // Needs padding in between the fields, single bit.
- test_padding({make_field(17, 31), make_field(0, 15)},
- {make_field(17, 31), make_field(16), make_field(0, 15)});
- // Multiple bits of padding.
- test_padding({make_field(17, 31), make_field(0, 14)},
- {make_field(17, 31), make_field(15, 16), make_field(0, 14)});
-
- // Padding before first field, single bit.
- test_padding({make_field(0, 30)}, {make_field(31), make_field(0, 30)});
- // Multiple bits.
- test_padding({make_field(0, 15)}, {make_field(16, 31), make_field(0, 15)});
-
- // Padding after last field, single bit.
- test_padding({make_field(1, 31)}, {make_field(1, 31), make_field(0)});
- // Multiple bits.
- test_padding({make_field(2, 31)}, {make_field(2, 31), make_field(0, 1)});
-
- // Fields need padding before, in between and after.
- // [31-28][field 27-24][23-22][field 21-20][19-12][field 11-8][7-0]
- test_padding({make_field(24, 27), make_field(20, 21), make_field(8, 11)},
- {make_field(28, 31), make_field(24, 27), make_field(22, 23),
- make_field(20, 21), make_field(12, 19), make_field(8, 11),
- make_field(0, 7)});
-}
-
TEST(RegisterFlagsTest, AsTable) {
- // Anonymous fields are shown with an empty name cell,
- // whether they are known up front or added during construction.
+ // Anonymous fields are shown with an empty name cell.
RegisterFlags anon_field("", 4, {make_field(0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
>From aa71f16542414ead9509d8f85cf285ea12af76d7 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Mon, 2 Sep 2024 10:48:31 +0000
Subject: [PATCH 03/16] [lldb] Introduce RegisterType base class for all
register type classes
This is refactoring to prepare for https://github.com/llvm/llvm-project/issues/87471.
Where I will be adding support for describing registers as unions. See:
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Target-Description-Format.html
A union is like a C union and references other types defined in the XML. Just like
a set of register flags might reference an enum for one of those flags.
By introducing this base class I'm making the treatment of all these different
types generic. So that when encoding them as XML we can emit the type's dependencies
recursively, and then emit the type itself.
This strategy will also be used later in RegisterTypeBuilderClang to generate
AST to represent these types (this is the decode step of the XML).
As GDB decided to include size in enums, whenever we emit something it
will get a "user" pointer. This allows an enum type to read the size of the
register it's being attached to. No other type class requires this.
I would call this "parent" but it is not usually the parent. The heirarchy is:
* A RegisterFlags type contains many flags.
* One of those flags has an enum as its type.
* That enum needs to query two levels up to get the RegisterFlag's size.
LLDB does not care about this enum size attribute, but GDB does so we emit
it for compatibility.
I don't expect anything other than a RegisterFlags to reference an enum
at this time. In theory, a vector's element could be an enum but I do not
know of anything available today that does this.
I'd like to support arbitrary nesting of these types, but only later once
known use cases work well.
---
lldb/include/lldb/Target/RegisterFlags.h | 42 ++++----
lldb/include/lldb/Target/RegisterType.h | 62 +++++++++++
lldb/include/lldb/lldb-private-types.h | 8 +-
lldb/source/Core/DumpRegisterInfo.cpp | 6 +-
lldb/source/Core/DumpRegisterValue.cpp | 11 +-
.../Utility/RegisterFlagsDetector_arm64.cpp | 2 +-
.../GDBRemoteCommunicationServerLLGS.cpp | 15 ++-
lldb/source/Target/CMakeLists.txt | 1 +
lldb/source/Target/RegisterFlags.cpp | 55 +++++-----
lldb/source/Target/RegisterType.cpp | 23 ++++
lldb/unittests/Target/RegisterFlagsTest.cpp | 100 ++++++++++++------
11 files changed, 222 insertions(+), 103 deletions(-)
create mode 100644 lldb/include/lldb/Target/RegisterType.h
create mode 100644 lldb/source/Target/RegisterType.cpp
diff --git a/lldb/include/lldb/Target/RegisterFlags.h b/lldb/include/lldb/Target/RegisterFlags.h
index 44356decaa6bf..6eefcd281372f 100644
--- a/lldb/include/lldb/Target/RegisterFlags.h
+++ b/lldb/include/lldb/Target/RegisterFlags.h
@@ -13,6 +13,7 @@
#include <string>
#include <vector>
+#include "lldb/Target/RegisterType.h"
#include "llvm/ADT/StringSet.h"
namespace lldb_private {
@@ -20,7 +21,7 @@ namespace lldb_private {
class Stream;
class Log;
-class FieldEnum {
+class FieldEnum : public RegisterType {
public:
struct Enumerator {
uint64_t m_value;
@@ -31,9 +32,9 @@ class FieldEnum {
Enumerator(uint64_t value, std::string name)
: m_value(value), m_name(std::move(name)) {}
- void ToXML(Stream &strm) const;
-
void DumpToLog(Log *log) const;
+
+ void ToXMLElement(Stream &strm) const;
};
typedef std::vector<Enumerator> Enumerators;
@@ -45,18 +46,20 @@ class FieldEnum {
const Enumerators &GetEnumerators() const { return m_enumerators; }
- const std::string &GetID() const { return m_id; }
+ void DumpToLog(Log *log) const;
- void ToXML(Stream &strm, unsigned size) const;
+ virtual void ToXMLElement(Stream &strm,
+ const RegisterType *user = nullptr) const override;
- void DumpToLog(Log *log) const;
+ static bool classof(const RegisterType *register_type) {
+ return register_type->getKind() == RegisterType::eRegisterTypeKindEnum;
+ }
private:
- std::string m_id;
Enumerators m_enumerators;
};
-class RegisterFlags {
+class RegisterFlags : public RegisterType {
public:
class Field {
public:
@@ -97,10 +100,7 @@ class RegisterFlags {
/// covered by either field.
unsigned PaddingDistance(const Field &other) const;
- /// Output XML that describes this field, to be inserted into a target XML
- /// file. Reserved characters in field names like "<" are replaced with
- /// their XML safe equivalents like ">".
- void ToXML(Stream &strm) const;
+ void ToXMLElement(Stream &strm) const;
bool operator<(const Field &rhs) const {
return GetStart() < rhs.GetStart();
@@ -141,8 +141,8 @@ class RegisterFlags {
std::string DumpEnums(uint32_t max_width) const;
const std::vector<Field> &GetFields() const { return m_fields; }
- const std::string &GetID() const { return m_id; }
unsigned GetSize() const { return m_size; }
+
void DumpToLog(Log *log) const;
/// Produce a text table showing the layout of all the fields. Unnamed/padding
@@ -152,20 +152,14 @@ class RegisterFlags {
/// be split into many tables as needed.
std::string AsTable(uint32_t max_width) const;
- /// Output XML that describes this set of flags.
- /// EnumsToXML should have been called before this.
- void ToXML(Stream &strm) const;
+ virtual void ToXMLElement(Stream &strm,
+ const RegisterType *user = nullptr) const override;
- /// Enum types must be defined before use, and
- /// GDBRemoteCommunicationServerLLGS view of the register types is based only
- /// on the registers. So this method emits any enum types that the upcoming
- /// set of fields may need. "seen" is a set of Enum IDs that we have already
- /// printed, that is updated with any printed by this call. This prevents us
- /// printing the same enum multiple times.
- void EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const;
+ static bool classof(const RegisterType *register_type) {
+ return register_type->getKind() == RegisterType::eRegisterTypeKindFlags;
+ }
private:
- const std::string m_id;
/// Size in bytes
const unsigned m_size;
std::vector<Field> m_fields;
diff --git a/lldb/include/lldb/Target/RegisterType.h b/lldb/include/lldb/Target/RegisterType.h
new file mode 100644
index 0000000000000..56e25fc841b28
--- /dev/null
+++ b/lldb/include/lldb/Target/RegisterType.h
@@ -0,0 +1,62 @@
+//===-- RegisterType.h ------------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_REGISTERTYPE_H
+#define LLDB_TARGET_REGISTERTYPE_H
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+namespace lldb_private {
+
+class Stream;
+class Log;
+
+class RegisterType {
+public:
+ enum RegisterTypeKind {
+ eRegisterTypeKindFlags,
+ eRegisterTypeKindEnum,
+ };
+
+ RegisterTypeKind getKind() const { return m_kind; }
+
+ RegisterType(RegisterTypeKind kind, std::string id)
+ : m_kind(kind), m_id(std::move(id)) {}
+
+ /// Output XML that describes this type, to be inserted into a target XML
+ /// file. Reserved characters like "<" are replaced with their XML safe
+ /// equivalents like ">".
+ void ToXML(Stream &strm,
+ std::unordered_set<const RegisterType *> &previously_emitted,
+ const RegisterType *user = nullptr) const;
+
+ virtual ~RegisterType() = default;
+
+ /// Output the register type as an XML element. That is, "<foo ...>" until the
+ /// closing </foo>, including any child types in between. For example the
+ /// flags in a register flag set.
+ virtual void ToXMLElement(Stream &strm,
+ const RegisterType *user = nullptr) const = 0;
+
+ const std::string &GetID() const { return m_id; }
+
+ void SetDependencies(const std::vector<const RegisterType *> dependencies) {
+ m_dependencies = dependencies;
+ }
+
+private:
+ const RegisterTypeKind m_kind;
+ const std::string m_id;
+ std::vector<const RegisterType *> m_dependencies;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_REGISTERTYPE_H
diff --git a/lldb/include/lldb/lldb-private-types.h b/lldb/include/lldb/lldb-private-types.h
index a60034314b77e..4f37303208655 100644
--- a/lldb/include/lldb/lldb-private-types.h
+++ b/lldb/include/lldb/lldb-private-types.h
@@ -23,7 +23,7 @@ class DynamicLibrary;
namespace lldb_private {
class Platform;
class ExecutionContext;
-class RegisterFlags;
+class RegisterType;
typedef llvm::SmallString<256> PathSmallString;
@@ -64,10 +64,10 @@ struct RegisterInfo {
uint32_t *invalidate_regs;
/// If not nullptr, a type defined by XML descriptions.
/// Register info tables are constructed as const, but this field may need to
- /// be updated if a specific target OS has a different layout. To enable that,
+ /// be updated if a specific target OS has a different type. To enable that,
/// this is mutable. The data pointed to is still const, so you must swap a
- /// whole set of flags for another.
- mutable const RegisterFlags *flags_type;
+ /// whole type for another whole type.
+ mutable const RegisterType *register_type;
llvm::ArrayRef<uint8_t> data(const uint8_t *context_base) const {
return llvm::ArrayRef<uint8_t>(context_base + byte_offset, byte_size);
diff --git a/lldb/source/Core/DumpRegisterInfo.cpp b/lldb/source/Core/DumpRegisterInfo.cpp
index eccc6784cd497..75ad153706eaa 100644
--- a/lldb/source/Core/DumpRegisterInfo.cpp
+++ b/lldb/source/Core/DumpRegisterInfo.cpp
@@ -11,6 +11,8 @@
#include "lldb/Target/RegisterFlags.h"
#include "lldb/Utility/Stream.h"
+#include "llvm/Support/Casting.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -62,7 +64,9 @@ void lldb_private::DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
}
DoDumpRegisterInfo(strm, info.name, info.alt_name, info.byte_size,
- invalidates, read_from, in_sets, info.flags_type,
+ invalidates, read_from, in_sets,
+ llvm::dyn_cast_if_present<lldb_private::RegisterFlags>(
+ info.register_type),
terminal_width);
}
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index 37ce1496131fe..263f73f6f7fed 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -24,7 +24,6 @@ using namespace lldb;
template <typename T>
static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
lldb_private::ExecutionContextScope *exe_scope,
- const lldb_private::RegisterInfo ®_info,
lldb_private::Stream &strm) {
lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder();
@@ -108,21 +107,23 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
0, // item_bit_offset
exe_scope);
- if (!print_flags || !reg_info.flags_type || !exe_scope || !target_sp ||
+ const RegisterFlags *flags_type =
+ llvm::dyn_cast_if_present<RegisterFlags>(reg_info.register_type);
+ if (!print_flags || !flags_type || !exe_scope || !target_sp ||
(reg_info.byte_size != 4 && reg_info.byte_size != 8))
return;
CompilerType fields_type = target_sp->GetRegisterType(
- reg_info.name, *reg_info.flags_type, reg_info.byte_size);
+ reg_info.name, *flags_type, reg_info.byte_size);
// Use a new stream so we can remove a trailing newline later.
StreamString fields_stream;
if (reg_info.byte_size == 4) {
- dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope, reg_info,
+ dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope,
fields_stream);
} else {
- dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope, reg_info,
+ dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope,
fields_stream);
}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
index 403d10f8ffed2..40343b4238265 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
@@ -314,7 +314,7 @@ void Arm64RegisterFlagsDetector::UpdateRegisterInfo(
if (reg_it != search_registers.end()) {
// Attach the field information.
- reg_info->flags_type = reg_it->second;
+ reg_info->register_type = reg_it->second;
// We do not expect to see this name again so don't look for it again.
search_registers.erase(reg_it);
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index e92d18ba8731a..5d4ddcf498c88 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -31,6 +31,7 @@
#include "lldb/Host/common/NativeRegisterContext.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Target/RegisterType.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/Utility/Endian.h"
@@ -3253,7 +3254,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
if (registers_count)
response.IndentMore();
- llvm::StringSet<> field_enums_seen;
+ std::unordered_set<const RegisterType *> register_types_emitted;
for (int reg_index = 0; reg_index < registers_count; reg_index++) {
const RegisterInfo *reg_info =
reg_context.GetRegisterInfoAtIndex(reg_index);
@@ -3265,12 +3266,8 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
continue;
}
- if (reg_info->flags_type) {
- response.IndentMore();
- reg_info->flags_type->EnumsToXML(response, field_enums_seen);
- reg_info->flags_type->ToXML(response);
- response.IndentLess();
- }
+ if (reg_info->register_type)
+ reg_info->register_type->ToXML(response, register_types_emitted);
response.Indent();
response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32
@@ -3291,8 +3288,8 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() {
if (!format.empty())
response << "format=\"" << format << "\" ";
- if (reg_info->flags_type)
- response << "type=\"" << reg_info->flags_type->GetID() << "\" ";
+ if (reg_info->register_type)
+ response << "type=\"" << reg_info->register_type->GetID() << "\" ";
const char *const register_set_name =
reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index);
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index ee9b68525e201..28ddbafb379f6 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -39,6 +39,7 @@ add_lldb_library(lldbTarget
RegisterContext.cpp
RegisterContextUnwind.cpp
RegisterFlags.cpp
+ RegisterType.cpp
RegisterNumber.cpp
RemoteAwarePlatform.cpp
ScriptedThreadPlan.cpp
diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterFlags.cpp
index f070e8896b9ee..4d66d9a18d0dd 100644
--- a/lldb/source/Target/RegisterFlags.cpp
+++ b/lldb/source/Target/RegisterFlags.cpp
@@ -11,6 +11,7 @@
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
#include <limits>
#include <numeric>
@@ -111,16 +112,22 @@ void RegisterFlags::SetFields(const std::vector<Field> &fields) {
// We expect that these are unsorted but do not overlap.
// They could fill the register but may have gaps.
m_fields = fields;
+
+ std::vector<const RegisterType *> dependencies;
+ for (const auto &field : m_fields)
+ if (auto enum_type = field.GetEnum())
+ dependencies.push_back(dynamic_cast<const RegisterType *>(enum_type));
+ SetDependencies(dependencies);
}
RegisterFlags::RegisterFlags(std::string id, unsigned size,
const std::vector<Field> &fields)
- : m_id(std::move(id)), m_size(size) {
+ : RegisterType(RegisterType::eRegisterTypeKindFlags, id), m_size(size) {
SetFields(fields);
}
void RegisterFlags::DumpToLog(Log *log) const {
- LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size);
+ LLDB_LOG(log, "ID: \"{0}\" Size: {1}", GetID().c_str(), m_size);
for (const Field &field : m_fields)
field.DumpToLog(log);
}
@@ -305,30 +312,24 @@ std::string RegisterFlags::DumpEnums(uint32_t max_width) const {
return strm.GetString().str();
}
-void RegisterFlags::EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const {
- for (const Field &field : m_fields)
- if (const FieldEnum *enum_type = field.GetEnum()) {
- const std::string &id = enum_type->GetID();
- if (!seen.contains(id)) {
- enum_type->ToXML(strm, GetSize());
- seen.insert(id);
- }
- }
-}
-
-void FieldEnum::ToXML(Stream &strm, unsigned size) const {
+void FieldEnum::ToXMLElement(Stream &strm, const RegisterType *user) const {
// Example XML:
// <enum id="foo" size="4">
// <evalue name="bar" value="1"/>
// </enum>
// Note that "size" is only emitted for GDB compatibility, LLDB does not need
// it.
-
strm.Indent();
- strm << "<enum id=\"" << GetID() << "\" ";
- // This is the size of the underlying enum type if this were a C type.
- // In other words, the size of the register in bytes.
- strm.Printf("size=\"%d\"", size);
+ strm << "<enum id=\"" << GetID() << "\"";
+
+ // We don't expect the user of an enum type to be anything but a register,
+ // but we cannot crash if that isn't true.
+ if (const RegisterFlags *flags_type =
+ llvm::dyn_cast_if_present<RegisterFlags>(user)) {
+ // This is the size of the underlying enum type if this were a C type.
+ // In other words, the size of the register in bytes.
+ strm.Printf(" size=\"%d\"", flags_type->GetSize());
+ }
const Enumerators &enumerators = GetEnumerators();
if (enumerators.empty()) {
@@ -340,14 +341,14 @@ void FieldEnum::ToXML(Stream &strm, unsigned size) const {
strm.IndentMore();
for (const auto &enumerator : enumerators) {
strm.Indent();
- enumerator.ToXML(strm);
+ enumerator.ToXMLElement(strm);
strm.PutChar('\n');
}
strm.IndentLess();
strm.Indent("</enum>\n");
}
-void FieldEnum::Enumerator::ToXML(Stream &strm) const {
+void FieldEnum::Enumerator::ToXMLElement(Stream &strm) const {
std::string escaped_name;
llvm::raw_string_ostream escape_strm(escaped_name);
llvm::printHTMLEscaped(m_name, escape_strm);
@@ -360,12 +361,13 @@ void FieldEnum::Enumerator::DumpToLog(Log *log) const {
}
void FieldEnum::DumpToLog(Log *log) const {
- LLDB_LOG(log, "ID: \"{0}\"", m_id.c_str());
+ LLDB_LOG(log, "ID: \"{0}\"", GetID().c_str());
for (const auto &enumerator : GetEnumerators())
enumerator.DumpToLog(log);
}
-void RegisterFlags::ToXML(Stream &strm) const {
+void RegisterFlags::ToXMLElement(Stream &strm, const RegisterType *user) const {
+ (void)user;
// Example XML:
// <flags id="cpsr_flags" size="4">
// <field name="incorrect" start="0" end="0"/>
@@ -381,14 +383,14 @@ void RegisterFlags::ToXML(Stream &strm) const {
strm << "\n";
strm.IndentMore();
- field.ToXML(strm);
+ field.ToXMLElement(strm);
strm.IndentLess();
}
strm.PutChar('\n');
strm.Indent("</flags>\n");
}
-void RegisterFlags::Field::ToXML(Stream &strm) const {
+void RegisterFlags::Field::ToXMLElement(Stream &strm) const {
// Example XML with an enum:
// <field name="correct" start="0" end="0" type="some_enum">
// Without:
@@ -410,7 +412,8 @@ void RegisterFlags::Field::ToXML(Stream &strm) const {
}
FieldEnum::FieldEnum(std::string id, const Enumerators &enumerators)
- : m_id(id), m_enumerators(enumerators) {
+ : RegisterType(RegisterType::eRegisterTypeKindEnum, id),
+ m_enumerators(enumerators) {
for (const auto &enumerator : m_enumerators) {
UNUSED_IF_ASSERT_DISABLED(enumerator);
assert(enumerator.m_name.size() && "Enumerator name cannot be empty");
diff --git a/lldb/source/Target/RegisterType.cpp b/lldb/source/Target/RegisterType.cpp
new file mode 100644
index 0000000000000..d47d015f2f573
--- /dev/null
+++ b/lldb/source/Target/RegisterType.cpp
@@ -0,0 +1,23 @@
+//===-- RegisterType.cpp --------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/RegisterType.h"
+
+using namespace lldb_private;
+
+void RegisterType::ToXML(
+ Stream &strm, std::unordered_set<const RegisterType *> &previously_emitted,
+ const RegisterType *user) const {
+ for (auto dep : m_dependencies)
+ if (previously_emitted.find(dep) == previously_emitted.end()) {
+ dep->ToXML(strm, previously_emitted, this);
+ previously_emitted.insert(dep);
+ }
+
+ ToXMLElement(strm, user);
+}
\ No newline at end of file
diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterFlagsTest.cpp
index 188a723113878..1e99a26c78076 100644
--- a/lldb/unittests/Target/RegisterFlagsTest.cpp
+++ b/lldb/unittests/Target/RegisterFlagsTest.cpp
@@ -11,6 +11,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include "llvm/Support/Casting.h"
+
using namespace lldb_private;
using namespace lldb;
@@ -277,7 +279,7 @@ TEST(RegisterFlagsTest, DumpEnums) {
"D: 0 = an_enumerator, 1 = another_enumerator");
}
-TEST(RegisterFieldsTest, FlagsToXML) {
+TEST(RegisterFieldsTest, FlagsToXMLElement) {
StreamString strm;
// RegisterFlags requires that some fields be given, so no testing of empty
@@ -285,12 +287,13 @@ TEST(RegisterFieldsTest, FlagsToXML) {
// Unnamed fields are padding that are ignored. This applies to fields passed
// in, and those generated to fill the other bits (31-1 here).
- RegisterFlags("Foo", 4, {RegisterFlags::Field("", 0, 0)}).ToXML(strm);
+ RegisterFlags("Foo", 4, {RegisterFlags::Field("", 0, 0)}).ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
"</flags>\n");
strm.Clear();
- RegisterFlags("Foo", 4, {RegisterFlags::Field("abc", 0, 0)}).ToXML(strm);
+ RegisterFlags("Foo", 4, {RegisterFlags::Field("abc", 0, 0)})
+ .ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
" <field name=\"abc\" start=\"0\" end=\"0\"/>\n"
"</flags>\n");
@@ -301,7 +304,7 @@ TEST(RegisterFieldsTest, FlagsToXML) {
RegisterFlags(
"Bar", 5,
{RegisterFlags::Field("f1", 25, 32), RegisterFlags::Field("f2", 10, 24)})
- .ToXML(strm);
+ .ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
" <flags id=\"Bar\" size=\"5\">\n"
" <field name=\"f1\" start=\"25\" end=\"32\"/>\n"
@@ -315,7 +318,7 @@ TEST(RegisterFieldsTest, FlagsToXML) {
{RegisterFlags::Field("A<", 4), RegisterFlags::Field("B>", 3),
RegisterFlags::Field("C'", 2), RegisterFlags::Field("D\"", 1),
RegisterFlags::Field("E&", 0)})
- .ToXML(strm);
+ .ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
"<flags id=\"Safe\" size=\"8\">\n"
" <field name=\"A<\" start=\"4\" end=\"4\"/>\n"
@@ -331,7 +334,7 @@ TEST(RegisterFieldsTest, FlagsToXML) {
RegisterFlags("Enumerators", 8,
{RegisterFlags::Field("NoEnumerators", 4),
RegisterFlags::Field("OneEnumerator", 3, 3, &enum_single)})
- .ToXML(strm);
+ .ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
"<flags id=\"Enumerators\" size=\"8\">\n"
" <field name=\"NoEnumerators\" start=\"4\" end=\"4\"/>\n"
@@ -340,10 +343,10 @@ TEST(RegisterFieldsTest, FlagsToXML) {
"</flags>\n");
}
-TEST(RegisterFlagsTest, EnumeratorToXML) {
+TEST(RegisterFlagsTest, EnumeratorToXMLElement) {
StreamString strm;
- FieldEnum::Enumerator(1234, "test").ToXML(strm);
+ FieldEnum::Enumerator(1234, "test").ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<evalue name=\"test\" value=\"1234\"/>");
// Special XML chars in names must be escaped.
@@ -362,58 +365,89 @@ TEST(RegisterFlagsTest, EnumeratorToXML) {
for (const auto &[enumerator, expected] : special_names) {
strm.Clear();
- enumerator.ToXML(strm);
+ enumerator.ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), expected);
}
}
-TEST(RegisterFlagsTest, EnumToXML) {
+TEST(RegisterFlagsTest, EnumToXMLElement) {
StreamString strm;
- FieldEnum("empty_enum", {}).ToXML(strm, 4);
+ RegisterFlags user_4("Foo", 4, {RegisterFlags::Field("", 0, 0)});
+ FieldEnum("empty_enum", {})
+ .ToXMLElement(strm, llvm::dyn_cast<const RegisterType>(&user_4));
ASSERT_EQ(strm.GetString(), "<enum id=\"empty_enum\" size=\"4\"/>\n");
strm.Clear();
+ RegisterFlags user_5("Foo", 5, {RegisterFlags::Field("", 0, 0)});
FieldEnum("single_enumerator", {FieldEnum::Enumerator(0, "zero")})
- .ToXML(strm, 5);
+ .ToXMLElement(strm, llvm::dyn_cast<const RegisterType>(&user_5));
ASSERT_EQ(strm.GetString(), "<enum id=\"single_enumerator\" size=\"5\">\n"
" <evalue name=\"zero\" value=\"0\"/>\n"
"</enum>\n");
+ // Currently we don't emit size if the user of this type is not a flags.
+ // We don't expect to see this situation in real use.
strm.Clear();
FieldEnum("multiple_enumerator",
{FieldEnum::Enumerator(0, "zero"), FieldEnum::Enumerator(1, "one")})
- .ToXML(strm, 8);
- ASSERT_EQ(strm.GetString(), "<enum id=\"multiple_enumerator\" size=\"8\">\n"
+ .ToXMLElement(strm, nullptr);
+ ASSERT_EQ(strm.GetString(), "<enum id=\"multiple_enumerator\">\n"
" <evalue name=\"zero\" value=\"0\"/>\n"
" <evalue name=\"one\" value=\"1\"/>\n"
"</enum>\n");
}
-TEST(RegisterFlagsTest, EnumsToXML) {
+TEST(RegisterFlagsTest, RegisterFlagsToXML) {
// This method should output all the enums used by the register flag set,
- // only once.
+ // then the flags set itself. There should only be one definition of each
+ // enum, even if it is used by multiple fields.
StreamString strm;
FieldEnum enum_a("enum_a", {FieldEnum::Enumerator(0, "zero")});
FieldEnum enum_b("enum_b", {FieldEnum::Enumerator(1, "one")});
FieldEnum enum_c("enum_c", {FieldEnum::Enumerator(2, "two")});
- llvm::StringSet<> seen;
+ std::unordered_set<const RegisterType *> previously_emitted;
// Pretend that enum_c was already emitted for a different flag set.
- seen.insert("enum_c");
-
- RegisterFlags("Test", 4,
- {
- RegisterFlags::Field("f1", 31, 31, &enum_a),
- RegisterFlags::Field("f2", 30, 30, &enum_a),
- RegisterFlags::Field("f3", 29, 29, &enum_b),
- RegisterFlags::Field("f4", 27, 28, &enum_c),
- })
- .EnumsToXML(strm, seen);
- ASSERT_EQ(strm.GetString(), "<enum id=\"enum_a\" size=\"4\">\n"
- " <evalue name=\"zero\" value=\"0\"/>\n"
- "</enum>\n"
- "<enum id=\"enum_b\" size=\"4\">\n"
- " <evalue name=\"one\" value=\"1\"/>\n"
- "</enum>\n");
+ previously_emitted.insert(&enum_c);
+
+ std::vector<RegisterFlags::Field> fields{
+ RegisterFlags::Field("f1", 31, 31, &enum_a),
+ RegisterFlags::Field("f2", 30, 30, &enum_a),
+ RegisterFlags::Field("f3", 29, 29, &enum_b),
+ RegisterFlags::Field("f4", 27, 28, &enum_c),
+ };
+
+ RegisterFlags("Test", 4, fields).ToXML(strm, previously_emitted);
+ ASSERT_EQ(strm.GetString(),
+ "<enum id=\"enum_a\" size=\"4\">\n"
+ " <evalue name=\"zero\" value=\"0\"/>\n"
+ "</enum>\n"
+ "<enum id=\"enum_b\" size=\"4\">\n"
+ " <evalue name=\"one\" value=\"1\"/>\n"
+ "</enum>\n"
+ "<flags id=\"Test\" size=\"4\">\n"
+ " <field name=\"f1\" start=\"31\" end=\"31\" type=\"enum_a\"/>\n"
+ " <field name=\"f2\" start=\"30\" end=\"30\" type=\"enum_a\"/>\n"
+ " <field name=\"f3\" start=\"29\" end=\"29\" type=\"enum_b\"/>\n"
+ " <field name=\"f4\" start=\"27\" end=\"28\" type=\"enum_c\"/>\n"
+ "</flags>\n");
+
+ // If another flag set were to use the same enums we should not output them
+ // again. Only output anything new.
+ strm.Clear();
+ FieldEnum enum_d("enum_d", {FieldEnum::Enumerator(3, "three")});
+ fields.push_back(RegisterFlags::Field("f5", 25, 26, &enum_d));
+ RegisterFlags("Test", 4, fields).ToXML(strm, previously_emitted);
+ ASSERT_EQ(strm.GetString(),
+ "<enum id=\"enum_d\" size=\"4\">\n"
+ " <evalue name=\"three\" value=\"3\"/>\n"
+ "</enum>\n"
+ "<flags id=\"Test\" size=\"4\">\n"
+ " <field name=\"f1\" start=\"31\" end=\"31\" type=\"enum_a\"/>\n"
+ " <field name=\"f2\" start=\"30\" end=\"30\" type=\"enum_a\"/>\n"
+ " <field name=\"f3\" start=\"29\" end=\"29\" type=\"enum_b\"/>\n"
+ " <field name=\"f4\" start=\"27\" end=\"28\" type=\"enum_c\"/>\n"
+ " <field name=\"f5\" start=\"25\" end=\"26\" type=\"enum_d\"/>\n"
+ "</flags>\n");
}
\ No newline at end of file
>From f06db3c698b8d9c8e336783a497ff2acbc14052e Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Tue, 3 Sep 2024 09:42:25 +0000
Subject: [PATCH 04/16] [lldb] Rename some register type classes
So that when more types are added, the hierarchy is clear.
RegisterType
-> RegisterTypeEnum
-> RegisterTypeFlags
(in future also...)
-> RegisterTypeUnion
-> RegisterTypeVector
Renamed the test file as it will cover all the classes derived
from RegisterType.
---
lldb/include/lldb/Core/DumpRegisterInfo.h | 4 +-
lldb/include/lldb/Core/FormatEntity.h | 2 +-
.../include/lldb/Target/DynamicRegisterInfo.h | 4 +-
.../include/lldb/Target/RegisterTypeBuilder.h | 7 +-
.../{RegisterFlags.h => RegisterTypeFlags.h} | 24 +-
lldb/include/lldb/Target/Target.h | 2 +-
lldb/source/Core/DumpRegisterInfo.cpp | 6 +-
lldb/source/Core/DumpRegisterValue.cpp | 6 +-
lldb/source/Core/FormatEntity.cpp | 6 +-
.../Utility/RegisterFlagsDetector_arm64.cpp | 33 ++-
.../Utility/RegisterFlagsDetector_arm64.h | 6 +-
.../Process/gdb-remote/ProcessGDBRemote.cpp | 64 +++--
.../Process/gdb-remote/ProcessGDBRemote.h | 8 +-
.../RegisterTypeBuilderClang.cpp | 11 +-
.../RegisterTypeBuilderClang.h | 2 +-
lldb/source/Target/CMakeLists.txt | 2 +-
...egisterFlags.cpp => RegisterTypeFlags.cpp} | 83 +++---
lldb/source/Target/Target.cpp | 7 +-
.../register_command/TestRegisters.py | 2 +-
.../gdb_remote_client/TestXMLRegisterFlags.py | 4 +-
lldb/unittests/Core/DumpRegisterInfoTest.cpp | 27 +-
lldb/unittests/Target/CMakeLists.txt | 2 +-
...sterFlagsTest.cpp => RegisterTypeTest.cpp} | 257 +++++++++---------
.../gn/secondary/lldb/source/Target/BUILD.gn | 2 +-
24 files changed, 302 insertions(+), 269 deletions(-)
rename lldb/include/lldb/Target/{RegisterFlags.h => RegisterTypeFlags.h} (89%)
rename lldb/source/Target/{RegisterFlags.cpp => RegisterTypeFlags.cpp} (81%)
rename lldb/unittests/Target/{RegisterFlagsTest.cpp => RegisterTypeTest.cpp} (61%)
diff --git a/lldb/include/lldb/Core/DumpRegisterInfo.h b/lldb/include/lldb/Core/DumpRegisterInfo.h
index bceabcacd836e..06b4d71940236 100644
--- a/lldb/include/lldb/Core/DumpRegisterInfo.h
+++ b/lldb/include/lldb/Core/DumpRegisterInfo.h
@@ -18,7 +18,7 @@ namespace lldb_private {
class Stream;
class RegisterContext;
struct RegisterInfo;
-class RegisterFlags;
+class RegisterTypeFlags;
void DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
const RegisterInfo &info, uint32_t terminal_width);
@@ -29,7 +29,7 @@ void DoDumpRegisterInfo(
const std::vector<const char *> &invalidates,
const std::vector<const char *> &read_from,
const std::vector<std::pair<const char *, uint32_t>> &in_sets,
- const RegisterFlags *flags_type, uint32_t terminal_width);
+ const RegisterTypeFlags *flags_type, uint32_t terminal_width);
} // namespace lldb_private
diff --git a/lldb/include/lldb/Core/FormatEntity.h b/lldb/include/lldb/Core/FormatEntity.h
index e01009a44aac7..f0e781c718765 100644
--- a/lldb/include/lldb/Core/FormatEntity.h
+++ b/lldb/include/lldb/Core/FormatEntity.h
@@ -78,7 +78,7 @@ struct Entry {
FrameRegisterPC,
FrameRegisterSP,
FrameRegisterFP,
- FrameRegisterFlags,
+ FrameRegisterTypeFlags,
FrameRegisterByName,
FrameIsArtificial,
FrameKind,
diff --git a/lldb/include/lldb/Target/DynamicRegisterInfo.h b/lldb/include/lldb/Target/DynamicRegisterInfo.h
index 43bba5038e537..717e07cdc5453 100644
--- a/lldb/include/lldb/Target/DynamicRegisterInfo.h
+++ b/lldb/include/lldb/Target/DynamicRegisterInfo.h
@@ -12,7 +12,7 @@
#include <map>
#include <vector>
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
@@ -41,7 +41,7 @@ class DynamicRegisterInfo {
std::vector<uint32_t> invalidate_regs;
uint32_t value_reg_offset = 0;
// Non-null if there is an XML provided type.
- const RegisterFlags *flags_type = nullptr;
+ const RegisterTypeFlags *flags_type = nullptr;
};
DynamicRegisterInfo() = default;
diff --git a/lldb/include/lldb/Target/RegisterTypeBuilder.h b/lldb/include/lldb/Target/RegisterTypeBuilder.h
index 7239e1d4bd126..bd75ebd3b6d58 100644
--- a/lldb/include/lldb/Target/RegisterTypeBuilder.h
+++ b/lldb/include/lldb/Target/RegisterTypeBuilder.h
@@ -18,9 +18,10 @@ class RegisterTypeBuilder : public PluginInterface {
public:
~RegisterTypeBuilder() override = default;
- virtual CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterFlags &flags,
- uint32_t byte_size) = 0;
+ virtual CompilerType
+ GetRegisterType(const std::string &name,
+ const lldb_private::RegisterTypeFlags &flags,
+ uint32_t byte_size) = 0;
protected:
RegisterTypeBuilder() = default;
diff --git a/lldb/include/lldb/Target/RegisterFlags.h b/lldb/include/lldb/Target/RegisterTypeFlags.h
similarity index 89%
rename from lldb/include/lldb/Target/RegisterFlags.h
rename to lldb/include/lldb/Target/RegisterTypeFlags.h
index 6eefcd281372f..77dacb902fc09 100644
--- a/lldb/include/lldb/Target/RegisterFlags.h
+++ b/lldb/include/lldb/Target/RegisterTypeFlags.h
@@ -1,4 +1,4 @@
-//===-- RegisterFlags.h -----------------------------------------*- C++ -*-===//
+//===-- RegisterTypeFlags.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLDB_TARGET_REGISTERFLAGS_H
-#define LLDB_TARGET_REGISTERFLAGS_H
+#ifndef LLDB_TARGET_REGISTERTYPEFLAGS_H
+#define LLDB_TARGET_REGISTERTYPEFLAGS_H
#include <stdint.h>
#include <string>
@@ -21,7 +21,7 @@ namespace lldb_private {
class Stream;
class Log;
-class FieldEnum : public RegisterType {
+class RegisterTypeEnum : public RegisterType {
public:
struct Enumerator {
uint64_t m_value;
@@ -42,7 +42,7 @@ class FieldEnum : public RegisterType {
// GDB also includes a "size" that is the size of the underlying register.
// We will not store that here but instead use the size of the register
// this gets attached to when emitting XML.
- FieldEnum(std::string id, const Enumerators &enumerators);
+ RegisterTypeEnum(std::string id, const Enumerators &enumerators);
const Enumerators &GetEnumerators() const { return m_enumerators; }
@@ -59,7 +59,7 @@ class FieldEnum : public RegisterType {
Enumerators m_enumerators;
};
-class RegisterFlags : public RegisterType {
+class RegisterTypeFlags : public RegisterType {
public:
class Field {
public:
@@ -69,7 +69,7 @@ class RegisterFlags : public RegisterType {
/// Construct a field that also has some known enum values.
Field(std::string name, unsigned start, unsigned end,
- const FieldEnum *enum_type);
+ const RegisterTypeEnum *enum_type);
/// Construct a field that occupies a single bit.
Field(std::string name, unsigned bit_position);
@@ -92,7 +92,7 @@ class RegisterFlags : public RegisterType {
const std::string &GetName() const { return m_name; }
unsigned GetStart() const { return m_start; }
unsigned GetEnd() const { return m_end; }
- const FieldEnum *GetEnum() const { return m_enum_type; }
+ const RegisterTypeEnum *GetEnum() const { return m_enum_type; }
bool Overlaps(const Field &other) const;
void DumpToLog(Log *log) const;
@@ -121,15 +121,15 @@ class RegisterFlags : public RegisterType {
unsigned m_start;
unsigned m_end;
- const FieldEnum *m_enum_type;
+ const RegisterTypeEnum *m_enum_type;
};
/// This assumes that:
/// * There is at least one field.
/// * The fields are sorted in descending order.
/// Gaps are allowed.
- RegisterFlags(std::string id, unsigned size,
- const std::vector<Field> &fields);
+ RegisterTypeFlags(std::string id, unsigned size,
+ const std::vector<Field> &fields);
/// Replace all the fields with the new set of fields. All the assumptions
/// and checks apply as when you use the constructor. Intended to only be used
@@ -167,4 +167,4 @@ class RegisterFlags : public RegisterType {
} // namespace lldb_private
-#endif // LLDB_TARGET_REGISTERFLAGS_H
+#endif // LLDB_TARGET_REGISTERTYPEFLAGS_H
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 87b5c4f9591f1..b7b173baae883 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1484,7 +1484,7 @@ class Target : public std::enable_shared_from_this<Target>,
llvm::Expected<lldb_private::Address> GetEntryPointAddress();
CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterFlags &flags,
+ const lldb_private::RegisterTypeFlags &flags,
uint32_t byte_size);
/// Sends a breakpoint notification event.
diff --git a/lldb/source/Core/DumpRegisterInfo.cpp b/lldb/source/Core/DumpRegisterInfo.cpp
index 75ad153706eaa..8906a63e53db2 100644
--- a/lldb/source/Core/DumpRegisterInfo.cpp
+++ b/lldb/source/Core/DumpRegisterInfo.cpp
@@ -8,7 +8,7 @@
#include "lldb/Core/DumpRegisterInfo.h"
#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/Stream.h"
#include "llvm/Support/Casting.h"
@@ -65,7 +65,7 @@ void lldb_private::DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
DoDumpRegisterInfo(strm, info.name, info.alt_name, info.byte_size,
invalidates, read_from, in_sets,
- llvm::dyn_cast_if_present<lldb_private::RegisterFlags>(
+ llvm::dyn_cast_if_present<lldb_private::RegisterTypeFlags>(
info.register_type),
terminal_width);
}
@@ -92,7 +92,7 @@ void lldb_private::DoDumpRegisterInfo(
Stream &strm, const char *name, const char *alt_name, uint32_t byte_size,
const std::vector<const char *> &invalidates,
const std::vector<const char *> &read_from,
- const std::vector<SetInfo> &in_sets, const RegisterFlags *flags_type,
+ const std::vector<SetInfo> &in_sets, const RegisterTypeFlags *flags_type,
uint32_t terminal_width) {
strm << " Name: " << name;
if (alt_name)
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index 263f73f6f7fed..c6f61cd0dd865 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -9,7 +9,7 @@
#include "lldb/Core/DumpRegisterValue.h"
#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/RegisterValue.h"
@@ -107,8 +107,8 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
0, // item_bit_offset
exe_scope);
- const RegisterFlags *flags_type =
- llvm::dyn_cast_if_present<RegisterFlags>(reg_info.register_type);
+ const RegisterTypeFlags *flags_type =
+ llvm::dyn_cast_if_present<RegisterTypeFlags>(reg_info.register_type);
if (!print_flags || !flags_type || !exe_scope || !target_sp ||
(reg_info.byte_size != 4 && reg_info.byte_size != 8))
return;
diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 24c4896f975eb..764d746f5d7bf 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -104,7 +104,7 @@ constexpr Definition g_frame_child_entries[] = {
Definition("pc", EntryType::FrameRegisterPC),
Definition("fp", EntryType::FrameRegisterFP),
Definition("sp", EntryType::FrameRegisterSP),
- Definition("flags", EntryType::FrameRegisterFlags),
+ Definition("flags", EntryType::FrameRegisterTypeFlags),
Definition("no-debug", EntryType::FrameNoDebug),
Entry::DefinitionWithChildren("reg", EntryType::FrameRegisterByName,
g_string_entry),
@@ -380,7 +380,7 @@ const char *FormatEntity::Entry::TypeToCString(Type t) {
ENUM_TO_CSTR(FrameRegisterPC);
ENUM_TO_CSTR(FrameRegisterSP);
ENUM_TO_CSTR(FrameRegisterFP);
- ENUM_TO_CSTR(FrameRegisterFlags);
+ ENUM_TO_CSTR(FrameRegisterTypeFlags);
ENUM_TO_CSTR(FrameRegisterByName);
ENUM_TO_CSTR(FrameIsArtificial);
ENUM_TO_CSTR(FrameKind);
@@ -1708,7 +1708,7 @@ bool FormatEntity::Formatter::Format(const Entry &entry, Stream &s,
}
return false;
- case Entry::Type::FrameRegisterFlags:
+ case Entry::Type::FrameRegisterTypeFlags:
if (m_exe_ctx) {
StackFrame *frame = m_exe_ctx->GetFramePtr();
if (frame) {
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
index 40343b4238265..710e0fe16f9f7 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
@@ -40,7 +40,7 @@ Arm64RegisterFlagsDetector::DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2,
if (!(hwcap2 & HWCAP2_POE))
return {};
- static const FieldEnum por_el0_perm_enum("por_el0_perm_enum",
+ static const RegisterTypeEnum por_el0_perm_enum("por_el0_perm_enum",
{
{0b0000, "No Access"},
{0b0001, "Read"},
@@ -81,10 +81,11 @@ Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
if (!(hwcap2 & HWCAP2_FPMR))
return {};
- static const FieldEnum fp8_format_enum("fp8_format_enum", {
- {0, "FP8_E5M2"},
- {1, "FP8_E4M3"},
- });
+ static const RegisterTypeEnum fp8_format_enum("fp8_format_enum",
+ {
+ {0, "FP8_E5M2"},
+ {1, "FP8_E4M3"},
+ });
return {
{"LSCALE2", 32, 37},
{"NSCALE", 24, 31},
@@ -144,12 +145,12 @@ Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2,
// to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
// used to build the value.
- std::vector<RegisterFlags::Field> fields;
+ std::vector<RegisterTypeFlags::Field> fields;
fields.reserve(4);
if (hwcap3 & HWCAP3_MTE_STORE_ONLY)
fields.push_back({"STORE_ONLY", 19});
- static const FieldEnum tcf_enum(
+ static const RegisterTypeEnum tcf_enum(
"tcf_enum",
{{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}});
@@ -167,11 +168,14 @@ Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
uint64_t hwcap3) {
(void)hwcap3;
- static const FieldEnum rmode_enum(
+ static const RegisterTypeEnum rmode_enum(
"rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
- std::vector<RegisterFlags::Field> fpcr_fields{
- {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum},
+ std::vector<RegisterTypeFlags::Field> fpcr_fields{
+ {"AHP", 26},
+ {"DN", 25},
+ {"FZ", 24},
+ {"RMode", 22, 23, &rmode_enum},
// Bits 21-20 are "Stride" which is unused in AArch64 state.
};
@@ -236,8 +240,11 @@ Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
// or at least not from userspace.
// Status bits that are always present.
- std::vector<RegisterFlags::Field> cpsr_fields{
- {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
+ std::vector<RegisterTypeFlags::Field> cpsr_fields{
+ {"N", 31},
+ {"Z", 30},
+ {"C", 29},
+ {"V", 28},
// Bits 27-26 reserved.
};
@@ -290,7 +297,7 @@ void Arm64RegisterFlagsDetector::UpdateRegisterInfo(
// Register names will not be duplicated, so we do not want to compare against
// one if it has already been found. Each time we find one, we erase it from
// this list.
- std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
+ std::vector<std::pair<llvm::StringRef, const RegisterTypeFlags *>>
search_registers;
for (const auto ® : m_registers) {
// It is possible that a register is all extension dependent fields, and
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
index 496c395de48a4..6fb305fc16702 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
@@ -9,7 +9,7 @@
#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "llvm/ADT/StringRef.h"
#include <functional>
@@ -52,7 +52,7 @@ class Arm64RegisterFlagsDetector {
bool HasDetected() const { return m_has_detected; }
private:
- using Fields = std::vector<RegisterFlags::Field>;
+ using Fields = std::vector<RegisterTypeFlags::Field>;
using DetectorFn = std::function<Fields(uint64_t, uint64_t, uint64_t)>;
static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
@@ -78,7 +78,7 @@ class Arm64RegisterFlagsDetector {
m_detector(detector) {}
llvm::StringRef m_name;
- RegisterFlags m_flags;
+ RegisterTypeFlags m_flags;
DetectorFn m_detector;
} m_registers[9] = {
RegisterEntry("cpsr", 4, DetectCPSRFields),
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index adf108919b36e..65d16b9dc8f7e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -55,7 +55,7 @@
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -4571,7 +4571,8 @@ struct GdbServerTargetInfo {
RegisterSetMap reg_set_map;
};
-static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {
+static RegisterTypeEnum::Enumerators
+ParseEnumEvalues(const XMLNode &enum_node) {
Log *log(GetLog(GDBRLog::Process));
// We will use the last instance of each value. Also we preserve the order
// of declaration in the XML, as it may not be numerical.
@@ -4585,7 +4586,7 @@ static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {
// 2 = pre-startup, 1 = startup, 0 = startup
// This only matters for "register info" but let's trust what the server
// chose regardless.
- std::map<uint64_t, FieldEnum::Enumerator> enumerators;
+ std::map<uint64_t, RegisterTypeEnum::Enumerator> enumerators;
enum_node.ForEachChildElementWithName(
"evalue", [&enumerators, &log](const XMLNode &enumerator_node) {
@@ -4624,22 +4625,22 @@ static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) {
if (value && name)
enumerators.insert_or_assign(
- *value, FieldEnum::Enumerator(*value, name->str()));
+ *value, RegisterTypeEnum::Enumerator(*value, name->str()));
// Find all evalue elements.
return true;
});
- FieldEnum::Enumerators final_enumerators;
+ RegisterTypeEnum::Enumerators final_enumerators;
for (auto [_, enumerator] : enumerators)
final_enumerators.push_back(enumerator);
return final_enumerators;
}
-static void
-ParseEnums(XMLNode feature_node,
- llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) {
+static void ParseEnums(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> ®isters_enum_types) {
Log *log(GetLog(GDBRLog::Process));
// The top level element is "<enum...".
@@ -4666,13 +4667,14 @@ ParseEnums(XMLNode feature_node,
});
if (!id.empty()) {
- FieldEnum::Enumerators enumerators = ParseEnumEvalues(enum_node);
+ RegisterTypeEnum::Enumerators enumerators =
+ ParseEnumEvalues(enum_node);
if (!enumerators.empty()) {
LLDB_LOG(log,
"ProcessGDBRemote::ParseEnums Found enum type \"{0}\"",
id);
registers_enum_types.insert_or_assign(
- id, std::make_unique<FieldEnum>(id, enumerators));
+ id, std::make_unique<RegisterTypeEnum>(id, enumerators));
}
}
@@ -4681,14 +4683,15 @@ ParseEnums(XMLNode feature_node,
});
}
-static std::vector<RegisterFlags::Field> ParseFlagsFields(
- XMLNode flags_node, unsigned size,
- const llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) {
+static std::vector<RegisterTypeFlags::Field>
+ParseFlagsFields(XMLNode flags_node, unsigned size,
+ const llvm::StringMap<std::unique_ptr<RegisterTypeEnum>>
+ ®isters_enum_types) {
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;
+ std::vector<RegisterTypeFlags::Field> fields;
flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, &log,
®isters_enum_types](
const XMLNode
@@ -4765,7 +4768,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(
"\"{2}\", ignoring",
*start, *end, name->data());
else {
- if (RegisterFlags::Field::GetSizeInBits(*start, *end) > 64)
+ if (RegisterTypeFlags::Field::GetSizeInBits(*start, *end) > 64)
LLDB_LOG(log,
"ProcessGDBRemote::ParseFlagsFields Ignoring field \"{2}\" "
"that has "
@@ -4773,7 +4776,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(
name->data());
else {
// A field's type may be set to the name of an enum type.
- const FieldEnum *enum_type = nullptr;
+ const RegisterTypeEnum *enum_type = nullptr;
if (type && !type->empty()) {
auto found = registers_enum_types.find(*type);
if (found != registers_enum_types.end()) {
@@ -4781,7 +4784,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(
// No enumerator can exceed the range of the field itself.
uint64_t max_value =
- RegisterFlags::Field::GetMaxValue(*start, *end);
+ RegisterTypeFlags::Field::GetMaxValue(*start, *end);
for (const auto &enumerator : enum_type->GetEnumerators()) {
if (enumerator.m_value > max_value) {
enum_type = nullptr;
@@ -4805,7 +4808,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(
}
fields.push_back(
- RegisterFlags::Field(name->str(), *start, *end, enum_type));
+ RegisterTypeFlags::Field(name->str(), *start, *end, enum_type));
}
}
}
@@ -4817,8 +4820,9 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(
void ParseFlags(
XMLNode feature_node,
- llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types,
- const llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) {
+ llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> ®isters_flags_types,
+ const llvm::StringMap<std::unique_ptr<RegisterTypeEnum>>
+ ®isters_enum_types) {
Log *log(GetLog(GDBRLog::Process));
feature_node.ForEachChildElementWithName(
@@ -4856,15 +4860,15 @@ void ParseFlags(
if (id && size) {
// Process the fields of this set of flags.
- std::vector<RegisterFlags::Field> fields =
+ std::vector<RegisterTypeFlags::Field> fields =
ParseFlagsFields(flags_node, *size, registers_enum_types);
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::vector<RegisterTypeFlags::Field>::const_iterator overlap =
std::adjacent_find(fields.begin(), fields.end(),
- [](const RegisterFlags::Field &lhs,
- const RegisterFlags::Field &rhs) {
+ [](const RegisterTypeFlags::Field &lhs,
+ const RegisterTypeFlags::Field &rhs) {
return lhs.Overlaps(rhs);
});
@@ -4890,12 +4894,12 @@ void ParseFlags(
id->data());
} else {
registers_flags_types.insert_or_assign(
- *id, std::make_unique<RegisterFlags>(id->str(), *size,
- std::move(fields)));
+ *id, std::make_unique<RegisterTypeFlags>(
+ 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::vector<RegisterTypeFlags::Field>::const_iterator next =
std::next(overlap);
LLDB_LOG(
log,
@@ -4922,8 +4926,8 @@ void ParseFlags(
bool ParseRegisters(
XMLNode feature_node, GdbServerTargetInfo &target_info,
std::vector<DynamicRegisterInfo::Register> ®isters,
- llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types,
- llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) {
+ llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> ®isters_flags_types,
+ llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> ®isters_enum_types) {
if (!feature_node)
return false;
@@ -5019,7 +5023,7 @@ bool ParseRegisters(
if (!gdb_type.empty()) {
// gdb_type could reference some flags type defined in XML.
- llvm::StringMap<std::unique_ptr<RegisterFlags>>::iterator it =
+ llvm::StringMap<std::unique_ptr<RegisterTypeFlags>>::iterator it =
registers_flags_types.find(gdb_type);
if (it != registers_flags_types.end()) {
auto flags_type = it->second.get();
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 7c2877fa71d49..64957b04bd332 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -518,18 +518,18 @@ class ProcessGDBRemote : public Process,
lldb::ThreadSP thread_sp);
// Lists of register fields generated from the remote's target XML.
- // Pointers to these RegisterFlags will be set in the register info passed
+ // Pointers to these RegisterTypeFlags will be set in the register info passed
// back to the upper levels of lldb. Doing so is safe because this class will
// live at least as long as the debug session. We therefore do not store the
// data directly in the map because the map may reallocate it's storage as new
// entries are added. Which would invalidate any pointers set in the register
// info up to that point.
- llvm::StringMap<std::unique_ptr<RegisterFlags>> m_registers_flags_types;
+ llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> m_registers_flags_types;
// Enum types are referenced by register fields. This does not store the data
// directly because the map may reallocate. Pointers to these are contained
- // within instances of RegisterFlags.
- llvm::StringMap<std::unique_ptr<FieldEnum>> m_registers_enum_types;
+ // within instances of RegisterTypeFlags.
+ llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> m_registers_enum_types;
};
} // namespace process_gdb_remote
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index e809973766604..edeae122786a2 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -11,7 +11,7 @@
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "RegisterTypeBuilderClang.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb_private;
@@ -36,7 +36,7 @@ RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
: m_target(target) {}
CompilerType RegisterTypeBuilderClang::GetRegisterType(
- const std::string &name, const lldb_private::RegisterFlags &flags,
+ const std::string &name, const lldb_private::RegisterTypeFlags &flags,
uint32_t byte_size) {
lldb::TypeSystemClangSP type_system = ScratchTypeSystemClang::GetForTarget(
m_target, ScratchTypeSystemClang::IsolatedASTKind::Registers);
@@ -69,11 +69,12 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// We assume that RegisterFlags has padded and sorted the fields
// already.
- for (const RegisterFlags::Field &field : flags.GetFields()) {
+ for (const RegisterTypeFlags::Field &field : flags.GetFields()) {
CompilerType field_type = field_uint_type;
- if (const FieldEnum *enum_type = field.GetEnum()) {
- const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
+ if (const RegisterTypeEnum *enum_type = field.GetEnum()) {
+ const RegisterTypeEnum::Enumerators &enumerators =
+ enum_type->GetEnumerators();
if (!enumerators.empty()) {
// Enums can be used by many registers and the size of each register
// may be different. The register size is used as the underlying size
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index d346f79acceb8..5dee428aff8bd 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -31,7 +31,7 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
static lldb::RegisterTypeBuilderSP CreateInstance(Target &target);
CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterFlags &flags,
+ const lldb_private::RegisterTypeFlags &flags,
uint32_t byte_size) override;
private:
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index 28ddbafb379f6..dc2f259e87544 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -38,7 +38,7 @@ add_lldb_library(lldbTarget
QueueList.cpp
RegisterContext.cpp
RegisterContextUnwind.cpp
- RegisterFlags.cpp
+ RegisterTypeFlags.cpp
RegisterType.cpp
RegisterNumber.cpp
RemoteAwarePlatform.cpp
diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterTypeFlags.cpp
similarity index 81%
rename from lldb/source/Target/RegisterFlags.cpp
rename to lldb/source/Target/RegisterTypeFlags.cpp
index 4d66d9a18d0dd..bafa16e99ba72 100644
--- a/lldb/source/Target/RegisterFlags.cpp
+++ b/lldb/source/Target/RegisterTypeFlags.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterFlags.cpp -------------------------------------------------===//
+//===-- RegisterTypeFlags.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
@@ -19,18 +19,18 @@
using namespace lldb_private;
-RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end)
+RegisterTypeFlags::Field::Field(std::string name, unsigned start, unsigned end)
: m_name(std::move(name)), m_start(start), m_end(end),
m_enum_type(nullptr) {
assert(m_start <= m_end && "Start bit must be <= end bit.");
}
-RegisterFlags::Field::Field(std::string name, unsigned bit_position)
+RegisterTypeFlags::Field::Field(std::string name, unsigned bit_position)
: m_name(std::move(name)), m_start(bit_position), m_end(bit_position),
m_enum_type(nullptr) {}
-RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end,
- const FieldEnum *enum_type)
+RegisterTypeFlags::Field::Field(std::string name, unsigned start, unsigned end,
+ const RegisterTypeEnum *enum_type)
: m_name(std::move(name)), m_start(start), m_end(end),
m_enum_type(enum_type) {
if (m_enum_type) {
@@ -48,18 +48,18 @@ RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end,
}
}
-void RegisterFlags::Field::DumpToLog(Log *log) const {
+void RegisterTypeFlags::Field::DumpToLog(Log *log) const {
LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start,
m_end);
}
-bool RegisterFlags::Field::Overlaps(const Field &other) const {
+bool RegisterTypeFlags::Field::Overlaps(const Field &other) const {
unsigned overlap_start = std::max(GetStart(), other.GetStart());
unsigned overlap_end = std::min(GetEnd(), other.GetEnd());
return overlap_start <= overlap_end;
}
-unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
+unsigned RegisterTypeFlags::Field::PaddingDistance(const Field &other) const {
assert(!Overlaps(other) &&
"Cannot get padding distance for overlapping fields.");
assert((other < (*this)) && "Expected fields in MSB to LSB order.");
@@ -79,15 +79,15 @@ unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const {
return lhs_start - rhs_end - 1;
}
-unsigned RegisterFlags::Field::GetSizeInBits(unsigned start, unsigned end) {
+unsigned RegisterTypeFlags::Field::GetSizeInBits(unsigned start, unsigned end) {
return end - start + 1;
}
-unsigned RegisterFlags::Field::GetSizeInBits() const {
+unsigned RegisterTypeFlags::Field::GetSizeInBits() const {
return GetSizeInBits(m_start, m_end);
}
-uint64_t RegisterFlags::Field::GetMaxValue(unsigned start, unsigned end) {
+uint64_t RegisterTypeFlags::Field::GetMaxValue(unsigned start, unsigned end) {
uint64_t max = std::numeric_limits<uint64_t>::max();
unsigned bits = GetSizeInBits(start, end);
// If the field is >= 64 bits the shift below would be undefined.
@@ -100,15 +100,15 @@ uint64_t RegisterFlags::Field::GetMaxValue(unsigned start, unsigned end) {
return max;
}
-uint64_t RegisterFlags::Field::GetMaxValue() const {
+uint64_t RegisterTypeFlags::Field::GetMaxValue() const {
return GetMaxValue(m_start, m_end);
}
-uint64_t RegisterFlags::Field::GetMask() const {
+uint64_t RegisterTypeFlags::Field::GetMask() const {
return GetMaxValue() << m_start;
}
-void RegisterFlags::SetFields(const std::vector<Field> &fields) {
+void RegisterTypeFlags::SetFields(const std::vector<Field> &fields) {
// We expect that these are unsorted but do not overlap.
// They could fill the register but may have gaps.
m_fields = fields;
@@ -120,13 +120,13 @@ void RegisterFlags::SetFields(const std::vector<Field> &fields) {
SetDependencies(dependencies);
}
-RegisterFlags::RegisterFlags(std::string id, unsigned size,
- const std::vector<Field> &fields)
+RegisterTypeFlags::RegisterTypeFlags(std::string id, unsigned size,
+ const std::vector<Field> &fields)
: RegisterType(RegisterType::eRegisterTypeKindFlags, id), m_size(size) {
SetFields(fields);
}
-void RegisterFlags::DumpToLog(Log *log) const {
+void RegisterTypeFlags::DumpToLog(Log *log) const {
LLDB_LOG(log, "ID: \"{0}\" Size: {1}", GetID().c_str(), m_size);
for (const Field &field : m_fields)
field.DumpToLog(log);
@@ -159,7 +159,7 @@ static void EmitTable(std::string &out, std::array<std::string, 3> &table) {
});
}
-static void EmitField(const RegisterFlags::Field &field, uint32_t max_width,
+static void EmitField(const RegisterTypeFlags::Field &field, uint32_t max_width,
uint32_t ¤t_width, std::string &table,
std::array<std::string, 3> &lines) {
StreamString position;
@@ -203,20 +203,19 @@ static void EmitField(const RegisterFlags::Field &field, uint32_t max_width,
current_width += column_width + 1;
}
-std::string RegisterFlags::AsTable(uint32_t max_width) const {
+std::string RegisterTypeFlags::AsTable(uint32_t max_width) const {
std::string table;
// position / gridline / name
std::array<std::string, 3> lines;
uint32_t current_width = 0;
- std::optional<RegisterFlags::Field> previous_field = std::nullopt;
+ std::optional<Field> previous_field = std::nullopt;
- for (const RegisterFlags::Field &field : m_fields) {
+ for (const Field &field : m_fields) {
if (previous_field) {
// If there is a gap between this field and the last, fill it with an
// anonymous field.
if (previous_field->PaddingDistance(field))
- EmitField(RegisterFlags::Field("", field.GetEnd() + 1,
- previous_field->GetStart() - 1),
+ EmitField(Field("", field.GetEnd() + 1, previous_field->GetStart() - 1),
max_width, current_width, table, lines);
}
@@ -226,8 +225,8 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const {
// If the last field did not extend to bit 0, pad down to bit 0.
if (previous_field && previous_field->GetStart() != 0)
- EmitField(RegisterFlags::Field("", 0, previous_field->GetStart() - 1),
- max_width, current_width, table, lines);
+ EmitField(Field("", 0, previous_field->GetStart() - 1), max_width,
+ current_width, table, lines);
// If we didn't overflow and still have table to print out.
if (lines[0].size())
@@ -241,7 +240,7 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const {
// Subject to the limits of the terminal width.
static void DumpEnumerators(StreamString &strm, size_t indent,
size_t current_width, uint32_t max_width,
- const FieldEnum::Enumerators &enumerators) {
+ const RegisterTypeEnum::Enumerators &enumerators) {
for (auto it = enumerators.cbegin(); it != enumerators.cend(); ++it) {
StreamString enumerator_strm;
// The first enumerator of a line doesn't need to be separated.
@@ -281,16 +280,17 @@ static void DumpEnumerators(StreamString &strm, size_t indent,
}
}
-std::string RegisterFlags::DumpEnums(uint32_t max_width) const {
+std::string RegisterTypeFlags::DumpEnums(uint32_t max_width) const {
StreamString strm;
bool printed_enumerators_once = false;
for (const auto &field : m_fields) {
- const FieldEnum *enum_type = field.GetEnum();
+ const RegisterTypeEnum *enum_type = field.GetEnum();
if (!enum_type)
continue;
- const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators();
+ const RegisterTypeEnum::Enumerators &enumerators =
+ enum_type->GetEnumerators();
if (enumerators.empty())
continue;
@@ -312,7 +312,8 @@ std::string RegisterFlags::DumpEnums(uint32_t max_width) const {
return strm.GetString().str();
}
-void FieldEnum::ToXMLElement(Stream &strm, const RegisterType *user) const {
+void RegisterTypeEnum::ToXMLElement(Stream &strm,
+ const RegisterType *user) const {
// Example XML:
// <enum id="foo" size="4">
// <evalue name="bar" value="1"/>
@@ -324,8 +325,8 @@ void FieldEnum::ToXMLElement(Stream &strm, const RegisterType *user) const {
// We don't expect the user of an enum type to be anything but a register,
// but we cannot crash if that isn't true.
- if (const RegisterFlags *flags_type =
- llvm::dyn_cast_if_present<RegisterFlags>(user)) {
+ if (const RegisterTypeFlags *flags_type =
+ llvm::dyn_cast_if_present<RegisterTypeFlags>(user)) {
// This is the size of the underlying enum type if this were a C type.
// In other words, the size of the register in bytes.
strm.Printf(" size=\"%d\"", flags_type->GetSize());
@@ -348,7 +349,7 @@ void FieldEnum::ToXMLElement(Stream &strm, const RegisterType *user) const {
strm.Indent("</enum>\n");
}
-void FieldEnum::Enumerator::ToXMLElement(Stream &strm) const {
+void RegisterTypeEnum::Enumerator::ToXMLElement(Stream &strm) const {
std::string escaped_name;
llvm::raw_string_ostream escape_strm(escaped_name);
llvm::printHTMLEscaped(m_name, escape_strm);
@@ -356,17 +357,18 @@ void FieldEnum::Enumerator::ToXMLElement(Stream &strm) const {
escaped_name.c_str(), m_value);
}
-void FieldEnum::Enumerator::DumpToLog(Log *log) const {
+void RegisterTypeEnum::Enumerator::DumpToLog(Log *log) const {
LLDB_LOG(log, " Name: \"{0}\" Value: {1}", m_name.c_str(), m_value);
}
-void FieldEnum::DumpToLog(Log *log) const {
+void RegisterTypeEnum::DumpToLog(Log *log) const {
LLDB_LOG(log, "ID: \"{0}\"", GetID().c_str());
for (const auto &enumerator : GetEnumerators())
enumerator.DumpToLog(log);
}
-void RegisterFlags::ToXMLElement(Stream &strm, const RegisterType *user) const {
+void RegisterTypeFlags::ToXMLElement(Stream &strm,
+ const RegisterType *user) const {
(void)user;
// Example XML:
// <flags id="cpsr_flags" size="4">
@@ -390,7 +392,7 @@ void RegisterFlags::ToXMLElement(Stream &strm, const RegisterType *user) const {
strm.Indent("</flags>\n");
}
-void RegisterFlags::Field::ToXMLElement(Stream &strm) const {
+void RegisterTypeFlags::Field::ToXMLElement(Stream &strm) const {
// Example XML with an enum:
// <field name="correct" start="0" end="0" type="some_enum">
// Without:
@@ -405,13 +407,14 @@ void RegisterFlags::Field::ToXMLElement(Stream &strm) const {
strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd());
- if (const FieldEnum *enum_type = GetEnum())
+ if (const RegisterTypeEnum *enum_type = GetEnum())
strm << " type=\"" << enum_type->GetID() << "\"";
strm << "/>";
}
-FieldEnum::FieldEnum(std::string id, const Enumerators &enumerators)
+RegisterTypeEnum::RegisterTypeEnum(std::string id,
+ const Enumerators &enumerators)
: RegisterType(RegisterType::eRegisterTypeKindEnum, id),
m_enumerators(enumerators) {
for (const auto &enumerator : m_enumerators) {
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index d7611f470b9b6..9680577b395ab 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -2631,9 +2631,10 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language,
create_on_demand);
}
-CompilerType Target::GetRegisterType(const std::string &name,
- const lldb_private::RegisterFlags &flags,
- uint32_t byte_size) {
+CompilerType
+Target::GetRegisterType(const std::string &name,
+ const lldb_private::RegisterTypeFlags &flags,
+ uint32_t byte_size) {
if (!m_register_type_builder_sp)
m_register_type_builder_sp = PluginManager::GetRegisterTypeBuilder(*this);
assert(m_register_type_builder_sp);
diff --git a/lldb/test/API/commands/register/register_command/TestRegisters.py b/lldb/test/API/commands/register/register_command/TestRegisters.py
index d7863a230cdb8..abe235f0b5adf 100644
--- a/lldb/test/API/commands/register/register_command/TestRegisters.py
+++ b/lldb/test/API/commands/register/register_command/TestRegisters.py
@@ -608,7 +608,7 @@ def test_info_register(self):
# The behaviour of this command is generic but the specific registers
# are not, so this is written for AArch64 only.
# Text alignment and ordering are checked in the DumpRegisterInfo and
- # RegisterFlags unit tests.
+ # RegisterTypeFlags unit tests.
self.build()
self.common_setup()
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
index cfd0bd638a1f8..f75343aa2d37b 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
@@ -41,7 +41,7 @@ def readRegisters(self):
)
-class TestXMLRegisterFlags(GDBRemoteTestBase):
+class TestXMLRegisterTypeFlags(GDBRemoteTestBase):
def setup_multidoc_test(self, docs):
self.server.responder = MultiDocResponder(docs)
target = self.dbg.CreateTarget("")
@@ -609,7 +609,7 @@ def test_xml_includes_flags_redefined(self):
@skipIfXmlSupportMissing
@skipIfRemote
def test_flags_in_register_info(self):
- # See RegisterFlags for comprehensive formatting tests.
+ # See RegisterTypeFlags for comprehensive formatting tests.
self.setup_flags_test(
'<field name="D" start="0" end="7"/>'
'<field name="C" start="8" end="15"/>'
diff --git a/lldb/unittests/Core/DumpRegisterInfoTest.cpp b/lldb/unittests/Core/DumpRegisterInfoTest.cpp
index 593170c2822ab..87c46de4e0406 100644
--- a/lldb/unittests/Core/DumpRegisterInfoTest.cpp
+++ b/lldb/unittests/Core/DumpRegisterInfoTest.cpp
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/DumpRegisterInfo.h"
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/StreamString.h"
#include "gtest/gtest.h"
@@ -86,13 +86,14 @@ TEST(DoDumpRegisterInfoTest, MaxInfo) {
}
TEST(DoDumpRegisterInfoTest, FieldsTable) {
- // This is thoroughly tested in RegisterFlags itself, only checking the
+ // This is thoroughly tested in RegisterTypeFlags itself, only checking the
// integration here.
StreamString strm;
- RegisterFlags flags(
- "", 4,
- {RegisterFlags::Field("A", 24, 31), RegisterFlags::Field("B", 16, 23),
- RegisterFlags::Field("C", 8, 15), RegisterFlags::Field("D", 0, 7)});
+ RegisterTypeFlags flags("", 4,
+ {RegisterTypeFlags::Field("A", 24, 31),
+ RegisterTypeFlags::Field("B", 16, 23),
+ RegisterTypeFlags::Field("C", 8, 15),
+ RegisterTypeFlags::Field("D", 0, 7)});
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {}, &flags, 100);
ASSERT_EQ(strm.GetString(), " Name: foo\n"
@@ -106,14 +107,14 @@ TEST(DoDumpRegisterInfoTest, FieldsTable) {
TEST(DoDumpRegisterInfoTest, Enumerators) {
StreamString strm;
- FieldEnum enum_one("enum_one", {{0, "an_enumerator"}});
- FieldEnum enum_two("enum_two",
- {{1, "another_enumerator"}, {2, "another_enumerator_2"}});
+ RegisterTypeEnum enum_one("enum_one", {{0, "an_enumerator"}});
+ RegisterTypeEnum enum_two(
+ "enum_two", {{1, "another_enumerator"}, {2, "another_enumerator_2"}});
- RegisterFlags flags("", 4,
- {RegisterFlags::Field("A", 24, 31, &enum_one),
- RegisterFlags::Field("B", 16, 23),
- RegisterFlags::Field("C", 8, 15, &enum_two)});
+ RegisterTypeFlags flags("", 4,
+ {RegisterTypeFlags::Field("A", 24, 31, &enum_one),
+ RegisterTypeFlags::Field("B", 16, 23),
+ RegisterTypeFlags::Field("C", 8, 15, &enum_two)});
DoDumpRegisterInfo(strm, "abc", nullptr, 4, {}, {}, {}, &flags, 100);
ASSERT_EQ(strm.GetString(),
diff --git a/lldb/unittests/Target/CMakeLists.txt b/lldb/unittests/Target/CMakeLists.txt
index bf08a8f015ba0..0c64be53bbfd9 100644
--- a/lldb/unittests/Target/CMakeLists.txt
+++ b/lldb/unittests/Target/CMakeLists.txt
@@ -9,7 +9,7 @@ add_lldb_unittest(TargetTests
MemoryTagMapTest.cpp
ModuleCacheTest.cpp
PathMappingListTest.cpp
- RegisterFlagsTest.cpp
+ RegisterTypeTest.cpp
RemoteAwarePlatformTest.cpp
ScratchTypeSystemTest.cpp
StackFrameRecognizerTest.cpp
diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterTypeTest.cpp
similarity index 61%
rename from lldb/unittests/Target/RegisterFlagsTest.cpp
rename to lldb/unittests/Target/RegisterTypeTest.cpp
index 1e99a26c78076..48e5f5128c9d2 100644
--- a/lldb/unittests/Target/RegisterFlagsTest.cpp
+++ b/lldb/unittests/Target/RegisterTypeTest.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterFlagsTest.cpp ---------------------------------------------===//
+//===-- RegisterTypeTest.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Target/RegisterFlags.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Utility/StreamString.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -16,10 +16,10 @@
using namespace lldb_private;
using namespace lldb;
-TEST(RegisterFlagsTest, Field) {
+TEST(RegisterTypeTest, Field) {
// We assume that start <= end is always true, so that is not tested here.
- RegisterFlags::Field f1("abc", 0);
+ RegisterTypeFlags::Field f1("abc", 0);
ASSERT_EQ(f1.GetName(), "abc");
// start == end means a 1 bit field.
ASSERT_EQ(f1.GetSizeInBits(), (unsigned)1);
@@ -27,13 +27,13 @@ TEST(RegisterFlagsTest, Field) {
// End is inclusive meaning that start 0 to end 1 includes bit 1
// to make a 2 bit field.
- RegisterFlags::Field f2("", 0, 1);
+ RegisterTypeFlags::Field f2("", 0, 1);
ASSERT_EQ(f2.GetSizeInBits(), (unsigned)2);
ASSERT_EQ(f2.GetMask(), (uint64_t)3);
// If the field doesn't start at 0 we need to shift up/down
// to account for it.
- RegisterFlags::Field f3("", 2, 5);
+ RegisterTypeFlags::Field f3("", 2, 5);
ASSERT_EQ(f3.GetSizeInBits(), (unsigned)4);
ASSERT_EQ(f3.GetMask(), (uint64_t)0x3c);
@@ -44,15 +44,15 @@ TEST(RegisterFlagsTest, Field) {
ASSERT_FALSE(f1 < f1);
}
-static RegisterFlags::Field make_field(unsigned start, unsigned end) {
- return RegisterFlags::Field("", start, end);
+static RegisterTypeFlags::Field make_field(unsigned start, unsigned end) {
+ return RegisterTypeFlags::Field("", start, end);
}
-static RegisterFlags::Field make_field(unsigned bit) {
- return RegisterFlags::Field("", bit);
+static RegisterTypeFlags::Field make_field(unsigned bit) {
+ return RegisterTypeFlags::Field("", bit);
}
-TEST(RegisterFlagsTest, FieldOverlaps) {
+TEST(RegisterTypeTest, FieldOverlaps) {
// Single bit fields
ASSERT_FALSE(make_field(0, 0).Overlaps(make_field(1)));
ASSERT_TRUE(make_field(1, 1).Overlaps(make_field(1)));
@@ -67,7 +67,7 @@ TEST(RegisterFlagsTest, FieldOverlaps) {
ASSERT_FALSE(make_field(15, 30).Overlaps(make_field(7, 12)));
}
-TEST(RegisterFlagsTest, PaddingDistance) {
+TEST(RegisterTypeTest, PaddingDistance) {
// We assume that this method is always called with a more significant
// (start bit is higher) field first and that they do not overlap.
@@ -81,46 +81,47 @@ TEST(RegisterFlagsTest, PaddingDistance) {
ASSERT_EQ(make_field(31, 31).PaddingDistance(make_field(0)), 30ULL);
}
-TEST(RegisterFlagsTest, AsTable) {
+TEST(RegisterTypeTest, AsTable) {
// Anonymous fields are shown with an empty name cell.
- RegisterFlags anon_field("", 4, {make_field(0, 31)});
+ RegisterTypeFlags anon_field("", 4, {make_field(0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
"| |",
anon_field.AsTable(100));
- RegisterFlags anon_with_pad("", 4, {make_field(16, 31)});
+ RegisterTypeFlags anon_with_pad("", 4, {make_field(16, 31)});
ASSERT_EQ("| 31-16 | 15-0 |\n"
"|-------|------|\n"
"| | |",
anon_with_pad.AsTable(100));
// Use the wider of position and name to set the column width.
- RegisterFlags name_wider("", 4, {RegisterFlags::Field("aardvark", 0, 31)});
+ RegisterTypeFlags name_wider("", 4,
+ {RegisterTypeFlags::Field("aardvark", 0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|----------|\n"
"| aardvark |",
name_wider.AsTable(100));
// When the padding is an odd number, put the remaining 1 on the right.
- RegisterFlags pos_wider("", 4, {RegisterFlags::Field("?", 0, 31)});
+ RegisterTypeFlags pos_wider("", 4, {RegisterTypeFlags::Field("?", 0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
"| ? |",
pos_wider.AsTable(100));
// Single bit fields don't need to show start and end, just one of them.
- RegisterFlags single_bit("", 4, {make_field(31)});
+ RegisterTypeFlags single_bit("", 4, {make_field(31)});
ASSERT_EQ("| 31 | 30-0 |\n"
"|----|------|\n"
"| | |",
single_bit.AsTable(100));
// Columns are printed horizontally if max width allows.
- RegisterFlags many_fields("", 4,
- {RegisterFlags::Field("cat", 28, 31),
- RegisterFlags::Field("pigeon", 20, 23),
- RegisterFlags::Field("wolf", 12),
- RegisterFlags::Field("x", 0, 4)});
+ RegisterTypeFlags many_fields("", 4,
+ {RegisterTypeFlags::Field("cat", 28, 31),
+ RegisterTypeFlags::Field("pigeon", 20, 23),
+ RegisterTypeFlags::Field("wolf", 12),
+ RegisterTypeFlags::Field("x", 0, 4)});
ASSERT_EQ("| 31-28 | 27-24 | 23-20 | 19-13 | 12 | 11-5 | 4-0 |\n"
"|-------|-------|--------|-------|------|------|-----|\n"
"| cat | | pigeon | | wolf | | x |",
@@ -128,14 +129,15 @@ TEST(RegisterFlagsTest, AsTable) {
// max_width tells us when we need to split into further tables.
// Here no split is needed.
- RegisterFlags exact_max_single_col("", 4, {RegisterFlags::Field("?", 0, 31)});
+ RegisterTypeFlags exact_max_single_col(
+ "", 4, {RegisterTypeFlags::Field("?", 0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
"| ? |",
exact_max_single_col.AsTable(9));
- RegisterFlags exact_max_two_col(
- "", 4,
- {RegisterFlags::Field("?", 16, 31), RegisterFlags::Field("#", 0, 15)});
+ RegisterTypeFlags exact_max_two_col("", 4,
+ {RegisterTypeFlags::Field("?", 16, 31),
+ RegisterTypeFlags::Field("#", 0, 15)});
ASSERT_EQ("| 31-16 | 15-0 |\n"
"|-------|------|\n"
"| ? | # |",
@@ -143,16 +145,17 @@ TEST(RegisterFlagsTest, AsTable) {
// If max is less than a single column, just print the single column. The user
// will have to put up with some wrapping in this niche case.
- RegisterFlags zero_max_single_col("", 4, {RegisterFlags::Field("?", 0, 31)});
+ RegisterTypeFlags zero_max_single_col("", 4,
+ {RegisterTypeFlags::Field("?", 0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
"| ? |",
zero_max_single_col.AsTable(0));
// Same logic for any following columns. Effectively making a "vertical"
// table, just with more grid lines.
- RegisterFlags zero_max_two_col(
- "", 4,
- {RegisterFlags::Field("?", 16, 31), RegisterFlags::Field("#", 0, 15)});
+ RegisterTypeFlags zero_max_two_col("", 4,
+ {RegisterTypeFlags::Field("?", 16, 31),
+ RegisterTypeFlags::Field("#", 0, 15)});
ASSERT_EQ("| 31-16 |\n"
"|-------|\n"
"| ? |\n"
@@ -162,15 +165,16 @@ TEST(RegisterFlagsTest, AsTable) {
"| # |",
zero_max_two_col.AsTable(0));
- RegisterFlags max_less_than_single_col("", 4,
- {RegisterFlags::Field("?", 0, 31)});
+ RegisterTypeFlags max_less_than_single_col(
+ "", 4, {RegisterTypeFlags::Field("?", 0, 31)});
ASSERT_EQ("| 31-0 |\n"
"|------|\n"
"| ? |",
max_less_than_single_col.AsTable(3));
- RegisterFlags max_less_than_two_col(
+ RegisterTypeFlags max_less_than_two_col(
"", 4,
- {RegisterFlags::Field("?", 16, 31), RegisterFlags::Field("#", 0, 15)});
+ {RegisterTypeFlags::Field("?", 16, 31),
+ RegisterTypeFlags::Field("#", 0, 15)});
ASSERT_EQ("| 31-16 |\n"
"|-------|\n"
"| ? |\n"
@@ -179,11 +183,12 @@ TEST(RegisterFlagsTest, AsTable) {
"|------|\n"
"| # |",
max_less_than_two_col.AsTable(9));
- RegisterFlags max_many_columns(
+ RegisterTypeFlags max_many_columns(
"", 4,
- {RegisterFlags::Field("A", 24, 31), RegisterFlags::Field("B", 16, 23),
- RegisterFlags::Field("C", 8, 15),
- RegisterFlags::Field("really long name", 0, 7)});
+ {RegisterTypeFlags::Field("A", 24, 31),
+ RegisterTypeFlags::Field("B", 16, 23),
+ RegisterTypeFlags::Field("C", 8, 15),
+ RegisterTypeFlags::Field("really long name", 0, 7)});
ASSERT_EQ("| 31-24 | 23-16 |\n"
"|-------|-------|\n"
"| A | B |\n"
@@ -198,28 +203,32 @@ TEST(RegisterFlagsTest, AsTable) {
max_many_columns.AsTable(23));
}
-TEST(RegisterFlagsTest, DumpEnums) {
- ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0}}).DumpEnums(80),
+TEST(RegisterTypeTest, DumpEnums) {
+ ASSERT_EQ(RegisterTypeFlags("", 8, {RegisterTypeFlags::Field{"A", 0}})
+ .DumpEnums(80),
"");
- FieldEnum basic_enum("test", {{0, "an_enumerator"}});
- ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 0, &basic_enum}})
+ RegisterTypeEnum basic_enum("test", {{0, "an_enumerator"}});
+ ASSERT_EQ(RegisterTypeFlags(
+ "", 8, {RegisterTypeFlags::Field{"A", 0, 0, &basic_enum}})
.DumpEnums(80),
"A: 0 = an_enumerator");
// If width is smaller than the enumerator name, print it anyway.
- ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 0, &basic_enum}})
+ ASSERT_EQ(RegisterTypeFlags(
+ "", 8, {RegisterTypeFlags::Field{"A", 0, 0, &basic_enum}})
.DumpEnums(5),
"A: 0 = an_enumerator");
- // Multiple values can go on the same line, up to the width.
- FieldEnum more_enum("long_enum",
- {{0, "an_enumerator"},
- {1, "another_enumerator"},
- {2, "a_very_very_long_enumerator_has_its_own_line"},
- {3, "small"},
- {4, "small2"}});
- ASSERT_EQ(RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 2, &more_enum}})
+ // Mutliple values can go on the same line, up to the width.
+ RegisterTypeEnum more_enum(
+ "long_enum", {{0, "an_enumerator"},
+ {1, "another_enumerator"},
+ {2, "a_very_very_long_enumerator_has_its_own_line"},
+ {3, "small"},
+ {4, "small2"}});
+ ASSERT_EQ(RegisterTypeFlags("", 8,
+ {RegisterTypeFlags::Field{"A", 0, 2, &more_enum}})
// Width is chosen to be exactly enough to allow 0 and 1
// enumerators on the first line.
.DumpEnums(45),
@@ -228,21 +237,21 @@ TEST(RegisterFlagsTest, DumpEnums) {
" 3 = small, 4 = small2");
// If they all exceed width, one per line.
- FieldEnum another_enum("another_enum", {{0, "an_enumerator"},
- {1, "another_enumerator"},
- {2, "a_longer_enumerator"}});
- ASSERT_EQ(
- RegisterFlags("", 8, {RegisterFlags::Field{"A", 0, 1, &another_enum}})
- .DumpEnums(5),
- "A: 0 = an_enumerator,\n"
- " 1 = another_enumerator,\n"
- " 2 = a_longer_enumerator");
+ RegisterTypeEnum another_enum("another_enum", {{0, "an_enumerator"},
+ {1, "another_enumerator"},
+ {2, "a_longer_enumerator"}});
+ ASSERT_EQ(RegisterTypeFlags(
+ "", 8, {RegisterTypeFlags::Field{"A", 0, 1, &another_enum}})
+ .DumpEnums(5),
+ "A: 0 = an_enumerator,\n"
+ " 1 = another_enumerator,\n"
+ " 2 = a_longer_enumerator");
// If the name is already > the width, put one value per line.
- FieldEnum short_enum("short_enum", {{0, "a"}, {1, "b"}, {2, "c"}});
- ASSERT_EQ(RegisterFlags("", 8,
- {RegisterFlags::Field{"AReallyLongFieldName", 0, 1,
- &short_enum}})
+ RegisterTypeEnum short_enum("short_enum", {{0, "a"}, {1, "b"}, {2, "c"}});
+ ASSERT_EQ(RegisterTypeFlags("", 8,
+ {RegisterTypeFlags::Field{"AReallyLongFieldName",
+ 0, 1, &short_enum}})
.DumpEnums(10),
"AReallyLongFieldName: 0 = a,\n"
" 1 = b,\n"
@@ -251,12 +260,13 @@ TEST(RegisterFlagsTest, DumpEnums) {
// Fields are separated by a blank line. Indentation of lines split by width
// is set by the size of the fields name (as opposed to some max of all field
// names).
- FieldEnum enum_1("enum_1", {{0, "an_enumerator"}, {1, "another_enumerator"}});
- FieldEnum enum_2("enum_2",
- {{0, "Cdef_enumerator_1"}, {1, "Cdef_enumerator_2"}});
- ASSERT_EQ(RegisterFlags("", 8,
- {RegisterFlags::Field{"Ab", 1, 1, &enum_1},
- RegisterFlags::Field{"Cdef", 0, 0, &enum_2}})
+ RegisterTypeEnum enum_1("enum_1",
+ {{0, "an_enumerator"}, {1, "another_enumerator"}});
+ RegisterTypeEnum enum_2("enum_2",
+ {{0, "Cdef_enumerator_1"}, {1, "Cdef_enumerator_2"}});
+ ASSERT_EQ(RegisterTypeFlags("", 8,
+ {RegisterTypeFlags::Field{"Ab", 1, 1, &enum_1},
+ RegisterTypeFlags::Field{"Cdef", 0, 0, &enum_2}})
.DumpEnums(10),
"Ab: 0 = an_enumerator,\n"
" 1 = another_enumerator\n"
@@ -265,14 +275,14 @@ TEST(RegisterFlagsTest, DumpEnums) {
" 1 = Cdef_enumerator_2");
// Having fields without enumerators shouldn't produce any extra newlines.
- ASSERT_EQ(RegisterFlags("", 8,
- {
- RegisterFlags::Field{"A", 4, 4},
- RegisterFlags::Field{"B", 3, 3, &enum_1},
- RegisterFlags::Field{"C", 2, 2},
- RegisterFlags::Field{"D", 1, 1, &enum_1},
- RegisterFlags::Field{"E", 0, 0},
- })
+ ASSERT_EQ(RegisterTypeFlags("", 8,
+ {
+ RegisterTypeFlags::Field{"A", 4, 4},
+ RegisterTypeFlags::Field{"B", 3, 3, &enum_1},
+ RegisterTypeFlags::Field{"C", 2, 2},
+ RegisterTypeFlags::Field{"D", 1, 1, &enum_1},
+ RegisterTypeFlags::Field{"E", 0, 0},
+ })
.DumpEnums(80),
"B: 0 = an_enumerator, 1 = another_enumerator\n"
"\n"
@@ -282,17 +292,18 @@ TEST(RegisterFlagsTest, DumpEnums) {
TEST(RegisterFieldsTest, FlagsToXMLElement) {
StreamString strm;
- // RegisterFlags requires that some fields be given, so no testing of empty
- // input.
+ // RegisterTypeFlags requires that some fields be given, so no testing of
+ // empty input.
// Unnamed fields are padding that are ignored. This applies to fields passed
// in, and those generated to fill the other bits (31-1 here).
- RegisterFlags("Foo", 4, {RegisterFlags::Field("", 0, 0)}).ToXMLElement(strm);
+ RegisterTypeFlags("Foo", 4, {RegisterTypeFlags::Field("", 0, 0)})
+ .ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
"</flags>\n");
strm.Clear();
- RegisterFlags("Foo", 4, {RegisterFlags::Field("abc", 0, 0)})
+ RegisterTypeFlags("Foo", 4, {RegisterTypeFlags::Field("abc", 0, 0)})
.ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n"
" <field name=\"abc\" start=\"0\" end=\"0\"/>\n"
@@ -301,9 +312,9 @@ TEST(RegisterFieldsTest, FlagsToXMLElement) {
strm.Clear();
// Should use the current indentation level as a starting point.
strm.IndentMore();
- RegisterFlags(
- "Bar", 5,
- {RegisterFlags::Field("f1", 25, 32), RegisterFlags::Field("f2", 10, 24)})
+ RegisterTypeFlags("Bar", 5,
+ {RegisterTypeFlags::Field("f1", 25, 32),
+ RegisterTypeFlags::Field("f2", 10, 24)})
.ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
" <flags id=\"Bar\" size=\"5\">\n"
@@ -314,10 +325,11 @@ TEST(RegisterFieldsTest, FlagsToXMLElement) {
strm.Clear();
strm.IndentLess();
// Should replace any XML unsafe characters in field names.
- RegisterFlags("Safe", 8,
- {RegisterFlags::Field("A<", 4), RegisterFlags::Field("B>", 3),
- RegisterFlags::Field("C'", 2), RegisterFlags::Field("D\"", 1),
- RegisterFlags::Field("E&", 0)})
+ RegisterTypeFlags(
+ "Safe", 8,
+ {RegisterTypeFlags::Field("A<", 4), RegisterTypeFlags::Field("B>", 3),
+ RegisterTypeFlags::Field("C'", 2), RegisterTypeFlags::Field("D\"", 1),
+ RegisterTypeFlags::Field("E&", 0)})
.ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
"<flags id=\"Safe\" size=\"8\">\n"
@@ -330,10 +342,11 @@ TEST(RegisterFieldsTest, FlagsToXMLElement) {
// Should include enumerators as the "type".
strm.Clear();
- FieldEnum enum_single("enum_single", {{0, "a"}});
- RegisterFlags("Enumerators", 8,
- {RegisterFlags::Field("NoEnumerators", 4),
- RegisterFlags::Field("OneEnumerator", 3, 3, &enum_single)})
+ RegisterTypeEnum enum_single("enum_single", {{0, "a"}});
+ RegisterTypeFlags(
+ "Enumerators", 8,
+ {RegisterTypeFlags::Field("NoEnumerators", 4),
+ RegisterTypeFlags::Field("OneEnumerator", 3, 3, &enum_single)})
.ToXMLElement(strm);
ASSERT_EQ(strm.GetString(),
"<flags id=\"Enumerators\" size=\"8\">\n"
@@ -343,23 +356,23 @@ TEST(RegisterFieldsTest, FlagsToXMLElement) {
"</flags>\n");
}
-TEST(RegisterFlagsTest, EnumeratorToXMLElement) {
+TEST(RegisterTypeTest, EnumeratorToXMLElement) {
StreamString strm;
- FieldEnum::Enumerator(1234, "test").ToXMLElement(strm);
+ RegisterTypeEnum::Enumerator(1234, "test").ToXMLElement(strm);
ASSERT_EQ(strm.GetString(), "<evalue name=\"test\" value=\"1234\"/>");
// Special XML chars in names must be escaped.
std::array special_names = {
- std::make_pair(FieldEnum::Enumerator(0, "A<"),
+ std::make_pair(RegisterTypeEnum::Enumerator(0, "A<"),
"<evalue name=\"A<\" value=\"0\"/>"),
- std::make_pair(FieldEnum::Enumerator(1, "B>"),
+ std::make_pair(RegisterTypeEnum::Enumerator(1, "B>"),
"<evalue name=\"B>\" value=\"1\"/>"),
- std::make_pair(FieldEnum::Enumerator(2, "C'"),
+ std::make_pair(RegisterTypeEnum::Enumerator(2, "C'"),
"<evalue name=\"C'\" value=\"2\"/>"),
- std::make_pair(FieldEnum::Enumerator(3, "D\""),
+ std::make_pair(RegisterTypeEnum::Enumerator(3, "D\""),
"<evalue name=\"D"\" value=\"3\"/>"),
- std::make_pair(FieldEnum::Enumerator(4, "E&"),
+ std::make_pair(RegisterTypeEnum::Enumerator(4, "E&"),
"<evalue name=\"E&\" value=\"4\"/>"),
};
@@ -370,17 +383,18 @@ TEST(RegisterFlagsTest, EnumeratorToXMLElement) {
}
}
-TEST(RegisterFlagsTest, EnumToXMLElement) {
+TEST(RegisterTypeTest, EnumToXMLElement) {
StreamString strm;
- RegisterFlags user_4("Foo", 4, {RegisterFlags::Field("", 0, 0)});
- FieldEnum("empty_enum", {})
+ RegisterTypeFlags user_4("Foo", 4, {RegisterTypeFlags::Field("", 0, 0)});
+ RegisterTypeEnum("empty_enum", {})
.ToXMLElement(strm, llvm::dyn_cast<const RegisterType>(&user_4));
ASSERT_EQ(strm.GetString(), "<enum id=\"empty_enum\" size=\"4\"/>\n");
strm.Clear();
- RegisterFlags user_5("Foo", 5, {RegisterFlags::Field("", 0, 0)});
- FieldEnum("single_enumerator", {FieldEnum::Enumerator(0, "zero")})
+ RegisterTypeFlags user_5("Foo", 5, {RegisterTypeFlags::Field("", 0, 0)});
+ RegisterTypeEnum("single_enumerator",
+ {RegisterTypeEnum::Enumerator(0, "zero")})
.ToXMLElement(strm, llvm::dyn_cast<const RegisterType>(&user_5));
ASSERT_EQ(strm.GetString(), "<enum id=\"single_enumerator\" size=\"5\">\n"
" <evalue name=\"zero\" value=\"0\"/>\n"
@@ -389,8 +403,9 @@ TEST(RegisterFlagsTest, EnumToXMLElement) {
// Currently we don't emit size if the user of this type is not a flags.
// We don't expect to see this situation in real use.
strm.Clear();
- FieldEnum("multiple_enumerator",
- {FieldEnum::Enumerator(0, "zero"), FieldEnum::Enumerator(1, "one")})
+ RegisterTypeEnum("multiple_enumerator",
+ {RegisterTypeEnum::Enumerator(0, "zero"),
+ RegisterTypeEnum::Enumerator(1, "one")})
.ToXMLElement(strm, nullptr);
ASSERT_EQ(strm.GetString(), "<enum id=\"multiple_enumerator\">\n"
" <evalue name=\"zero\" value=\"0\"/>\n"
@@ -398,27 +413,27 @@ TEST(RegisterFlagsTest, EnumToXMLElement) {
"</enum>\n");
}
-TEST(RegisterFlagsTest, RegisterFlagsToXML) {
+TEST(RegisterTypeTest, RegisterTypeFlagsToXML) {
// This method should output all the enums used by the register flag set,
// then the flags set itself. There should only be one definition of each
// enum, even if it is used by multiple fields.
StreamString strm;
- FieldEnum enum_a("enum_a", {FieldEnum::Enumerator(0, "zero")});
- FieldEnum enum_b("enum_b", {FieldEnum::Enumerator(1, "one")});
- FieldEnum enum_c("enum_c", {FieldEnum::Enumerator(2, "two")});
+ RegisterTypeEnum enum_a("enum_a", {RegisterTypeEnum::Enumerator(0, "zero")});
+ RegisterTypeEnum enum_b("enum_b", {RegisterTypeEnum::Enumerator(1, "one")});
+ RegisterTypeEnum enum_c("enum_c", {RegisterTypeEnum::Enumerator(2, "two")});
std::unordered_set<const RegisterType *> previously_emitted;
// Pretend that enum_c was already emitted for a different flag set.
previously_emitted.insert(&enum_c);
- std::vector<RegisterFlags::Field> fields{
- RegisterFlags::Field("f1", 31, 31, &enum_a),
- RegisterFlags::Field("f2", 30, 30, &enum_a),
- RegisterFlags::Field("f3", 29, 29, &enum_b),
- RegisterFlags::Field("f4", 27, 28, &enum_c),
+ std::vector<RegisterTypeFlags::Field> fields{
+ RegisterTypeFlags::Field("f1", 31, 31, &enum_a),
+ RegisterTypeFlags::Field("f2", 30, 30, &enum_a),
+ RegisterTypeFlags::Field("f3", 29, 29, &enum_b),
+ RegisterTypeFlags::Field("f4", 27, 28, &enum_c),
};
- RegisterFlags("Test", 4, fields).ToXML(strm, previously_emitted);
+ RegisterTypeFlags("Test", 4, fields).ToXML(strm, previously_emitted);
ASSERT_EQ(strm.GetString(),
"<enum id=\"enum_a\" size=\"4\">\n"
" <evalue name=\"zero\" value=\"0\"/>\n"
@@ -436,9 +451,9 @@ TEST(RegisterFlagsTest, RegisterFlagsToXML) {
// If another flag set were to use the same enums we should not output them
// again. Only output anything new.
strm.Clear();
- FieldEnum enum_d("enum_d", {FieldEnum::Enumerator(3, "three")});
- fields.push_back(RegisterFlags::Field("f5", 25, 26, &enum_d));
- RegisterFlags("Test", 4, fields).ToXML(strm, previously_emitted);
+ RegisterTypeEnum enum_d("enum_d", {RegisterTypeEnum::Enumerator(3, "three")});
+ fields.push_back(RegisterTypeFlags::Field("f5", 25, 26, &enum_d));
+ RegisterTypeFlags("Test", 4, fields).ToXML(strm, previously_emitted);
ASSERT_EQ(strm.GetString(),
"<enum id=\"enum_d\" size=\"4\">\n"
" <evalue name=\"three\" value=\"3\"/>\n"
diff --git a/llvm/utils/gn/secondary/lldb/source/Target/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Target/BUILD.gn
index ac63bbc6ee3b3..c162bc02d7abe 100644
--- a/llvm/utils/gn/secondary/lldb/source/Target/BUILD.gn
+++ b/llvm/utils/gn/secondary/lldb/source/Target/BUILD.gn
@@ -60,7 +60,7 @@ static_library("Target") {
"QueueList.cpp",
"RegisterContext.cpp",
"RegisterContextUnwind.cpp",
- "RegisterFlags.cpp",
+ "RegisterTypeFlags.cpp",
"RegisterNumber.cpp",
"RemoteAwarePlatform.cpp",
"ScriptedThreadPlan.cpp",
>From 8b6affe3eee40153f0a0efbbd420bec80270ace3 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Tue, 3 Sep 2024 10:11:22 +0000
Subject: [PATCH 05/16] [lldb] Convert uses of RegisterTypeFlags into
RegisterType
So we are using the generic interface that will work with
all future RegisterType derived classes.
Right now we'll only be asked to print RegisterTypeFlags, so
there's a few dyn_cast to that. Later we will switch on the
kind, and support rendering more types.
---
lldb/include/lldb/Core/DumpRegisterInfo.h | 4 +--
.../include/lldb/Target/DynamicRegisterInfo.h | 4 +--
.../include/lldb/Target/RegisterTypeBuilder.h | 2 +-
lldb/include/lldb/Target/Target.h | 2 +-
lldb/source/Core/DumpRegisterInfo.cpp | 5 +--
lldb/source/Core/DumpRegisterValue.cpp | 32 ++++++++++---------
.../Process/gdb-remote/ProcessGDBRemote.cpp | 2 +-
.../Process/gdb-remote/ProcessGDBRemote.h | 1 +
.../RegisterTypeBuilderClang.cpp | 12 +++++--
.../RegisterTypeBuilderClang.h | 2 +-
lldb/source/Target/DynamicRegisterInfo.cpp | 2 +-
lldb/source/Target/Target.cpp | 5 +--
lldb/unittests/Core/DumpRegisterInfoTest.cpp | 8 +++--
13 files changed, 48 insertions(+), 33 deletions(-)
diff --git a/lldb/include/lldb/Core/DumpRegisterInfo.h b/lldb/include/lldb/Core/DumpRegisterInfo.h
index 06b4d71940236..6021456bb8a41 100644
--- a/lldb/include/lldb/Core/DumpRegisterInfo.h
+++ b/lldb/include/lldb/Core/DumpRegisterInfo.h
@@ -18,7 +18,7 @@ namespace lldb_private {
class Stream;
class RegisterContext;
struct RegisterInfo;
-class RegisterTypeFlags;
+class RegisterType;
void DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
const RegisterInfo &info, uint32_t terminal_width);
@@ -29,7 +29,7 @@ void DoDumpRegisterInfo(
const std::vector<const char *> &invalidates,
const std::vector<const char *> &read_from,
const std::vector<std::pair<const char *, uint32_t>> &in_sets,
- const RegisterTypeFlags *flags_type, uint32_t terminal_width);
+ const RegisterType *register_type, uint32_t terminal_width);
} // namespace lldb_private
diff --git a/lldb/include/lldb/Target/DynamicRegisterInfo.h b/lldb/include/lldb/Target/DynamicRegisterInfo.h
index 717e07cdc5453..a5c58fbbe3890 100644
--- a/lldb/include/lldb/Target/DynamicRegisterInfo.h
+++ b/lldb/include/lldb/Target/DynamicRegisterInfo.h
@@ -12,7 +12,7 @@
#include <map>
#include <vector>
-#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterType.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
@@ -41,7 +41,7 @@ class DynamicRegisterInfo {
std::vector<uint32_t> invalidate_regs;
uint32_t value_reg_offset = 0;
// Non-null if there is an XML provided type.
- const RegisterTypeFlags *flags_type = nullptr;
+ const RegisterType *register_type = nullptr;
};
DynamicRegisterInfo() = default;
diff --git a/lldb/include/lldb/Target/RegisterTypeBuilder.h b/lldb/include/lldb/Target/RegisterTypeBuilder.h
index bd75ebd3b6d58..c24d218962e39 100644
--- a/lldb/include/lldb/Target/RegisterTypeBuilder.h
+++ b/lldb/include/lldb/Target/RegisterTypeBuilder.h
@@ -20,7 +20,7 @@ class RegisterTypeBuilder : public PluginInterface {
virtual CompilerType
GetRegisterType(const std::string &name,
- const lldb_private::RegisterTypeFlags &flags,
+ const lldb_private::RegisterType &type_info,
uint32_t byte_size) = 0;
protected:
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index b7b173baae883..8ab75374cabf5 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1484,7 +1484,7 @@ class Target : public std::enable_shared_from_this<Target>,
llvm::Expected<lldb_private::Address> GetEntryPointAddress();
CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterTypeFlags &flags,
+ const lldb_private::RegisterType &type_info,
uint32_t byte_size);
/// Sends a breakpoint notification event.
diff --git a/lldb/source/Core/DumpRegisterInfo.cpp b/lldb/source/Core/DumpRegisterInfo.cpp
index 8906a63e53db2..98682015dce27 100644
--- a/lldb/source/Core/DumpRegisterInfo.cpp
+++ b/lldb/source/Core/DumpRegisterInfo.cpp
@@ -92,7 +92,7 @@ void lldb_private::DoDumpRegisterInfo(
Stream &strm, const char *name, const char *alt_name, uint32_t byte_size,
const std::vector<const char *> &invalidates,
const std::vector<const char *> &read_from,
- const std::vector<SetInfo> &in_sets, const RegisterTypeFlags *flags_type,
+ const std::vector<SetInfo> &in_sets, const RegisterType *register_type,
uint32_t terminal_width) {
strm << " Name: " << name;
if (alt_name)
@@ -115,7 +115,8 @@ void lldb_private::DoDumpRegisterInfo(
};
DumpList(strm, " In sets: ", in_sets, emit_set);
- if (flags_type) {
+ if (auto flags_type =
+ llvm::dyn_cast_if_present<RegisterTypeFlags>(register_type)) {
strm.Printf("\n\n%s", flags_type->AsTable(terminal_width).c_str());
std::string enumerators = flags_type->DumpEnums(terminal_width);
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index c6f61cd0dd865..94bc14f20c95b 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -107,24 +107,24 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
0, // item_bit_offset
exe_scope);
- const RegisterTypeFlags *flags_type =
- llvm::dyn_cast_if_present<RegisterTypeFlags>(reg_info.register_type);
- if (!print_flags || !flags_type || !exe_scope || !target_sp ||
+ if (!print_flags || !reg_info.register_type || !exe_scope || !target_sp ||
(reg_info.byte_size != 4 && reg_info.byte_size != 8))
return;
- CompilerType fields_type = target_sp->GetRegisterType(
- reg_info.name, *flags_type, reg_info.byte_size);
+ CompilerType register_type = target_sp->GetRegisterType(
+ reg_info.name, *reg_info.register_type, reg_info.byte_size);
+ if (!register_type.IsValid())
+ return;
// Use a new stream so we can remove a trailing newline later.
- StreamString fields_stream;
+ StreamString register_type_stream;
if (reg_info.byte_size == 4) {
- dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope,
- fields_stream);
+ dump_type_value(register_type, reg_val.GetAsUInt32(), exe_scope,
+ register_type_stream);
} else {
- dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope,
- fields_stream);
+ dump_type_value(register_type, reg_val.GetAsUInt64(), exe_scope,
+ register_type_stream);
}
// Registers are indented like:
@@ -134,16 +134,18 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
// First drop the extra newline that the value printer added. The register
// command will add one itself.
- llvm::StringRef fields_str = fields_stream.GetString().drop_back();
+ llvm::StringRef register_type_str =
+ register_type_stream.GetString().drop_back();
// End the line that contains " foo = 0x12345678".
s.EOL();
// Then split the value lines and indent each one.
bool first = true;
- while (fields_str.size()) {
- std::pair<llvm::StringRef, llvm::StringRef> split = fields_str.split('\n');
- fields_str = split.second;
+ while (register_type_str.size()) {
+ std::pair<llvm::StringRef, llvm::StringRef> split =
+ register_type_str.split('\n');
+ register_type_str = split.second;
// Indent as far as the register name did.
s.Printf(fmt.c_str(), "");
@@ -156,7 +158,7 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
// On the last line we don't want a newline because the command will add
// one too.
- if (fields_str.size())
+ if (register_type_str.size())
s.EOL();
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 65d16b9dc8f7e..b0198fbb13108 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5028,7 +5028,7 @@ bool ParseRegisters(
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;
+ reg_info.register_type = flags_type;
else
LLDB_LOG(
log,
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 64957b04bd332..482c2d1589544 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -22,6 +22,7 @@
#include "lldb/Host/HostThread.h"
#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Broadcaster.h"
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index edeae122786a2..f13472fb6f9df 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -36,7 +36,7 @@ RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
: m_target(target) {}
CompilerType RegisterTypeBuilderClang::GetRegisterType(
- const std::string &name, const lldb_private::RegisterTypeFlags &flags,
+ const std::string &name, const lldb_private::RegisterType &type_info,
uint32_t byte_size) {
lldb::TypeSystemClangSP type_system = ScratchTypeSystemClang::GetForTarget(
m_target, ScratchTypeSystemClang::IsolatedASTKind::Registers);
@@ -48,6 +48,12 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
}
std::string register_type_name = "__lldb_register_fields_" + name;
+ // For now we can only build sets of flags.
+ const RegisterTypeFlags *flags =
+ llvm::dyn_cast<RegisterTypeFlags>(&type_info);
+ if (!flags)
+ return {};
+
// See if we have made this type before and can reuse it.
CompilerType fields_type =
type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
@@ -69,7 +75,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// We assume that RegisterFlags has padded and sorted the fields
// already.
- for (const RegisterTypeFlags::Field &field : flags.GetFields()) {
+ for (const RegisterTypeFlags::Field &field : flags->GetFields()) {
CompilerType field_type = field_uint_type;
if (const RegisterTypeEnum *enum_type = field.GetEnum()) {
@@ -126,7 +132,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
// This should be true if RegisterFlags padded correctly.
assert(llvm::expectedToOptional(fields_type.GetByteSize(nullptr))
- .value_or(0) == flags.GetSize());
+ .value_or(0) == flags->GetSize());
}
return fields_type;
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index 5dee428aff8bd..c8908da5c854e 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -31,7 +31,7 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
static lldb::RegisterTypeBuilderSP CreateInstance(Target &target);
CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterTypeFlags &flags,
+ const lldb_private::RegisterType &type_info,
uint32_t byte_size) override;
private:
diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp
index c0116921e33fc..abb0a426ae9c7 100644
--- a/lldb/source/Target/DynamicRegisterInfo.cpp
+++ b/lldb/source/Target/DynamicRegisterInfo.cpp
@@ -424,7 +424,7 @@ size_t DynamicRegisterInfo::SetRegisterInfo(
// value_regs and invalidate_regs are filled by Finalize()
nullptr,
nullptr,
- reg.flags_type};
+ reg.register_type};
m_regs.push_back(reg_info);
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 9680577b395ab..d6660b7da16f6 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -2633,12 +2633,13 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language,
CompilerType
Target::GetRegisterType(const std::string &name,
- const lldb_private::RegisterTypeFlags &flags,
+ const lldb_private::RegisterType &type_info,
uint32_t byte_size) {
if (!m_register_type_builder_sp)
m_register_type_builder_sp = PluginManager::GetRegisterTypeBuilder(*this);
assert(m_register_type_builder_sp);
- return m_register_type_builder_sp->GetRegisterType(name, flags, byte_size);
+ return m_register_type_builder_sp->GetRegisterType(name, type_info,
+ byte_size);
}
std::vector<lldb::TypeSystemSP>
diff --git a/lldb/unittests/Core/DumpRegisterInfoTest.cpp b/lldb/unittests/Core/DumpRegisterInfoTest.cpp
index 87c46de4e0406..e469b09f9dc08 100644
--- a/lldb/unittests/Core/DumpRegisterInfoTest.cpp
+++ b/lldb/unittests/Core/DumpRegisterInfoTest.cpp
@@ -11,6 +11,8 @@
#include "lldb/Utility/StreamString.h"
#include "gtest/gtest.h"
+#include "llvm/Support/Casting.h"
+
using namespace lldb_private;
TEST(DoDumpRegisterInfoTest, MinimumInfo) {
@@ -95,7 +97,8 @@ TEST(DoDumpRegisterInfoTest, FieldsTable) {
RegisterTypeFlags::Field("C", 8, 15),
RegisterTypeFlags::Field("D", 0, 7)});
- DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {}, &flags, 100);
+ const RegisterType *register_type = llvm::dyn_cast<RegisterType>(&flags);
+ DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {}, register_type, 100);
ASSERT_EQ(strm.GetString(), " Name: foo\n"
" Size: 4 bytes (32 bits)\n"
"\n"
@@ -116,7 +119,8 @@ TEST(DoDumpRegisterInfoTest, Enumerators) {
RegisterTypeFlags::Field("B", 16, 23),
RegisterTypeFlags::Field("C", 8, 15, &enum_two)});
- DoDumpRegisterInfo(strm, "abc", nullptr, 4, {}, {}, {}, &flags, 100);
+ const RegisterType *register_type = llvm::dyn_cast<RegisterType>(&flags);
+ DoDumpRegisterInfo(strm, "abc", nullptr, 4, {}, {}, {}, register_type, 100);
ASSERT_EQ(strm.GetString(),
" Name: abc\n"
" Size: 4 bytes (32 bits)\n"
>From 8b044694dc7c4e33406dedb0cd6d26c5942d60e0 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Tue, 3 Sep 2024 10:46:24 +0000
Subject: [PATCH 06/16] [lldb] Store all XML register types in a single string
map
We are assuming that their ID's are unique, so there's no need to keep
separate maps. We can do basic type checking by checking the kind of
the type pointed to.
A few more methods were added to the base RegisterType. GetSize()
returns 0 for enums because enums don't have a size until they are
used by a register. This is not ideal but it works for now.
---
lldb/include/lldb/Target/RegisterType.h | 6 +
lldb/include/lldb/Target/RegisterTypeFlags.h | 14 +-
.../Process/gdb-remote/ProcessGDBRemote.cpp | 134 +++++++++---------
.../Process/gdb-remote/ProcessGDBRemote.h | 17 ++-
lldb/source/Target/RegisterTypeFlags.cpp | 4 +-
5 files changed, 91 insertions(+), 84 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterType.h b/lldb/include/lldb/Target/RegisterType.h
index 56e25fc841b28..416c33209ed05 100644
--- a/lldb/include/lldb/Target/RegisterType.h
+++ b/lldb/include/lldb/Target/RegisterType.h
@@ -51,6 +51,12 @@ class RegisterType {
m_dependencies = dependencies;
}
+ virtual void DumpToLog(Log *log) const = 0;
+
+ /// The size of the type in bytes. Return 0 if the size is unknown or context
+ /// specific.
+ virtual unsigned GetSize() const = 0;
+
private:
const RegisterTypeKind m_kind;
const std::string m_id;
diff --git a/lldb/include/lldb/Target/RegisterTypeFlags.h b/lldb/include/lldb/Target/RegisterTypeFlags.h
index 77dacb902fc09..b9085cbc294f5 100644
--- a/lldb/include/lldb/Target/RegisterTypeFlags.h
+++ b/lldb/include/lldb/Target/RegisterTypeFlags.h
@@ -46,7 +46,15 @@ class RegisterTypeEnum : public RegisterType {
const Enumerators &GetEnumerators() const { return m_enumerators; }
- void DumpToLog(Log *log) const;
+ virtual void DumpToLog(Log *log) const override;
+
+ virtual unsigned GetSize() const override {
+ // Enums don't have a size until they are used by a specific register,
+ // so we return 0 just to be sure they don't end up attached directly to a
+ // register. We expect them to only be used by flags, then the flags are
+ // attached to the register.
+ return 0;
+ }
virtual void ToXMLElement(Stream &strm,
const RegisterType *user = nullptr) const override;
@@ -141,9 +149,9 @@ class RegisterTypeFlags : public RegisterType {
std::string DumpEnums(uint32_t max_width) const;
const std::vector<Field> &GetFields() const { return m_fields; }
- unsigned GetSize() const { return m_size; }
+ virtual unsigned GetSize() const override { return m_size; }
- void DumpToLog(Log *log) const;
+ virtual void DumpToLog(Log *log) const override;
/// Produce a text table showing the layout of all the fields. Unnamed/padding
/// fields will be included, with only their positions shown.
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index b0198fbb13108..4a1d5e611d96b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4638,14 +4638,14 @@ ParseEnumEvalues(const XMLNode &enum_node) {
return final_enumerators;
}
-static void ParseEnums(
- XMLNode feature_node,
- llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> ®isters_enum_types) {
+static void
+ParseEnums(XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
Log *log(GetLog(GDBRLog::Process));
// The top level element is "<enum...".
feature_node.ForEachChildElementWithName(
- "enum", [log, ®isters_enum_types](const XMLNode &enum_node) {
+ "enum", [log, ®ister_types](const XMLNode &enum_node) {
std::string id;
enum_node.ForEachAttribute([&id](const llvm::StringRef &attr_name,
@@ -4673,7 +4673,7 @@ static void ParseEnums(
LLDB_LOG(log,
"ProcessGDBRemote::ParseEnums Found enum type \"{0}\"",
id);
- registers_enum_types.insert_or_assign(
+ register_types.insert_or_assign(
id, std::make_unique<RegisterTypeEnum>(id, enumerators));
}
}
@@ -4683,17 +4683,16 @@ static void ParseEnums(
});
}
-static std::vector<RegisterTypeFlags::Field>
-ParseFlagsFields(XMLNode flags_node, unsigned size,
- const llvm::StringMap<std::unique_ptr<RegisterTypeEnum>>
- ®isters_enum_types) {
+static std::vector<RegisterTypeFlags::Field> ParseFlagsFields(
+ XMLNode flags_node, unsigned size,
+ const llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
Log *log(GetLog(GDBRLog::Process));
const unsigned max_start_bit = size * 8 - 1;
// Process the fields of this set of flags.
std::vector<RegisterTypeFlags::Field> fields;
flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, &log,
- ®isters_enum_types](
+ ®ister_types](
const XMLNode
&field_node) {
std::optional<llvm::StringRef> name;
@@ -4775,35 +4774,39 @@ ParseFlagsFields(XMLNode flags_node, unsigned size,
"size > 64 bits, this is not supported",
name->data());
else {
- // A field's type may be set to the name of an enum type.
+ // A field's type may be set to another previously defined type.
+ // Right now we only support enum.
const RegisterTypeEnum *enum_type = nullptr;
if (type && !type->empty()) {
- auto found = registers_enum_types.find(*type);
- if (found != registers_enum_types.end()) {
- enum_type = found->second.get();
-
- // No enumerator can exceed the range of the field itself.
- uint64_t max_value =
- RegisterTypeFlags::Field::GetMaxValue(*start, *end);
- for (const auto &enumerator : enum_type->GetEnumerators()) {
- if (enumerator.m_value > max_value) {
- enum_type = nullptr;
- LLDB_LOG(
- log,
- "ProcessGDBRemote::ParseFlagsFields In enum \"{0}\" "
- "evalue \"{1}\" with value {2} exceeds the maximum value "
- "of field \"{3}\" ({4}), ignoring enum",
- type->data(), enumerator.m_name, enumerator.m_value,
- name->data(), max_value);
- break;
+ auto found = register_types.find(*type);
+ if (found != register_types.end()) {
+ enum_type = llvm::dyn_cast<RegisterTypeEnum>(found->second.get());
+ if (enum_type) {
+ // No enumerator can exceed the range of the field itself.
+ uint64_t max_value =
+ RegisterTypeFlags::Field::GetMaxValue(*start, *end);
+ for (const auto &enumerator : enum_type->GetEnumerators()) {
+ if (enumerator.m_value > max_value) {
+ enum_type = nullptr;
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields In enum \"{0}\" "
+ "evalue \"{1}\" with value {2} exceeds the maximum "
+ "value "
+ "of field \"{3}\" ({4}), ignoring enum",
+ type->data(), enumerator.m_name, enumerator.m_value,
+ name->data(), max_value);
+ break;
+ }
}
}
} else {
- LLDB_LOG(log,
- "ProcessGDBRemote::ParseFlagsFields Could not find type "
- "\"{0}\" "
- "for field \"{1}\", ignoring",
- type->data(), name->data());
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseFlagsFields Could not find enum type "
+ "\"{0}\" "
+ "for field \"{1}\", ignoring",
+ type->data(), name->data());
}
}
@@ -4820,15 +4823,11 @@ ParseFlagsFields(XMLNode flags_node, unsigned size,
void ParseFlags(
XMLNode feature_node,
- llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> ®isters_flags_types,
- const llvm::StringMap<std::unique_ptr<RegisterTypeEnum>>
- ®isters_enum_types) {
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
Log *log(GetLog(GDBRLog::Process));
feature_node.ForEachChildElementWithName(
- "flags",
- [&log, ®isters_flags_types,
- ®isters_enum_types](const XMLNode &flags_node) -> bool {
+ "flags", [&log, ®ister_types](const XMLNode &flags_node) -> bool {
LLDB_LOG(log, "ProcessGDBRemote::ParseFlags Found flags node \"{0}\"",
flags_node.GetAttributeValue("id").c_str());
@@ -4861,7 +4860,7 @@ void ParseFlags(
if (id && size) {
// Process the fields of this set of flags.
std::vector<RegisterTypeFlags::Field> fields =
- ParseFlagsFields(flags_node, *size, registers_enum_types);
+ ParseFlagsFields(flags_node, *size, register_types);
if (fields.size()) {
// Sort so that the fields with the MSBs are first.
std::sort(fields.rbegin(), fields.rend());
@@ -4874,26 +4873,27 @@ void ParseFlags(
// If no fields overlap, use them.
if (overlap == fields.end()) {
- if (registers_flags_types.contains(*id)) {
+ if (register_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
+ // register then reuse the ID. 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
+ // expensive and difficult. This means that pointers to types
+ // in the register info remain valid if later the ID is reused.
+ // 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 "
+ "ProcessGDBRemote::ParseFlags Definition of flags with ID "
"\"{0}\" shadows "
- "previous definition, using original definition instead.",
+ "previous use of that ID, using original definition "
+ "instead.",
id->data());
} else {
- registers_flags_types.insert_or_assign(
+ register_types.insert_or_assign(
*id, std::make_unique<RegisterTypeFlags>(
id->str(), *size, std::move(fields)));
}
@@ -4926,25 +4926,21 @@ void ParseFlags(
bool ParseRegisters(
XMLNode feature_node, GdbServerTargetInfo &target_info,
std::vector<DynamicRegisterInfo::Register> ®isters,
- llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> ®isters_flags_types,
- llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> ®isters_enum_types) {
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
if (!feature_node)
return false;
Log *log(GetLog(GDBRLog::Process));
// Enums first because they are referenced by fields in the flags.
- ParseEnums(feature_node, registers_enum_types);
- for (const auto &enum_type : registers_enum_types)
- enum_type.second->DumpToLog(log);
-
- ParseFlags(feature_node, registers_flags_types, registers_enum_types);
- for (const auto &flags : registers_flags_types)
- flags.second->DumpToLog(log);
+ ParseEnums(feature_node, register_types);
+ ParseFlags(feature_node, register_types);
+ for (const auto ®ister_type : register_types)
+ register_type.second->DumpToLog(log);
feature_node.ForEachChildElementWithName(
"reg",
- [&target_info, ®isters, ®isters_flags_types,
+ [&target_info, ®isters, ®ister_types,
log](const XMLNode ®_node) -> bool {
std::string gdb_group;
std::string gdb_type;
@@ -5023,19 +5019,19 @@ bool ParseRegisters(
if (!gdb_type.empty()) {
// gdb_type could reference some flags type defined in XML.
- llvm::StringMap<std::unique_ptr<RegisterTypeFlags>>::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.register_type = flags_type;
+ llvm::StringMap<std::unique_ptr<RegisterType>>::iterator it =
+ register_types.find(gdb_type);
+ if (it != register_types.end()) {
+ auto register_type = it->second.get();
+ if (reg_info.byte_size == register_type->GetSize())
+ reg_info.register_type = register_type;
else
LLDB_LOG(
log,
"ProcessGDBRemote::ParseRegisters Size of register flags {0} "
"({1} bytes) for register {2} does not match the register "
"size ({3} bytes). Ignoring this set of flags.",
- flags_type->GetID().c_str(), flags_type->GetSize(),
+ register_type->GetID().c_str(), register_type->GetSize(),
reg_info.name, reg_info.byte_size);
}
@@ -5205,8 +5201,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess(
if (arch_to_use.IsValid()) {
for (auto &feature_node : feature_nodes) {
- ParseRegisters(feature_node, target_info, registers,
- m_registers_flags_types, m_registers_enum_types);
+ ParseRegisters(feature_node, target_info, registers, m_register_types);
}
for (const auto &include : target_info.includes) {
@@ -5282,8 +5277,7 @@ llvm::Error ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) {
// 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();
- m_registers_enum_types.clear();
+ m_register_types.clear();
std::vector<DynamicRegisterInfo::Register> registers;
if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml",
registers) &&
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 482c2d1589544..97bab324031d2 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -22,7 +22,7 @@
#include "lldb/Host/HostThread.h"
#include "lldb/Target/DynamicRegisterInfo.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterType.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Broadcaster.h"
@@ -518,19 +518,18 @@ class ProcessGDBRemote : public Process,
void ParseExpeditedRegisters(ExpeditedRegisterMap &expedited_register_map,
lldb::ThreadSP thread_sp);
- // Lists of register fields generated from the remote's target XML.
- // Pointers to these RegisterTypeFlags will be set in the register info passed
+ // Lists of register types generated from the remote's target XML.
+ // Pointers to these RegisterTypes will be set in the register info passed
// back to the upper levels of lldb. Doing so is safe because this class will
// live at least as long as the debug session. We therefore do not store the
// data directly in the map because the map may reallocate it's storage as new
// entries are added. Which would invalidate any pointers set in the register
// info up to that point.
- llvm::StringMap<std::unique_ptr<RegisterTypeFlags>> m_registers_flags_types;
-
- // Enum types are referenced by register fields. This does not store the data
- // directly because the map may reallocate. Pointers to these are contained
- // within instances of RegisterTypeFlags.
- llvm::StringMap<std::unique_ptr<RegisterTypeEnum>> m_registers_enum_types;
+ // The key is the XML ID of the type. The kind of element does not play a part
+ // here, the XML author should use unique global IDs.
+ // RegisterTypes may contain pointers to other RegisterTypes, but they will
+ // not attempt to destroy those types when they themselves destruct.
+ llvm::StringMap<std::unique_ptr<RegisterType>> m_register_types;
};
} // namespace process_gdb_remote
diff --git a/lldb/source/Target/RegisterTypeFlags.cpp b/lldb/source/Target/RegisterTypeFlags.cpp
index bafa16e99ba72..9340760e610fe 100644
--- a/lldb/source/Target/RegisterTypeFlags.cpp
+++ b/lldb/source/Target/RegisterTypeFlags.cpp
@@ -127,7 +127,7 @@ RegisterTypeFlags::RegisterTypeFlags(std::string id, unsigned size,
}
void RegisterTypeFlags::DumpToLog(Log *log) const {
- LLDB_LOG(log, "ID: \"{0}\" Size: {1}", GetID().c_str(), m_size);
+ LLDB_LOG(log, "flags ID: \"{0}\" Size: {1}", GetID().c_str(), m_size);
for (const Field &field : m_fields)
field.DumpToLog(log);
}
@@ -362,7 +362,7 @@ void RegisterTypeEnum::Enumerator::DumpToLog(Log *log) const {
}
void RegisterTypeEnum::DumpToLog(Log *log) const {
- LLDB_LOG(log, "ID: \"{0}\"", GetID().c_str());
+ LLDB_LOG(log, "enum ID: \"{0}\"", GetID().c_str());
for (const auto &enumerator : GetEnumerators())
enumerator.DumpToLog(log);
}
>From 2d822d9db234be0564e62d653f7bcd4fc6448604 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Fri, 6 Sep 2024 10:35:58 +0000
Subject: [PATCH 07/16] [lldb] Make RegisterFlagsDetector into
RegisterTypesDetector
In future it may be generating things other than flags. Functionality
is the same, but the interface changes to use RegisterType.
---
.../NativeRegisterContextFreeBSD_arm64.cpp | 14 +-
.../NativeRegisterContextLinux_arm64.cpp | 18 +-
.../Plugins/Process/Utility/CMakeLists.txt | 2 +-
.../Utility/RegisterFlagsDetector_arm64.h | 101 ---------
...m64.cpp => RegisterTypeDetector_arm64.cpp} | 196 ++++++++++--------
.../Utility/RegisterTypeDetector_arm64.h | 100 +++++++++
.../RegisterContextPOSIXCore_arm64.cpp | 12 +-
.../elf-core/RegisterContextPOSIXCore_arm64.h | 4 +-
.../source/Plugins/Process/Utility/BUILD.gn | 2 +-
9 files changed, 232 insertions(+), 217 deletions(-)
delete mode 100644 lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
rename lldb/source/Plugins/Process/Utility/{RegisterFlagsDetector_arm64.cpp => RegisterTypeDetector_arm64.cpp} (60%)
create mode 100644 lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
index f50b28e2ebd1d..0a023a32a26b6 100644
--- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
+++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp
@@ -16,8 +16,8 @@
#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "Plugins/Process/Utility/RegisterTypeDetector_arm64.h"
// clang-format off
#include <sys/param.h>
@@ -33,16 +33,16 @@ using namespace lldb_private::process_freebsd;
// will contain the same fields. Therefore this mutex prevents each instance
// competing with the other, and subsequent instances from having to detect the
// fields all over again.
-static std::mutex g_register_flags_detector_mutex;
-static Arm64RegisterFlagsDetector g_register_flags_detector;
+static std::mutex g_register_type_detector_mutex;
+static Arm64RegisterTypeDetector g_register_type_detector;
NativeRegisterContextFreeBSD *
NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD(
const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) {
- std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex);
- if (!g_register_flags_detector.HasDetected()) {
+ std::lock_guard<std::mutex> lock(g_register_type_detector_mutex);
+ if (!g_register_type_detector.HasDetected()) {
NativeProcessFreeBSD &process = native_thread.GetProcess();
- g_register_flags_detector.DetectFields(
+ g_register_type_detector.DetectTypes(
process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0),
process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0),
/*hwcap3=*/0);
@@ -56,7 +56,7 @@ NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64(
: NativeRegisterContextRegisterInfo(
native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0)),
m_read_dbreg(false) {
- g_register_flags_detector.UpdateRegisterInfo(
+ g_register_type_detector.UpdateRegisterInfo(
GetRegisterInfoInterface().GetRegisterInfo(),
GetRegisterInfoInterface().GetRegisterCount());
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index c7bd5d7bec252..0352cf1afe70a 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -24,8 +24,8 @@
#include "Plugins/Process/Linux/Procfs.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h"
-#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include "Plugins/Process/Utility/RegisterTypeDetector_arm64.h"
// System includes - They have to be included after framework includes because
// they define some macros which collide with variable names in other modules
@@ -101,8 +101,8 @@ using namespace lldb_private::process_linux;
// will contain the same fields. Therefore this mutex prevents each instance
// competing with the other, and subsequent instances from having to detect the
// fields all over again.
-static std::mutex g_register_flags_detector_mutex;
-static Arm64RegisterFlagsDetector g_register_flags_detector;
+static std::mutex g_register_type_detector_mutex;
+static Arm64RegisterTypeDetector g_register_type_detector;
std::unique_ptr<NativeRegisterContextLinux>
NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
@@ -182,11 +182,11 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
std::optional<uint64_t> auxv_at_hwcap3 =
process.GetAuxValue(AuxVector::AUXV_AT_HWCAP3);
- std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex);
- if (!g_register_flags_detector.HasDetected())
- g_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
- auxv_at_hwcap2.value_or(0),
- auxv_at_hwcap3.value_or(0));
+ std::lock_guard<std::mutex> lock(g_register_type_detector_mutex);
+ if (!g_register_type_detector.HasDetected())
+ g_register_type_detector.DetectTypes(auxv_at_hwcap.value_or(0),
+ auxv_at_hwcap2.value_or(0),
+ auxv_at_hwcap3.value_or(0));
auto register_info_up =
std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets);
@@ -210,7 +210,7 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
: NativeRegisterContextRegisterInfo(native_thread,
register_info_up.release()),
NativeRegisterContextLinux(native_thread) {
- g_register_flags_detector.UpdateRegisterInfo(
+ g_register_type_detector.UpdateRegisterInfo(
GetRegisterInfoInterface().GetRegisterInfo(),
GetRegisterInfoInterface().GetRegisterCount());
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 88e5353cd5a79..e4b08ce498f49 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -52,7 +52,7 @@ add_lldb_library(lldbPluginProcessUtility
RegisterContextThreadMemory.cpp
RegisterContextWindows_i386.cpp
RegisterContextWindows_x86_64.cpp
- RegisterFlagsDetector_arm64.cpp
+ RegisterTypeDetector_arm64.cpp
RegisterInfos_x86_64_with_base_shared.cpp
RegisterInfoPOSIX_arm.cpp
RegisterInfoPOSIX_arm64.cpp
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
deleted file mode 100644
index 6fb305fc16702..0000000000000
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//===-- RegisterFlagsDetector_arm64.h ---------------------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
-#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
-
-#include "lldb/Target/RegisterTypeFlags.h"
-#include "llvm/ADT/StringRef.h"
-#include <functional>
-
-namespace lldb_private {
-
-struct RegisterInfo;
-
-/// This class manages the storage and detection of register field information.
-/// The same register may have different fields on different CPUs. This class
-/// abstracts out the field detection process so we can use it on live processes
-/// and core files.
-///
-/// The way to use this class is:
-/// * Make an instance somewhere that will last as long as the debug session
-/// (because your final register info will point to this instance).
-/// * Read hardware capabilities from a core note, binary, prctl, etc.
-/// * Pass those to DetectFields.
-/// * Call UpdateRegisterInfo with your RegisterInfo to add pointers
-/// to the detected fields for all registers listed in this class.
-///
-/// This must be done in that order, and you should ensure that if multiple
-/// threads will reference the information, a mutex is used to make sure only
-/// one calls DetectFields.
-class Arm64RegisterFlagsDetector {
-public:
- /// For the registers listed in this class, detect which fields are
- /// present. Must be called before UpdateRegisterInfos.
- /// If called more than once, fields will be redetected each time from
- /// scratch. If the target would not have this register at all, the list of
- /// fields will be left empty.
- void DetectFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3);
-
- /// Add the field information of any registers named in this class,
- /// to the relevant RegisterInfo instances. Note that this will be done
- /// with a pointer to the instance of this class that you call this on, so
- /// the lifetime of that instance must be at least that of the register info.
- void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs);
-
- /// Returns true if field detection has been run at least once.
- bool HasDetected() const { return m_has_detected; }
-
-private:
- using Fields = std::vector<RegisterTypeFlags::Field>;
- using DetectorFn = std::function<Fields(uint64_t, uint64_t, uint64_t)>;
-
- static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
- static Fields DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3);
-
- struct RegisterEntry {
- RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
- : m_name(name), m_flags(std::string(name) + "_flags", size, {}),
- m_detector(detector) {}
-
- llvm::StringRef m_name;
- RegisterTypeFlags m_flags;
- DetectorFn m_detector;
- } m_registers[9] = {
- RegisterEntry("cpsr", 4, DetectCPSRFields),
- RegisterEntry("fpsr", 4, DetectFPSRFields),
- RegisterEntry("fpcr", 4, DetectFPCRFields),
- RegisterEntry("mte_ctrl", 8, DetectMTECtrlFields),
- RegisterEntry("svcr", 8, DetectSVCRFields),
- RegisterEntry("fpmr", 8, DetectFPMRFields),
- RegisterEntry("gcs_features_enabled", 8, DetectGCSFeatureFields),
- RegisterEntry("gcs_features_locked", 8, DetectGCSFeatureFields),
- RegisterEntry("por_el0", 8, DetectPOREL0Fields),
- };
-
- // Becomes true once field detection has been run for all registers.
- bool m_has_detected = false;
-};
-
-} // namespace lldb_private
-
-#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
similarity index 60%
rename from lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
rename to lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index 710e0fe16f9f7..ed9d914f18317 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -1,4 +1,4 @@
-//===-- RegisterFlagsDetector_arm64.cpp -----------------------------------===//
+//===-- RegisterTypeDetector_arm64.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "RegisterFlagsDetector_arm64.h"
+#include "RegisterTypeDetector_arm64.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/lldb-private-types.h"
// This file is built on all systems because it is used by native processes and
@@ -31,9 +32,9 @@
using namespace lldb_private;
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectPOREL0Type(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap;
(void)hwcap3;
@@ -52,29 +53,33 @@ Arm64RegisterFlagsDetector::DetectPOREL0Fields(uint64_t hwcap, uint64_t hwcap2,
{0b0111, "Read, Write, Execute"},
});
- return {
- {"Perm15", 60, 63, &por_el0_perm_enum},
- {"Perm14", 56, 59, &por_el0_perm_enum},
- {"Perm13", 52, 55, &por_el0_perm_enum},
- {"Perm12", 48, 51, &por_el0_perm_enum},
- {"Perm11", 44, 47, &por_el0_perm_enum},
- {"Perm10", 40, 43, &por_el0_perm_enum},
- {"Perm9", 36, 39, &por_el0_perm_enum},
- {"Perm8", 32, 35, &por_el0_perm_enum},
- {"Perm7", 28, 31, &por_el0_perm_enum},
- {"Perm6", 24, 27, &por_el0_perm_enum},
- {"Perm5", 20, 23, &por_el0_perm_enum},
- {"Perm4", 16, 19, &por_el0_perm_enum},
- {"Perm3", 12, 15, &por_el0_perm_enum},
- {"Perm2", 8, 11, &por_el0_perm_enum},
- {"Perm1", 4, 7, &por_el0_perm_enum},
- {"Perm0", 0, 3, &por_el0_perm_enum},
- };
+ static const RegisterTypeFlags por_el0_flags(
+ "por_el0_flags", 8,
+ {
+ {"Perm15", 60, 63, &por_el0_perm_enum},
+ {"Perm14", 56, 59, &por_el0_perm_enum},
+ {"Perm13", 52, 55, &por_el0_perm_enum},
+ {"Perm12", 48, 51, &por_el0_perm_enum},
+ {"Perm11", 44, 47, &por_el0_perm_enum},
+ {"Perm10", 40, 43, &por_el0_perm_enum},
+ {"Perm9", 36, 39, &por_el0_perm_enum},
+ {"Perm8", 32, 35, &por_el0_perm_enum},
+ {"Perm7", 28, 31, &por_el0_perm_enum},
+ {"Perm6", 24, 27, &por_el0_perm_enum},
+ {"Perm5", 20, 23, &por_el0_perm_enum},
+ {"Perm4", 16, 19, &por_el0_perm_enum},
+ {"Perm3", 12, 15, &por_el0_perm_enum},
+ {"Perm2", 8, 11, &por_el0_perm_enum},
+ {"Perm1", 4, 7, &por_el0_perm_enum},
+ {"Perm0", 0, 3, &por_el0_perm_enum},
+ });
+
+ return &por_el0_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectFPMRType(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap;
(void)hwcap3;
@@ -86,60 +91,59 @@ Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2,
{0, "FP8_E5M2"},
{1, "FP8_E4M3"},
});
- return {
- {"LSCALE2", 32, 37},
- {"NSCALE", 24, 31},
- {"LSCALE", 16, 22},
- {"OSC", 15},
- {"OSM", 14},
- {"F8D", 6, 8, &fp8_format_enum},
- {"F8S2", 3, 5, &fp8_format_enum},
- {"F8S1", 0, 2, &fp8_format_enum},
- };
+
+ static const RegisterTypeFlags fpmr_flags("fpmr_flags", 8,
+ {{"LSCALE2", 32, 37},
+ {"NSCALE", 24, 31},
+ {"LSCALE", 16, 22},
+ {"OSC", 15},
+ {"OSM", 14},
+ {"F8D", 6, 8, &fp8_format_enum},
+ {"F8S2", 3, 5, &fp8_format_enum},
+ {"F8S1", 0, 2, &fp8_format_enum}});
+
+ return &fpmr_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap,
- uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectGCSFeaturesType(
+ uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3) {
(void)hwcap2;
(void)hwcap3;
if (!(hwcap & HWCAP_GCS))
return {};
- return {
- {"PUSH", 2},
- {"WRITE", 1},
- {"ENABLE", 0},
- };
+ static const RegisterTypeFlags gcs_features_flags(
+ "gcs_features_flags", 8, {{"PUSH", 2}, {"WRITE", 1}, {"ENABLE", 0}});
+
+ return &gcs_features_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectSVCRType(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap;
(void)hwcap3;
if (!(hwcap2 & HWCAP2_SME))
- return {};
+ return nullptr;
// Represents the pseudo register that lldb-server builds, which itself
// matches the architectural register SCVR. The fields match SVCR in the Arm
// manual.
- return {
- {"ZA", 1},
- {"SM", 0},
- };
+ static const RegisterTypeFlags svcr_flags("svcr_flags", 8,
+ {{"ZA", 1}, {"SM", 0}});
+
+ return &svcr_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *
+Arm64RegisterTypeDetector::DetectMTECtrlType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap;
if (!(hwcap2 & HWCAP2_MTE))
- return {};
+ return nullptr;
// Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
// to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
@@ -160,16 +164,19 @@ Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2,
{"TCF", 1, 2, &tcf_enum},
{"TAGGED_ADDR_ENABLE", 0}});
- return fields;
+ static const RegisterTypeFlags mte_ctrl_flags("mte_ctrl_flags", 8, fields);
+
+ return &mte_ctrl_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectFPCRType(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap3;
static const RegisterTypeEnum rmode_enum(
"rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
+ static RegisterTypeFlags fpcr_flags("fpcr_flags", 4, {});
std::vector<RegisterTypeFlags::Field> fpcr_fields{
{"AHP", 26},
@@ -205,39 +212,46 @@ Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2,
fpcr_fields.push_back({"FIZ", 0});
}
- return fpcr_fields;
+ fpcr_flags.SetFields(fpcr_fields);
+
+ return &fpcr_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectFPSRType(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
// fpsr's contents are constant.
(void)hwcap;
(void)hwcap2;
(void)hwcap3;
- return {
- // Bits 31-28 are N/Z/C/V, only used by AArch32.
- {"QC", 27},
- // Bits 26-8 reserved.
- {"IDC", 7},
- // Bits 6-5 reserved.
- {"IXC", 4},
- {"UFC", 3},
- {"OFC", 2},
- {"DZC", 1},
- {"IOC", 0},
- };
+ static const RegisterTypeFlags fpsr_flags(
+ "fpsr_flags", 4,
+ {
+ // Bits 31-28 are N/Z/C/V, only used by AArch32.
+ {"QC", 27},
+ // Bits 26-8 reserved.
+ {"IDC", 7},
+ // Bits 6-5 reserved.
+ {"IXC", 4},
+ {"UFC", 3},
+ {"OFC", 2},
+ {"DZC", 1},
+ {"IOC", 0},
+ });
+
+ return &fpsr_flags;
}
-Arm64RegisterFlagsDetector::Fields
-Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+const RegisterType *Arm64RegisterTypeDetector::DetectCPSRType(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
(void)hwcap3;
// The fields here are a combination of the Arm manual's SPSR_EL1,
// plus a few changes where Linux has decided not to make use of them at all,
// or at least not from userspace.
+ static RegisterTypeFlags cpsr_flags("cpsr_flags", 4, {});
// Status bits that are always present.
std::vector<RegisterTypeFlags::Field> cpsr_fields{
@@ -279,31 +293,33 @@ Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2,
// Bit 1 is unused and expected to be 0.
cpsr_fields.push_back({"SP", 0});
- return cpsr_fields;
+ cpsr_flags.SetFields(cpsr_fields);
+
+ return &cpsr_flags;
}
-void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2,
- uint64_t hwcap3) {
+void Arm64RegisterTypeDetector::DetectTypes(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3) {
for (auto ® : m_registers)
- reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2, hwcap3));
+ reg.m_type = reg.m_detector(hwcap, hwcap2, hwcap3);
m_has_detected = true;
}
-void Arm64RegisterFlagsDetector::UpdateRegisterInfo(
- const RegisterInfo *reg_info, uint32_t num_regs) {
+void Arm64RegisterTypeDetector::UpdateRegisterInfo(const RegisterInfo *reg_info,
+ uint32_t num_regs) {
assert(m_has_detected &&
- "Must call DetectFields before updating register info.");
+ "Must call DetectTypes before updating register info.");
// Register names will not be duplicated, so we do not want to compare against
// one if it has already been found. Each time we find one, we erase it from
// this list.
- std::vector<std::pair<llvm::StringRef, const RegisterTypeFlags *>>
+ std::vector<std::pair<llvm::StringRef, const RegisterType *>>
search_registers;
for (const auto ® : m_registers) {
// It is possible that a register is all extension dependent fields, and
// none of them are present.
- if (reg.m_flags.GetFields().size())
- search_registers.push_back({reg.m_name, ®.m_flags});
+ if (reg.m_type)
+ search_registers.push_back({reg.m_name, reg.m_type});
}
// Walk register information while there are registers we know need
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
new file mode 100644
index 0000000000000..7388756b71e91
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
@@ -0,0 +1,100 @@
+//===-- RegisterTypeDetector_arm64.h ----------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERTYPEDETECTOR_ARM64_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERTYPEDETECTOR_ARM64_H
+
+#include "lldb/Target/RegisterType.h"
+#include "llvm/ADT/StringRef.h"
+#include <functional>
+
+namespace lldb_private {
+
+struct RegisterInfo;
+
+/// This class manages the storage and detection of register type information.
+/// The same register may have different fields on different CPUs. This class
+/// abstracts out the field detection process so we can use it on live processes
+/// and core files.
+///
+/// The way to use this class is:
+/// * Make an instance somewhere that will last as long as the debug session
+/// (because your final register info will point to this instance).
+/// * Read hardware capabilities from a core note, binary, prctl, etc.
+/// * Pass those to DetectTypes.
+/// * Call UpdateRegisterInfo with your RegisterInfo to add pointers
+/// to the detected types for all registers listed in this class.
+///
+/// This must be done in that order, and you should ensure that if multiple
+/// threads will reference the information, a mutex is used to make sure only
+/// one calls DetectTypes.
+class Arm64RegisterTypeDetector {
+public:
+ /// For the registers listed in this class, detect which fields are
+ /// present and build types for those. Must be called before
+ /// UpdateRegisterInfos. If called more than once, fields will be redetected
+ /// each time from scratch. If the target would not have this register at all,
+ /// no type is produced.
+ void DetectTypes(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3);
+
+ /// Add the type information of any registers named in this class,
+ /// to the relevant RegisterInfo instances. Note that this will be done
+ /// with a pointer to the instance of this class that you call this on, so
+ /// the lifetime of that instance must be at least that of the register info.
+ void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs);
+
+ /// Returns true if field detection has been run at least once.
+ bool HasDetected() const { return m_has_detected; }
+
+private:
+ using DetectorFn =
+ std::function<const RegisterType *(uint64_t, uint64_t, uint64_t)>;
+
+ static const RegisterType *DetectCPSRType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *DetectFPSRType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *DetectFPCRType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *DetectMTECtrlType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *DetectSVCRType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *DetectFPMRType(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+ static const RegisterType *
+ DetectGCSFeaturesType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3);
+ static const RegisterType *DetectPOREL0Type(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
+
+ struct RegisterEntry {
+ RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector)
+ : m_name(name), m_type(nullptr), m_detector(detector) {}
+
+ llvm::StringRef m_name;
+ const RegisterType *m_type;
+ DetectorFn m_detector;
+ } m_registers[9] = {
+ RegisterEntry("cpsr", 4, DetectCPSRType),
+ RegisterEntry("fpsr", 4, DetectFPSRType),
+ RegisterEntry("fpcr", 4, DetectFPCRType),
+ RegisterEntry("mte_ctrl", 8, DetectMTECtrlType),
+ RegisterEntry("svcr", 8, DetectSVCRType),
+ RegisterEntry("fpmr", 8, DetectFPMRType),
+ RegisterEntry("gcs_features_enabled", 8, DetectGCSFeaturesType),
+ RegisterEntry("gcs_features_locked", 8, DetectGCSFeaturesType),
+ RegisterEntry("por_el0", 8, DetectPOREL0Type),
+ };
+
+ // Becomes true once field detection has been run for all registers.
+ bool m_has_detected = false;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERTYPEDETECTOR_ARM64_H
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
index feeed4a9f0ac3..837cb30798fe1 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp
@@ -10,7 +10,7 @@
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
#include "Plugins/Process/Utility/AuxVector.h"
-#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
+#include "Plugins/Process/Utility/RegisterTypeDetector_arm64.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "lldb/Target/Thread.h"
@@ -113,11 +113,11 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
is_freebsd ? std::nullopt
: aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP3);
- m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
- auxv_at_hwcap2.value_or(0),
- auxv_at_hwcap3.value_or(0));
- m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
- GetRegisterCount());
+ m_register_type_detector.DetectTypes(auxv_at_hwcap.value_or(0),
+ auxv_at_hwcap2.value_or(0),
+ auxv_at_hwcap3.value_or(0));
+ m_register_type_detector.UpdateRegisterInfo(GetRegisterInfo(),
+ GetRegisterCount());
}
m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
index f6d6c522d836a..9d9a2da2bc1b9 100644
--- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
+++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h
@@ -11,7 +11,7 @@
#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h"
#include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h"
-#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
+#include "Plugins/Process/Utility/RegisterTypeDetector_arm64.h"
#include "Plugins/Process/elf-core/RegisterUtilities.h"
#include "lldb/Utility/DataBufferHeap.h"
@@ -78,7 +78,7 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
struct sme_pseudo_regs m_sme_pseudo_regs;
- lldb_private::Arm64RegisterFlagsDetector m_register_flags_detector;
+ lldb_private::Arm64RegisterTypeDetector m_register_type_detector;
const uint8_t *GetSVEBuffer(uint64_t offset = 0);
diff --git a/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
index 3aef832e1c457..c4f9881331ad1 100644
--- a/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
+++ b/llvm/utils/gn/secondary/lldb/source/Plugins/Process/Utility/BUILD.gn
@@ -69,7 +69,7 @@ static_library("Utility") {
"RegisterContextWindows_i386.cpp",
"RegisterContextWindows_x86_64.cpp",
"RegisterContext_x86.cpp",
- "RegisterFlagsDetector_arm64.cpp",
+ "RegisterTypeDetector_arm64.cpp",
"RegisterInfoPOSIX_arm.cpp",
"RegisterInfoPOSIX_arm64.cpp",
"RegisterInfoPOSIX_loongarch64.cpp",
>From 4d5ac3881496f824b51ff60ae193f59d37ad463a Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Wed, 4 Sep 2024 12:00:58 +0000
Subject: [PATCH 08/16] [lldb] Add union type for registers
https://sourceware.org/gdb/current/onlinedocs/gdb.html/Target-Description-Format.html
```
<union id=\"id\">
<field name=\"name\" type=\"type\">
<...>
</union>
```
This allows you to describe a register with multiple views on the data.
Primarily this is used for vector registers where you use a union of the
<vector> type (which I have yet to implement) to show the register with
different element sizes.
This work relates to https://github.com/llvm/llvm-project/issues/87471
which covers that in more detail.
This first commit introduces the type class and XML emitter, but does
not yet parse it from XML or produce C types from it.
It's unlikely we will be using <union> in lldb-server, but I figured
it was best to implement ToElementXML for it anyway to be consistent
with the rest of the classes.
It's possible that "type" may not be the ID of another element but instead
some generic name like "uint32". I don't know of any debug server that
sends that, so for now I'm assuming that "type" always refers to some
other type element.
---
lldb/include/lldb/Target/RegisterType.h | 1 +
lldb/include/lldb/Target/RegisterTypeUnion.h | 41 +++++++++++
lldb/source/Target/CMakeLists.txt | 1 +
lldb/source/Target/RegisterTypeUnion.cpp | 75 ++++++++++++++++++++
lldb/unittests/Target/RegisterTypeTest.cpp | 18 +++++
5 files changed, 136 insertions(+)
create mode 100644 lldb/include/lldb/Target/RegisterTypeUnion.h
create mode 100644 lldb/source/Target/RegisterTypeUnion.cpp
diff --git a/lldb/include/lldb/Target/RegisterType.h b/lldb/include/lldb/Target/RegisterType.h
index 416c33209ed05..b9589c71b413b 100644
--- a/lldb/include/lldb/Target/RegisterType.h
+++ b/lldb/include/lldb/Target/RegisterType.h
@@ -23,6 +23,7 @@ class RegisterType {
enum RegisterTypeKind {
eRegisterTypeKindFlags,
eRegisterTypeKindEnum,
+ eRegisterTypeKindUnion,
};
RegisterTypeKind getKind() const { return m_kind; }
diff --git a/lldb/include/lldb/Target/RegisterTypeUnion.h b/lldb/include/lldb/Target/RegisterTypeUnion.h
new file mode 100644
index 0000000000000..1c59dea40cf49
--- /dev/null
+++ b/lldb/include/lldb/Target/RegisterTypeUnion.h
@@ -0,0 +1,41 @@
+//===-- RegisterTypeUnion.h -------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_REGISTERTYPEUNION_H
+#define LLDB_TARGET_REGISTERTYPEUNION_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "lldb/Target/RegisterType.h"
+
+namespace lldb_private {
+
+class Stream;
+class Log;
+
+class RegisterTypeUnion : public RegisterType {
+public:
+ typedef std::vector<std::pair<std::string, const RegisterType *>> Fields;
+ RegisterTypeUnion(std::string id, const Fields &fields);
+
+ virtual void ToXMLElement(Stream &strm,
+ const RegisterType *user = nullptr) const override;
+
+ virtual void DumpToLog(Log *log) const override;
+
+ virtual unsigned GetSize() const override;
+
+private:
+ Fields m_fields;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_REGISTERTYPEUNION_H
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index dc2f259e87544..eebeba601abf6 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -39,6 +39,7 @@ add_lldb_library(lldbTarget
RegisterContext.cpp
RegisterContextUnwind.cpp
RegisterTypeFlags.cpp
+ RegisterTypeUnion.cpp
RegisterType.cpp
RegisterNumber.cpp
RemoteAwarePlatform.cpp
diff --git a/lldb/source/Target/RegisterTypeUnion.cpp b/lldb/source/Target/RegisterTypeUnion.cpp
new file mode 100644
index 0000000000000..07b8936ef3d37
--- /dev/null
+++ b/lldb/source/Target/RegisterTypeUnion.cpp
@@ -0,0 +1,75 @@
+//===-- RegisterTypeUnion.cpp ---------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/RegisterTypeUnion.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb_private;
+
+RegisterTypeUnion::RegisterTypeUnion(std::string id,
+ const RegisterTypeUnion::Fields &fields)
+ : RegisterType(eRegisterTypeKindUnion, id), m_fields(fields) {
+ std::vector<const RegisterType *> dependencies;
+ std::optional<unsigned> size;
+ UNUSED_IF_ASSERT_DISABLED(size);
+
+ for (const auto &field : m_fields) {
+ // All fields of the union must have the same size. When this class is
+ // constructed from XML, we assume that the XML parser has verified that.
+ // This assert is here in case these are constructed directly from C++.
+ if (size)
+ assert(field.second->GetSize() == *size &&
+ "All fields of a union must have the same size.");
+ else
+ size = field.second->GetSize();
+
+ dependencies.push_back(field.second);
+ }
+
+ SetDependencies(dependencies);
+}
+
+void RegisterTypeUnion::ToXMLElement(Stream &strm,
+ const RegisterType *user) const {
+ (void)user;
+ // Example XML:
+ // <union id="foo">
+ // <field name="some name" type="some type"/>
+ // </union>
+ strm.Indent();
+ strm << "<union id=\"" << GetID() << "\"";
+
+ if (m_fields.empty()) {
+ strm << "/>\n";
+ return;
+ } else
+ strm << ">\n";
+
+ strm.IndentMore();
+ for (const auto &field : m_fields) {
+ strm.Indent("<field name=\"");
+ strm << field.first << "\" type=\"" << field.second->GetID() << "\"/>\n";
+ }
+ strm.IndentLess();
+ strm.Indent("</union>\n");
+}
+
+void RegisterTypeUnion::DumpToLog(Log *log) const {
+ LLDB_LOG(log, "union ID: \"{0}\"", GetID().c_str());
+ for (const auto &field : m_fields)
+ LLDB_LOG(log, " Name: \"{0}\" Type: \"{1}\"", field.first.c_str(),
+ field.second->GetID());
+}
+
+unsigned RegisterTypeUnion::GetSize() const {
+ // We assume that the XML parser and/or class constructor checked that all
+ // fields have the same size. A union with no fields is valid, but you'll
+ // never be able to attach it to a register, which is what size of 0 means.
+ return m_fields.size() ? m_fields[0].second->GetSize() : 0;
+}
\ No newline at end of file
diff --git a/lldb/unittests/Target/RegisterTypeTest.cpp b/lldb/unittests/Target/RegisterTypeTest.cpp
index 48e5f5128c9d2..d81ed370cd96a 100644
--- a/lldb/unittests/Target/RegisterTypeTest.cpp
+++ b/lldb/unittests/Target/RegisterTypeTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterTypeUnion.h"
#include "lldb/Utility/StreamString.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -465,4 +466,21 @@ TEST(RegisterTypeTest, RegisterTypeFlagsToXML) {
" <field name=\"f4\" start=\"27\" end=\"28\" type=\"enum_c\"/>\n"
" <field name=\"f5\" start=\"25\" end=\"26\" type=\"enum_d\"/>\n"
"</flags>\n");
+}
+
+TEST(RegisterTypeTest, RegisterTypeUnionToXML) {
+ StreamString strm;
+ RegisterTypeUnion("foo", {}).ToXMLElement(strm);
+ ASSERT_EQ(strm.GetString(), "<union id=\"foo\"/>\n");
+
+ strm.Clear();
+
+ RegisterTypeFlags view_1("view_1", 4, {RegisterTypeFlags::Field("", 0, 0)});
+ RegisterTypeFlags view_2("view_2", 4, {RegisterTypeFlags::Field("", 0, 0)});
+ RegisterTypeUnion("bar", {{"1_view", &view_1}, {"2_view", &view_2}})
+ .ToXMLElement(strm);
+ ASSERT_EQ(strm.GetString(), "<union id=\"bar\">\n"
+ " <field name=\"1_view\" type=\"view_1\"/>\n"
+ " <field name=\"2_view\" type=\"view_2\"/>\n"
+ "</union>\n");
}
\ No newline at end of file
>From 4068879c33d1a661663bd5a762d0b86c2dd6bb07 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Fri, 6 Sep 2024 13:17:43 +0000
Subject: [PATCH 09/16] [lldb] Refactor RegisterTypeBuilder
This prepares it for emitting union types. Major changes:
* Entry function is now a dispatcher to builder functions for each type.
* Name mangling is standardised.
* The register name parameter is no longer needed and so was removed.
---
.../include/lldb/Target/RegisterTypeBuilder.h | 5 +-
lldb/include/lldb/Target/Target.h | 5 +-
lldb/source/Core/DumpRegisterValue.cpp | 4 +-
.../RegisterTypeBuilderClang.cpp | 212 ++++++++++--------
.../RegisterTypeBuilderClang.h | 16 +-
lldb/source/Target/Target.cpp | 6 +-
6 files changed, 140 insertions(+), 108 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterTypeBuilder.h b/lldb/include/lldb/Target/RegisterTypeBuilder.h
index c24d218962e39..5a37109661da0 100644
--- a/lldb/include/lldb/Target/RegisterTypeBuilder.h
+++ b/lldb/include/lldb/Target/RegisterTypeBuilder.h
@@ -19,9 +19,8 @@ class RegisterTypeBuilder : public PluginInterface {
~RegisterTypeBuilder() override = default;
virtual CompilerType
- GetRegisterType(const std::string &name,
- const lldb_private::RegisterType &type_info,
- uint32_t byte_size) = 0;
+ GetRegisterType(const lldb_private::RegisterType &type_info,
+ uint32_t register_byte_size) = 0;
protected:
RegisterTypeBuilder() = default;
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index 8ab75374cabf5..2718dcee2dc97 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -1483,9 +1483,8 @@ class Target : public std::enable_shared_from_this<Target>,
/// if none can be found.
llvm::Expected<lldb_private::Address> GetEntryPointAddress();
- CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterType &type_info,
- uint32_t byte_size);
+ CompilerType GetRegisterType(const lldb_private::RegisterType &type_info,
+ uint32_t register_byte_size);
/// Sends a breakpoint notification event.
void NotifyBreakpointChanged(Breakpoint &bp,
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index 94bc14f20c95b..d38dfe998e503 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -111,8 +111,8 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
(reg_info.byte_size != 4 && reg_info.byte_size != 8))
return;
- CompilerType register_type = target_sp->GetRegisterType(
- reg_info.name, *reg_info.register_type, reg_info.byte_size);
+ CompilerType register_type =
+ target_sp->GetRegisterType(*reg_info.register_type, reg_info.byte_size);
if (!register_type.IsValid())
return;
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index f13472fb6f9df..6c52ae957f4d2 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -8,10 +8,8 @@
#include "clang/AST/DeclCXX.h"
-#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "RegisterTypeBuilderClang.h"
#include "lldb/Core/PluginManager.h"
-#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb_private;
@@ -35,11 +33,119 @@ RegisterTypeBuilderClang::CreateInstance(Target &target) {
RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
: m_target(target) {}
+static std::string MakeTypeName(const RegisterType &type_info,
+ uint32_t register_byte_size) {
+ std::string type_name = "__lldb_register_fields_";
+ switch (type_info.getKind()) {
+ case RegisterType::eRegisterTypeKindFlags:
+ type_name += "flags_";
+ break;
+ case RegisterType::eRegisterTypeKindUnion:
+ type_name += "union_";
+ break;
+ case RegisterType::eRegisterTypeKindEnum:
+ // Enums can be used by many registers and the size of each register
+ // may be different. The register size is used as the underlying size
+ // of the enumerators, so we must make one enum type per register size
+ // it is used with.
+ type_name += "enum_" + std::to_string(register_byte_size) + "_";
+ break;
+ }
+
+ return type_name + type_info.GetID();
+}
+
+CompilerType
+RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum &enum_type_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system) {
+ std::string enum_type_name = MakeTypeName(enum_type_info, register_byte_size);
+
+ // Reuse existing type if we can.
+ if (CompilerType enum_type =
+ type_system->GetTypeForIdentifier<clang::EnumDecl>(
+ type_system->getASTContext(), enum_type_name))
+ return enum_type;
+
+ CompilerType register_uint_type =
+ type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
+ register_byte_size * 8);
+ CompilerType enum_type = type_system->CreateEnumerationType(
+ enum_type_name, type_system->GetTranslationUnitDecl(),
+ OptionalClangModuleID(), Declaration(), register_uint_type, false);
+
+ type_system->StartTagDeclarationDefinition(enum_type);
+
+ Declaration decl;
+ for (const auto &enumerator : enum_type_info.GetEnumerators()) {
+ type_system->AddEnumerationValueToEnumerationType(
+ enum_type, decl, enumerator.m_name.c_str(), enumerator.m_value,
+ register_byte_size * 8);
+ }
+
+ type_system->CompleteTagDeclarationDefinition(enum_type);
+
+ return enum_type;
+}
+
+CompilerType RegisterTypeBuilderClang::BuildFlagsType(
+ const lldb_private::RegisterTypeFlags &flags_info,
+ uint32_t register_byte_size, lldb::TypeSystemClangSP type_system) {
+ std::string register_type_name = MakeTypeName(flags_info, register_byte_size);
+
+ // Reuse existing type if we can.
+ if (CompilerType flags_type =
+ type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
+ type_system->getASTContext(), register_type_name))
+ return flags_type;
+
+ // In most ABI, a change of field type means a change in storage unit.
+ // We want it all in one unit, so we use a field type the same as the
+ // register's size.
+ CompilerType field_uint_type =
+ type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
+ register_byte_size * 8);
+
+ CompilerType flags_type = type_system->CreateRecordType(
+ nullptr, OptionalClangModuleID(), register_type_name,
+ llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
+ type_system->StartTagDeclarationDefinition(flags_type);
+ llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
+
+ for (auto field : flags_info.GetFields()) {
+ CompilerType field_type = field_uint_type;
+
+ if (const RegisterTypeEnum *enum_type_info = field.GetEnum())
+ if (!enum_type_info->GetEnumerators().empty())
+ field_type =
+ BuildEnumType(*enum_type_info, register_byte_size, type_system);
+
+ clang::FieldDecl *field_decl = type_system->AddFieldToRecordType(
+ flags_type, field.GetName(), field_type, field.GetSizeInBits());
+ field_offsets.insert({field_decl, field.GetStart()});
+ }
+
+ m_external_ast->m_struct_layouts.insert(
+ {type_system->GetAsRecordDecl(flags_type),
+ RegisterExternalASTSource::LayoutInfo{register_byte_size,
+ field_offsets}});
+
+ type_system->CompleteTagDeclarationDefinition(flags_type);
+ // So that the size of the type matches the size of the register.
+ type_system->SetIsPacked(flags_type);
+
+ // This should be true if RegisterFlags padded correctly.
+ assert(
+ llvm::expectedToOptional(flags_type.GetByteSize(nullptr)).value_or(0) ==
+ flags_info.GetSize());
+
+ return flags_type;
+}
+
CompilerType RegisterTypeBuilderClang::GetRegisterType(
- const std::string &name, const lldb_private::RegisterType &type_info,
- uint32_t byte_size) {
- lldb::TypeSystemClangSP type_system = ScratchTypeSystemClang::GetForTarget(
- m_target, ScratchTypeSystemClang::IsolatedASTKind::Registers);
+ const lldb_private::RegisterType &type_info, uint32_t register_byte_size) {
+ lldb::TypeSystemClangSP type_system =
+ ScratchTypeSystemClang::GetForTarget(m_target);
assert(type_system);
if (!m_external_ast) {
@@ -47,93 +153,13 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
type_system->SetExternalSource(m_external_ast);
}
- std::string register_type_name = "__lldb_register_fields_" + name;
- // For now we can only build sets of flags.
- const RegisterTypeFlags *flags =
- llvm::dyn_cast<RegisterTypeFlags>(&type_info);
- if (!flags)
+ switch (type_info.getKind()) {
+ case RegisterType::eRegisterTypeKindFlags:
+ return BuildFlagsType(*llvm::dyn_cast<RegisterTypeFlags>(&type_info),
+ register_byte_size, type_system);
+ case RegisterType::eRegisterTypeKindUnion:
+ return {};
+ case RegisterType::eRegisterTypeKindEnum:
return {};
-
- // See if we have made this type before and can reuse it.
- CompilerType fields_type =
- type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
- type_system->getASTContext(), register_type_name);
-
- if (!fields_type) {
- // In most ABI, a change of field type means a change in storage unit.
- // We want it all in one unit, so we use a field type the same as the
- // register's size.
- CompilerType field_uint_type =
- type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
- byte_size * 8);
-
- fields_type = type_system->CreateRecordType(
- nullptr, OptionalClangModuleID(), register_type_name,
- llvm::to_underlying(clang::TagTypeKind::Struct), lldb::eLanguageTypeC);
- type_system->StartTagDeclarationDefinition(fields_type);
- llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
-
- // We assume that RegisterFlags has padded and sorted the fields
- // already.
- for (const RegisterTypeFlags::Field &field : flags->GetFields()) {
- CompilerType field_type = field_uint_type;
-
- if (const RegisterTypeEnum *enum_type = field.GetEnum()) {
- const RegisterTypeEnum::Enumerators &enumerators =
- enum_type->GetEnumerators();
- if (!enumerators.empty()) {
- // Enums can be used by many registers and the size of each register
- // may be different. The register size is used as the underlying size
- // of the enumerators, so we must make one enum type per register size
- // it is used with.
- std::string enum_type_name = "__lldb_register_fields_enum_" +
- enum_type->GetID() + "_" +
- std::to_string(byte_size);
-
- // Enums can be used by mutiple fields and multiple registers, so we
- // may have built this one already.
- CompilerType field_enum_type =
- type_system->GetTypeForIdentifier<clang::EnumDecl>(
- type_system->getASTContext(), enum_type_name);
-
- if (field_enum_type)
- field_type = field_enum_type;
- else {
- field_type = type_system->CreateEnumerationType(
- enum_type_name, type_system->GetTranslationUnitDecl(),
- OptionalClangModuleID(), Declaration(), field_uint_type, false);
-
- type_system->StartTagDeclarationDefinition(field_type);
-
- Declaration decl;
- for (auto enumerator : enumerators) {
- type_system->AddEnumerationValueToEnumerationType(
- field_type, decl, enumerator.m_name.c_str(),
- enumerator.m_value, byte_size * 8);
- }
-
- type_system->CompleteTagDeclarationDefinition(field_type);
- }
- }
- }
-
- clang::FieldDecl *field_decl = type_system->AddFieldToRecordType(
- fields_type, field.GetName(), field_type, field.GetSizeInBits());
- field_offsets.insert({field_decl, field.GetStart()});
- }
-
- m_external_ast->m_struct_layouts.insert(
- {type_system->GetAsRecordDecl(fields_type),
- RegisterExternalASTSource::LayoutInfo{byte_size, field_offsets}});
-
- type_system->CompleteTagDeclarationDefinition(fields_type);
- // So that the size of the type matches the size of the register.
- type_system->SetIsPacked(fields_type);
-
- // This should be true if RegisterFlags padded correctly.
- assert(llvm::expectedToOptional(fields_type.GetByteSize(nullptr))
- .value_or(0) == flags->GetSize());
}
-
- return fields_type;
}
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index c8908da5c854e..c0e91951b83af 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -11,7 +11,9 @@
#include "clang/AST/ExternalASTSource.h"
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Target/RegisterTypeBuilder.h"
+#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Target/Target.h"
namespace lldb_private {
@@ -30,9 +32,8 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
}
static lldb::RegisterTypeBuilderSP CreateInstance(Target &target);
- CompilerType GetRegisterType(const std::string &name,
- const lldb_private::RegisterType &type_info,
- uint32_t byte_size) override;
+ CompilerType GetRegisterType(const lldb_private::RegisterType &type_info,
+ uint32_t register_byte_size) override;
private:
/// This external AST is used to override the layout of bitfield structs
@@ -78,6 +79,15 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
}
};
+private:
+ CompilerType BuildEnumType(const RegisterTypeEnum &enum_type_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system);
+
+ CompilerType BuildFlagsType(const RegisterTypeFlags &flags_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system);
+
// This is created the first time a register type is requested, then handed
// to the type system. We keep a reference to it so we can add more layouts
// as more register types are requested.
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index d6660b7da16f6..f9955d37679a5 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -2632,14 +2632,12 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language,
}
CompilerType
-Target::GetRegisterType(const std::string &name,
- const lldb_private::RegisterType &type_info,
+Target::GetRegisterType(const lldb_private::RegisterType &type_info,
uint32_t byte_size) {
if (!m_register_type_builder_sp)
m_register_type_builder_sp = PluginManager::GetRegisterTypeBuilder(*this);
assert(m_register_type_builder_sp);
- return m_register_type_builder_sp->GetRegisterType(name, type_info,
- byte_size);
+ return m_register_type_builder_sp->GetRegisterType(type_info, byte_size);
}
std::vector<lldb::TypeSystemSP>
>From b07734b18c37256b6e5603ed1294911e3929cece Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Fri, 6 Sep 2024 10:08:24 +0000
Subject: [PATCH 10/16] WIP: parse unions from XML
TODO: tests????
---
lldb/include/lldb/Target/RegisterTypeUnion.h | 3 +-
.../Process/gdb-remote/ProcessGDBRemote.cpp | 113 ++++++++++++++++++
2 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/lldb/include/lldb/Target/RegisterTypeUnion.h b/lldb/include/lldb/Target/RegisterTypeUnion.h
index 1c59dea40cf49..ed89f3f05a7a8 100644
--- a/lldb/include/lldb/Target/RegisterTypeUnion.h
+++ b/lldb/include/lldb/Target/RegisterTypeUnion.h
@@ -22,7 +22,8 @@ class Log;
class RegisterTypeUnion : public RegisterType {
public:
- typedef std::vector<std::pair<std::string, const RegisterType *>> Fields;
+ typedef std::pair<std::string, const RegisterType *> Field;
+ typedef std::vector<Field> Fields;
RegisterTypeUnion(std::string id, const Fields &fields);
virtual void ToXMLElement(Stream &strm,
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 4a1d5e611d96b..abddb97e6ccf9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -56,6 +56,7 @@
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterTypeUnion.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -4923,6 +4924,116 @@ void ParseFlags(
});
}
+RegisterTypeUnion::Fields ParseUnionFields(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ RegisterTypeUnion::Fields fields;
+
+ feature_node.ForEachChildElementWithName(
+ "field",
+ [&log, ®ister_types, &fields](const XMLNode &field_node) -> bool {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseUnionFields Found field node \"{0}\"",
+ field_node.GetAttributeValue("name").c_str());
+
+ std::optional<llvm::StringRef> field_name;
+ std::optional<llvm::StringRef> field_type;
+
+ field_node.ForEachAttribute(
+ [&field_name, &field_type, &log](const llvm::StringRef &name,
+ const llvm::StringRef &value) {
+ if (name == "name")
+ field_name = value;
+ else if (name == "type")
+ field_type = value;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseUnionFields Ignoring unknown "
+ "attribute \"{0}\" in field node",
+ name.data());
+ }
+ return true; // Walk all attributes.
+ });
+
+ if (field_name && field_type) {
+ auto referenced_type = register_types.find(*field_type);
+ if (referenced_type != register_types.end()) {
+ fields.push_back(RegisterTypeUnion::Field(
+ *field_name, referenced_type->second.get()));
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseUnionFields field \"{0}\" "
+ "references unknown type \"{1}\", ignoring field",
+ field_name->data(), field_type->data());
+ }
+ }
+
+ return true; // Walk all fields.
+ });
+
+ return fields;
+}
+
+void ParseUnions(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ feature_node.ForEachChildElementWithName(
+ "union", [&log, ®ister_types](const XMLNode &union_node) -> bool {
+ LLDB_LOG(log, "ProcessGDBRemote::ParseUnions Found union node \"{0}\"",
+ union_node.GetAttributeValue("id").c_str());
+
+ std::optional<llvm::StringRef> id;
+ union_node.ForEachAttribute([&id, &log](const llvm::StringRef &name,
+ const llvm::StringRef &value) {
+ if (name == "id")
+ id = value;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseUnions Ignoring unknown "
+ "attribute \"{0}\" in union node",
+ name.data());
+ }
+ return true; // Walk all attributes.
+ });
+
+ if (id) {
+ RegisterTypeUnion::Fields fields =
+ ParseUnionFields(union_node, register_types);
+ if (fields.size()) {
+ if (register_types.contains(*id)) {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseUnions Definition of union with ID "
+ "\"{0}\" shadows "
+ "previous use of that ID, using original definition "
+ "instead.",
+ id->data());
+ } else {
+ // TODO: for now we're assuming that we parse all the things a
+ // union could reference, then parse unions. In future we might
+ // want to parse everything then walk all the types to make sure
+ // all references are valid.
+ register_types.insert_or_assign(
+ *id, std::make_unique<RegisterTypeUnion>(id->str(),
+ std::move(fields)));
+ }
+ } else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseUnions Ignoring definition of union "
+ "\"{0}\" because it contains no valid fields.",
+ id->data());
+ }
+ }
+
+ return true; // Keep iterating through all "union" elements.
+ });
+}
+
bool ParseRegisters(
XMLNode feature_node, GdbServerTargetInfo &target_info,
std::vector<DynamicRegisterInfo::Register> ®isters,
@@ -4935,6 +5046,8 @@ bool ParseRegisters(
// Enums first because they are referenced by fields in the flags.
ParseEnums(feature_node, register_types);
ParseFlags(feature_node, register_types);
+ // TODO: this has to be last as it may reference the others.
+ ParseUnions(feature_node, register_types);
for (const auto ®ister_type : register_types)
register_type.second->DumpToLog(log);
>From 0c8ecfab18300fef754e40d41eac629baebb1072 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Fri, 6 Sep 2024 13:51:37 +0000
Subject: [PATCH 11/16] [lldb] Generate union types in RegisterBuilderClang
TODO: add some XML tests to prove this works
TODO: register info support
---
lldb/include/lldb/Target/RegisterTypeUnion.h | 8 ++++
.../Process/gdb-remote/ProcessGDBRemote.cpp | 16 +++++--
.../RegisterTypeBuilderClang.cpp | 46 ++++++++++++++++++-
lldb/source/Target/RegisterTypeUnion.cpp | 36 +++++++++------
4 files changed, 89 insertions(+), 17 deletions(-)
diff --git a/lldb/include/lldb/Target/RegisterTypeUnion.h b/lldb/include/lldb/Target/RegisterTypeUnion.h
index ed89f3f05a7a8..3a50b8838d16c 100644
--- a/lldb/include/lldb/Target/RegisterTypeUnion.h
+++ b/lldb/include/lldb/Target/RegisterTypeUnion.h
@@ -33,6 +33,14 @@ class RegisterTypeUnion : public RegisterType {
virtual unsigned GetSize() const override;
+ const Fields &GetFields() const { return m_fields; }
+
+ static bool classof(const RegisterType *register_type) {
+ return register_type->getKind() == RegisterType::eRegisterTypeKindUnion;
+ }
+
+ static bool ValidateFields(const Fields &fields);
+
private:
Fields m_fields;
};
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index abddb97e6ccf9..e020dcde4234e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5017,9 +5017,19 @@ void ParseUnions(
// union could reference, then parse unions. In future we might
// want to parse everything then walk all the types to make sure
// all references are valid.
- register_types.insert_or_assign(
- *id, std::make_unique<RegisterTypeUnion>(id->str(),
- std::move(fields)));
+
+ if (RegisterTypeUnion::ValidateFields(fields))
+ register_types.insert_or_assign(
+ *id, std::make_unique<RegisterTypeUnion>(
+ id->str(), std::move(fields)));
+ else {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseUnions not all fields of "
+ "union \"{0}\" "
+ "have the same size and have non-zero size, ignoring union",
+ id->data());
+ }
}
} else {
LLDB_LOG(
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index 6c52ae957f4d2..f0c3d9bdc0297 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -142,6 +142,49 @@ CompilerType RegisterTypeBuilderClang::BuildFlagsType(
return flags_type;
}
+CompilerType
+RegisterTypeBuilderClang::BuildUnionType(const lldb_private::RegisterTypeUnion &union_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system) {
+ std::string union_type_name = MakeTypeName(union_info, register_byte_size);
+
+ // Reuse existing type if we can.
+ if (CompilerType union_type =
+ type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
+ type_system->getASTContext(), union_type_name))
+ return union_type;
+
+ CompilerType union_type = type_system->CreateRecordType(
+ nullptr, OptionalClangModuleID(), union_type_name,
+ llvm::to_underlying(clang::TagTypeKind::Union), lldb::eLanguageTypeC);
+ type_system->StartTagDeclarationDefinition(union_type);
+
+ for (const RegisterTypeUnion::Field &field : union_info.GetFields()) {
+ auto [name, type_info] = field;
+ // Unions can in theory reference any other type, but we will start by only
+ // supporting flags here.
+ CompilerType field_type;
+
+ switch (type_info->getKind()) {
+ case RegisterType::eRegisterTypeKindEnum:
+ break;
+ case RegisterType::eRegisterTypeKindUnion:
+ break;
+ case RegisterType::eRegisterTypeKindFlags:
+ field_type = BuildFlagsType(*llvm::dyn_cast<RegisterTypeFlags>(type_info),
+ register_byte_size, type_system);
+ break;
+ }
+
+ if (field_type.IsValid())
+ type_system->AddFieldToRecordType(union_type, name, field_type, 0);
+ }
+
+ type_system->CompleteTagDeclarationDefinition(union_type);
+
+ return union_type;
+}
+
CompilerType RegisterTypeBuilderClang::GetRegisterType(
const lldb_private::RegisterType &type_info, uint32_t register_byte_size) {
lldb::TypeSystemClangSP type_system =
@@ -158,7 +201,8 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
return BuildFlagsType(*llvm::dyn_cast<RegisterTypeFlags>(&type_info),
register_byte_size, type_system);
case RegisterType::eRegisterTypeKindUnion:
- return {};
+ return BuildUnionType(*llvm::dyn_cast<RegisterTypeUnion>(&type_info),
+ register_byte_size, type_system);
case RegisterType::eRegisterTypeKindEnum:
return {};
}
diff --git a/lldb/source/Target/RegisterTypeUnion.cpp b/lldb/source/Target/RegisterTypeUnion.cpp
index 07b8936ef3d37..4b1ac53fde021 100644
--- a/lldb/source/Target/RegisterTypeUnion.cpp
+++ b/lldb/source/Target/RegisterTypeUnion.cpp
@@ -15,24 +15,34 @@ using namespace lldb_private;
RegisterTypeUnion::RegisterTypeUnion(std::string id,
const RegisterTypeUnion::Fields &fields)
: RegisterType(eRegisterTypeKindUnion, id), m_fields(fields) {
+ // We assume the XML processor also checked this, so this assert is only for
+ // unions created directly from C++ (or in other words, for lldb's built in
+ // register types).
+ assert(ValidateFields(m_fields) &&
+ "All fields of a union must have the same size, "
+ "and their size must be non-zero.");
+
std::vector<const RegisterType *> dependencies;
- std::optional<unsigned> size;
- UNUSED_IF_ASSERT_DISABLED(size);
+ for (const auto &field : m_fields)
+ dependencies.push_back(field.second);
- for (const auto &field : m_fields) {
- // All fields of the union must have the same size. When this class is
- // constructed from XML, we assume that the XML parser has verified that.
- // This assert is here in case these are constructed directly from C++.
- if (size)
- assert(field.second->GetSize() == *size &&
- "All fields of a union must have the same size.");
- else
- size = field.second->GetSize();
+ SetDependencies(dependencies);
+}
- dependencies.push_back(field.second);
+bool RegisterTypeUnion::ValidateFields(
+ const RegisterTypeUnion::Fields &fields) {
+ std::optional<unsigned> size;
+ for (const auto &field : fields) {
+ // All fields of the union must have the same size, and no field can have 0
+ // size.
+ if (size) {
+ if (!size || field.second->GetSize() != *size)
+ return false;
+ } else
+ size = field.second->GetSize();
}
- SetDependencies(dependencies);
+ return true;
}
void RegisterTypeUnion::ToXMLElement(Stream &strm,
>From 864520746a59385dfd2b2abe6986b127588e8fd9 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Fri, 6 Sep 2024 11:15:13 +0000
Subject: [PATCH 12/16] WIP: add hacky union for testing
---
.../Utility/RegisterTypeDetector_arm64.cpp | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index ed9d914f18317..063d9562b51fc 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -8,6 +8,7 @@
#include "RegisterTypeDetector_arm64.h"
#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterTypeUnion.h"
#include "lldb/lldb-private-types.h"
// This file is built on all systems because it is used by native processes and
@@ -295,7 +296,23 @@ const RegisterType *Arm64RegisterTypeDetector::DetectCPSRType(uint64_t hwcap,
cpsr_flags.SetFields(cpsr_fields);
- return &cpsr_flags;
+ static RegisterTypeFlags cpsr_flags_reversed("cpsr_raw_bits", 4, {});
+ const static std::vector<RegisterTypeFlags::Field> raw_bits{
+ {"31", 31}, {"30", 30}, {"29", 29}, {"28", 28}, {"27", 27}, {"26", 26},
+ {"25", 25}, {"24", 24}, {"23", 23}, {"22", 22}, {"21", 21}, {"20", 20},
+ {"19", 19}, {"18", 18}, {"17", 17}, {"16", 16}, {"15", 15}, {"14", 14},
+ {"13", 13}, {"12", 12}, {"11", 11}, {"10", 10}, {"9", 9}, {"8", 8},
+ {"7", 7}, {"6", 6}, {"5", 5}, {"4", 4}, {"3", 3}, {"2", 2},
+ {"1", 1}, {"0", 0},
+ };
+
+ cpsr_flags_reversed.SetFields(raw_bits);
+
+ static RegisterTypeUnion cpsr_union(
+ "cpsr_union",
+ {{"normal", &cpsr_flags}, {"raw_bits", &cpsr_flags_reversed}});
+
+ return &cpsr_union;
}
void Arm64RegisterTypeDetector::DetectTypes(uint64_t hwcap, uint64_t hwcap2,
>From ece03d1d09a2ae05335f048f02723ab87e6b1b83 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 11 Mar 2026 18:05:12 +0000
Subject: [PATCH 13/16] better demo of union problem and why this is a better
solution
---
.../Utility/RegisterTypeDetector_arm64.cpp | 19 +++++++++++++++++++
.../Utility/RegisterTypeDetector_arm64.h | 5 ++++-
.../RegisterTypeBuilderClang.h | 5 +++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index 063d9562b51fc..64fe54f19702b 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -244,6 +244,25 @@ const RegisterType *Arm64RegisterTypeDetector::DetectFPSRType(uint64_t hwcap,
return &fpsr_flags;
}
+const RegisterType *Arm64RegisterTypeDetector::DetectX0Type(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
+ (void)hwcap;
+ (void)hwcap2;
+ (void)hwcap3;
+
+ static RegisterTypeFlags x0_flags_lhs("x0_flags_lhs", 8, {
+ {"w", 16, 63}, {"x", 0, 15}});
+ static RegisterTypeFlags x0_flags_rhs("x0_flags_rhs", 8, {
+ {"y", 48, 63}, {"z", 0, 47}});
+
+ static RegisterTypeUnion x0_union(
+ "x0_union",
+ {{"lhs", &x0_flags_lhs}, {"rhs", &x0_flags_rhs}});
+
+ return &x0_union;
+}
+
const RegisterType *Arm64RegisterTypeDetector::DetectCPSRType(uint64_t hwcap,
uint64_t hwcap2,
uint64_t hwcap3) {
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
index 7388756b71e91..f411009c75723 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
@@ -67,6 +67,8 @@ class Arm64RegisterTypeDetector {
uint64_t hwcap3);
static const RegisterType *DetectFPMRType(uint64_t hwcap, uint64_t hwcap2,
uint64_t hwcap3);
+ static const RegisterType *DetectX0Type(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
static const RegisterType *
DetectGCSFeaturesType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3);
static const RegisterType *DetectPOREL0Type(uint64_t hwcap, uint64_t hwcap2,
@@ -79,7 +81,7 @@ class Arm64RegisterTypeDetector {
llvm::StringRef m_name;
const RegisterType *m_type;
DetectorFn m_detector;
- } m_registers[9] = {
+ } m_registers[10] = {
RegisterEntry("cpsr", 4, DetectCPSRType),
RegisterEntry("fpsr", 4, DetectFPSRType),
RegisterEntry("fpcr", 4, DetectFPCRType),
@@ -89,6 +91,7 @@ class Arm64RegisterTypeDetector {
RegisterEntry("gcs_features_enabled", 8, DetectGCSFeaturesType),
RegisterEntry("gcs_features_locked", 8, DetectGCSFeaturesType),
RegisterEntry("por_el0", 8, DetectPOREL0Type),
+ RegisterEntry("x0", 8, DetectX0Type),
};
// Becomes true once field detection has been run for all registers.
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index c0e91951b83af..7ecdf49ecfe26 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -14,6 +14,7 @@
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Target/RegisterTypeBuilder.h"
#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterTypeUnion.h"
#include "lldb/Target/Target.h"
namespace lldb_private {
@@ -88,6 +89,10 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system);
+ CompilerType BuildUnionType(const RegisterTypeUnion &union_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system);
+
// This is created the first time a register type is requested, then handed
// to the type system. We keep a reference to it so we can add more layouts
// as more register types are requested.
>From 3e6683d8547ce09beb22b1ff72b3dae6518b2b41 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at linaro.org>
Date: Mon, 9 Sep 2024 08:31:05 +0000
Subject: [PATCH 14/16] WIP: vectors
---
lldb/include/lldb/Target/RegisterType.h | 1 +
lldb/include/lldb/Target/RegisterTypeVector.h | 57 +++++++++++++++++
.../Utility/RegisterTypeDetector_arm64.cpp | 25 ++++++--
.../Process/gdb-remote/ProcessGDBRemote.cpp | 64 +++++++++++++++++++
.../RegisterTypeBuilderClang.cpp | 38 +++++++++--
.../RegisterTypeBuilderClang.h | 7 +-
lldb/source/Target/CMakeLists.txt | 1 +
lldb/source/Target/RegisterTypeVector.cpp | 64 +++++++++++++++++++
8 files changed, 247 insertions(+), 10 deletions(-)
create mode 100644 lldb/include/lldb/Target/RegisterTypeVector.h
create mode 100644 lldb/source/Target/RegisterTypeVector.cpp
diff --git a/lldb/include/lldb/Target/RegisterType.h b/lldb/include/lldb/Target/RegisterType.h
index b9589c71b413b..2e45ec558c46c 100644
--- a/lldb/include/lldb/Target/RegisterType.h
+++ b/lldb/include/lldb/Target/RegisterType.h
@@ -24,6 +24,7 @@ class RegisterType {
eRegisterTypeKindFlags,
eRegisterTypeKindEnum,
eRegisterTypeKindUnion,
+ eRegisterTypeKindVector,
};
RegisterTypeKind getKind() const { return m_kind; }
diff --git a/lldb/include/lldb/Target/RegisterTypeVector.h b/lldb/include/lldb/Target/RegisterTypeVector.h
new file mode 100644
index 0000000000000..61c55e1b3769f
--- /dev/null
+++ b/lldb/include/lldb/Target/RegisterTypeVector.h
@@ -0,0 +1,57 @@
+//===-- RegisterTypeVector.h -------------------------------------*- ++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_REGISTERTYPEVECTOR_H
+#define LLDB_TARGET_REGISTERTYPEVECTOR_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "lldb/Target/RegisterType.h"
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private {
+
+class Stream;
+class Log;
+
+class RegisterTypeVector : public RegisterType {
+public:
+ RegisterTypeVector(std::string id, std::string type, unsigned count);
+
+ virtual void ToXMLElement(Stream &strm,
+ const RegisterType *user = nullptr) const override;
+
+ virtual void DumpToLog(Log *log) const override;
+
+ virtual unsigned GetSize() const override;
+
+ static bool classof(const RegisterType *register_type) {
+ return register_type->getKind() == RegisterType::eRegisterTypeKindVector;
+ }
+
+ const std::string &GetType() const { return m_type; }
+
+ unsigned GetCount() const { return m_count; }
+
+ struct ElementTypeInfo {
+ lldb::Encoding encoding = lldb::eEncodingInvalid;
+ unsigned size = 0;
+ };
+ ElementTypeInfo GetElementTypeInfo() const { return m_element_type_info; }
+
+private:
+ std::string m_type;
+ unsigned m_count;
+ ElementTypeInfo m_element_type_info;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_REGISTERTYPEVECTOR_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index 64fe54f19702b..ebdac68ec752e 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -9,6 +9,7 @@
#include "RegisterTypeDetector_arm64.h"
#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Target/RegisterTypeUnion.h"
+#include "lldb/Target/RegisterTypeVector.h"
#include "lldb/lldb-private-types.h"
// This file is built on all systems because it is used by native processes and
@@ -256,9 +257,17 @@ const RegisterType *Arm64RegisterTypeDetector::DetectX0Type(uint64_t hwcap,
static RegisterTypeFlags x0_flags_rhs("x0_flags_rhs", 8, {
{"y", 48, 63}, {"z", 0, 47}});
+ static RegisterTypeVector x0_vec8( "x0_vec8", "uint8", 8);
+ static RegisterTypeVector x0_vec16("x0_vec16", "uint16", 4);
+ static RegisterTypeVector x0_vec32("x0_vec32", "uint32", 2);
+ static RegisterTypeUnion x0_vec_union(
+ "x0_vec_union",
+ {{"8", &x0_vec8}, {"16", &x0_vec16}, {"32", &x0_vec32}});
+
static RegisterTypeUnion x0_union(
"x0_union",
- {{"lhs", &x0_flags_lhs}, {"rhs", &x0_flags_rhs}});
+ {{"lhs", &x0_flags_lhs}, {"rhs", &x0_flags_rhs},
+ {"vector", &x0_vec_union}});
return &x0_union;
}
@@ -327,9 +336,17 @@ const RegisterType *Arm64RegisterTypeDetector::DetectCPSRType(uint64_t hwcap,
cpsr_flags_reversed.SetFields(raw_bits);
- static RegisterTypeUnion cpsr_union(
- "cpsr_union",
- {{"normal", &cpsr_flags}, {"raw_bits", &cpsr_flags_reversed}});
+ static RegisterTypeVector cpsr_vec8("cpsr_vec8", "uint8", 4);
+ static RegisterTypeVector cpsr_vec16("cpsr_vec16", "uint16", 2);
+ static RegisterTypeVector cpsr_vec32("cpsr_vec32", "uint32", 1);
+ static RegisterTypeUnion cpsr_vec_union(
+ "cpsr_vec_union",
+ {{"8", &cpsr_vec8}, {"16", &cpsr_vec16}, {"32", &cpsr_vec32}});
+
+ static RegisterTypeUnion cpsr_union("cpsr_union",
+ {{"normal", &cpsr_flags},
+ {"raw_bits", &cpsr_flags_reversed},
+ {"vectors", &cpsr_vec_union}});
return &cpsr_union;
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index e020dcde4234e..ffb7b8da018d9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -57,6 +57,7 @@
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/RegisterTypeFlags.h"
#include "lldb/Target/RegisterTypeUnion.h"
+#include "lldb/Target/RegisterTypeVector.h"
#include "lldb/Target/SystemRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/TargetList.h"
@@ -5044,6 +5045,66 @@ void ParseUnions(
});
}
+void ParseVectors(
+ XMLNode feature_node,
+ llvm::StringMap<std::unique_ptr<RegisterType>> ®ister_types) {
+ Log *log(GetLog(GDBRLog::Process));
+
+ feature_node.ForEachChildElementWithName(
+ "vector", [&log, ®ister_types](const XMLNode &union_node) -> bool {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseVectors Found vector node \"{0}\"",
+ union_node.GetAttributeValue("id").c_str());
+
+ std::optional<llvm::StringRef> id;
+ std::optional<llvm::StringRef> type;
+ std::optional<unsigned> count;
+ union_node.ForEachAttribute([&id, &type, &count,
+ &log](const llvm::StringRef &name,
+ const llvm::StringRef &value) {
+ if (name == "id")
+ id = value;
+ else if (name == "type")
+ type = value;
+ else if (name == "count") {
+ unsigned parsed_count = 0;
+ if (llvm::to_integer(value, parsed_count))
+ count = parsed_count;
+ else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseVectors Invalid count \"{0}\" "
+ "in vector node",
+ value.data());
+ }
+ } else {
+ LLDB_LOG(log,
+ "ProcessGDBRemote::ParseVectors Ignoring unknown "
+ "attribute \"{0}\" in vector node",
+ name.data());
+ }
+ return true; // Walk all attributes.
+ });
+
+ if (id && type && count) {
+ if (register_types.contains(*id)) {
+ LLDB_LOG(
+ log,
+ "ProcessGDBRemote::ParseVectors Definition of vector with ID "
+ "\"{0}\" shadows "
+ "previous use of that ID, using original definition "
+ "instead.",
+ id->data());
+ } else {
+ register_types.insert_or_assign(
+ *id, std::make_unique<RegisterTypeVector>(id->str(),
+ type->str(), *count));
+ }
+ }
+
+ return true; // Keep iterating through all "vector" elements.
+ });
+}
+
bool ParseRegisters(
XMLNode feature_node, GdbServerTargetInfo &target_info,
std::vector<DynamicRegisterInfo::Register> ®isters,
@@ -5055,6 +5116,7 @@ bool ParseRegisters(
// Enums first because they are referenced by fields in the flags.
ParseEnums(feature_node, register_types);
+ ParseVectors(feature_node, register_types);
ParseFlags(feature_node, register_types);
// TODO: this has to be last as it may reference the others.
ParseUnions(feature_node, register_types);
@@ -5151,6 +5213,7 @@ bool ParseRegisters(
else
LLDB_LOG(
log,
+ // TODO: make this error generic!
"ProcessGDBRemote::ParseRegisters Size of register flags {0} "
"({1} bytes) for register {2} does not match the register "
"size ({3} bytes). Ignoring this set of flags.",
@@ -5158,6 +5221,7 @@ bool ParseRegisters(
reg_info.name, reg_info.byte_size);
}
+ // TODO: update comment to refer to types not flags!!!
// 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).
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
index f0c3d9bdc0297..01b3e1b759eae 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -50,15 +50,33 @@ static std::string MakeTypeName(const RegisterType &type_info,
// it is used with.
type_name += "enum_" + std::to_string(register_byte_size) + "_";
break;
+ case RegisterType::eRegisterTypeKindVector:
+ // Since array types are not declared (there is no "array" keyword"),
+ // they do not have names and do not need to be cached.
+ break;
}
return type_name + type_info.GetID();
}
CompilerType
-RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum &enum_type_info,
- uint32_t register_byte_size,
- lldb::TypeSystemClangSP type_system) {
+RegisterTypeBuilderClang::BuildVectorType(const lldb_private::RegisterTypeVector &vector_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system) {
+ // Don't need to check for existing types because all array types are
+ // pre-existing. This also means they do not have unique names.
+ auto element_info = vector_info.GetElementTypeInfo();
+ CompilerType element_type = type_system->GetBuiltinTypeForEncodingAndBitSize(
+ element_info.encoding, element_info.size * 8);
+ // If we didn't recognise the vector's "type", element_type may be invalid,
+ // but CreateArrayType already checks for this.
+ return type_system->CreateArrayType(element_type, vector_info.GetCount(),
+ /*is_vector=*/true);
+}
+
+CompilerType RegisterTypeBuilderClang::BuildEnumType(const RegisterTypeEnum &enum_type_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system) {
std::string enum_type_name = MakeTypeName(enum_type_info, register_byte_size);
// Reuse existing type if we can.
@@ -161,14 +179,21 @@ RegisterTypeBuilderClang::BuildUnionType(const lldb_private::RegisterTypeUnion &
for (const RegisterTypeUnion::Field &field : union_info.GetFields()) {
auto [name, type_info] = field;
- // Unions can in theory reference any other type, but we will start by only
- // supporting flags here.
+ // Unions can in theory reference anything, but we are not supporting all
+ // combinations right now.
CompilerType field_type;
switch (type_info->getKind()) {
case RegisterType::eRegisterTypeKindEnum:
break;
case RegisterType::eRegisterTypeKindUnion:
+ field_type = BuildUnionType(*llvm::dyn_cast<RegisterTypeUnion>(type_info),
+ register_byte_size, type_system);
+ break;
+ case RegisterType::eRegisterTypeKindVector:
+ field_type =
+ BuildVectorType(*llvm::dyn_cast<RegisterTypeVector>(type_info),
+ register_byte_size, type_system);
break;
case RegisterType::eRegisterTypeKindFlags:
field_type = BuildFlagsType(*llvm::dyn_cast<RegisterTypeFlags>(type_info),
@@ -203,6 +228,9 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType(
case RegisterType::eRegisterTypeKindUnion:
return BuildUnionType(*llvm::dyn_cast<RegisterTypeUnion>(&type_info),
register_byte_size, type_system);
+ case RegisterType::eRegisterTypeKindVector:
+ return BuildVectorType(*llvm::dyn_cast<RegisterTypeVector>(&type_info),
+ register_byte_size, type_system);
case RegisterType::eRegisterTypeKindEnum:
return {};
}
diff --git a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
index 7ecdf49ecfe26..498e4b43f57ba 100644
--- a/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
+++ b/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -14,6 +14,7 @@
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/Target/RegisterTypeBuilder.h"
#include "lldb/Target/RegisterTypeFlags.h"
+#include "lldb/Target/RegisterTypeVector.h"
#include "lldb/Target/RegisterTypeUnion.h"
#include "lldb/Target/Target.h"
@@ -88,8 +89,12 @@ class RegisterTypeBuilderClang : public RegisterTypeBuilder {
CompilerType BuildFlagsType(const RegisterTypeFlags &flags_info,
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system);
+
+ CompilerType BuildVectorType(const lldb_private::RegisterTypeVector &vector_info,
+ uint32_t register_byte_size,
+ lldb::TypeSystemClangSP type_system);
- CompilerType BuildUnionType(const RegisterTypeUnion &union_info,
+ CompilerType BuildUnionType(const lldb_private::RegisterTypeUnion &union_info,
uint32_t register_byte_size,
lldb::TypeSystemClangSP type_system);
diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt
index eebeba601abf6..4bd23f803cf43 100644
--- a/lldb/source/Target/CMakeLists.txt
+++ b/lldb/source/Target/CMakeLists.txt
@@ -40,6 +40,7 @@ add_lldb_library(lldbTarget
RegisterContextUnwind.cpp
RegisterTypeFlags.cpp
RegisterTypeUnion.cpp
+ RegisterTypeVector.cpp
RegisterType.cpp
RegisterNumber.cpp
RemoteAwarePlatform.cpp
diff --git a/lldb/source/Target/RegisterTypeVector.cpp b/lldb/source/Target/RegisterTypeVector.cpp
new file mode 100644
index 0000000000000..bba0fe9d8eea8
--- /dev/null
+++ b/lldb/source/Target/RegisterTypeVector.cpp
@@ -0,0 +1,64 @@
+//===-- RegisterTypeVector.cpp --------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/RegisterTypeVector.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/StreamString.h"
+
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace lldb_private;
+
+// TODO: this code may already exist in the XML processor.
+static RegisterTypeVector::ElementTypeInfo
+LookupElementType(const std::string &type) {
+ // See
+ // https://sourceware.org/gdb/current/onlinedocs/gdb.html/Predefined-Target-Types.html#Predefined-Target-Types.
+ // Currently this is just the ones qemu sends for SVE vectors.
+ return llvm::StringSwitch<RegisterTypeVector::ElementTypeInfo>(type)
+ .Case("int8", {lldb::eEncodingSint, 1})
+ .Case("int16", {lldb::eEncodingSint, 2})
+ .Case("int32", {lldb::eEncodingSint, 4})
+ .Case("int64", {lldb::eEncodingSint, 8})
+ .Case("int128", {lldb::eEncodingSint, 16})
+ .Case("uint8", {lldb::eEncodingUint, 1})
+ .Case("uint16", {lldb::eEncodingUint, 2})
+ .Case("uint32", {lldb::eEncodingUint, 4})
+ .Case("uint64", {lldb::eEncodingUint, 8})
+ .Case("uint128", {lldb::eEncodingUint, 16})
+ .Case("ieee_half", {lldb::eEncodingIEEE754, 2})
+ .Case("ieee_single", {lldb::eEncodingIEEE754, 4})
+ .Case("ieee_double", {lldb::eEncodingIEEE754, 8})
+ .Default({});
+}
+
+RegisterTypeVector::RegisterTypeVector(std::string id, std::string type,
+ unsigned count)
+ : RegisterType(eRegisterTypeKindVector, id), m_type(type), m_count(count),
+ m_element_type_info(LookupElementType(type)) {}
+
+// TODO: test me!
+void RegisterTypeVector::ToXMLElement(Stream &strm,
+ const RegisterType *user) const {
+ (void)user;
+ // Example XML:
+ // <vector id="foo" type="some type" count="4"/>
+ strm.Indent();
+ strm << "<vector id=\"" << GetID() << "\" type=\"" << GetType()
+ << "\" count=\"";
+ strm.Printf("%d\"/>\n", GetCount());
+}
+
+void RegisterTypeVector::DumpToLog(Log *log) const {
+ LLDB_LOG(log, "vector ID: \"{0}\", type: \"{1}\", count: {2}",
+ GetID().c_str(), GetType().c_str(), GetCount());
+}
+
+unsigned RegisterTypeVector::GetSize() const {
+ return GetCount() * m_element_type_info.size;
+}
\ No newline at end of file
>From 5ac6ee5b12a21d7750b3960cfc822602bb3b78c3 Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Thu, 12 Mar 2026 17:17:12 +0000
Subject: [PATCH 15/16] example vector and removing register size limit
TODO: backport the size limit removal to the flags only patches
---
lldb/source/Core/DumpRegisterValue.cpp | 35 +++++++++----------
.../Utility/RegisterTypeDetector_arm64.cpp | 19 ++++++++++
.../Utility/RegisterTypeDetector_arm64.h | 5 ++-
3 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/lldb/source/Core/DumpRegisterValue.cpp b/lldb/source/Core/DumpRegisterValue.cpp
index d38dfe998e503..9804cc3bb0519 100644
--- a/lldb/source/Core/DumpRegisterValue.cpp
+++ b/lldb/source/Core/DumpRegisterValue.cpp
@@ -21,20 +21,23 @@
using namespace lldb;
-template <typename T>
-static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
+static void dump_type_value(lldb_private::CompilerType &fields_type,
+ lldb_private::RegisterValue reg_val,
+ const lldb_private::RegisterInfo ®_info,
lldb_private::ExecutionContextScope *exe_scope,
lldb_private::Stream &strm) {
+ auto heap_buf_sp =
+ std::make_shared<lldb_private::DataBufferHeap>(reg_val.GetByteSize(), 0);
lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder();
+ lldb_private::Status err;
+ uint32_t wrote =
+ reg_val.GetAsMemoryData(reg_info, heap_buf_sp->GetBytes(),
+ reg_val.GetByteSize(), target_order, err);
+ if (wrote != reg_val.GetByteSize() || err.Fail())
+ return;
- // The type will be rendered in the target's type system, so it must match
- // its endian.
- if (lldb_private::endian::InlHostByteOrder() != target_order)
- value = llvm::byteswap(value);
-
- lldb_private::DataExtractor data_extractor{&value, sizeof(T), target_order,
- 8};
-
+ lldb_private::DataExtractor data_extractor(heap_buf_sp);
+ data_extractor.SetByteOrder(target_order);
lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create(
exe_scope, fields_type, lldb_private::ConstString(), data_extractor);
lldb_private::DumpValueObjectOptions dump_options;
@@ -107,8 +110,7 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
0, // item_bit_offset
exe_scope);
- if (!print_flags || !reg_info.register_type || !exe_scope || !target_sp ||
- (reg_info.byte_size != 4 && reg_info.byte_size != 8))
+ if (!print_flags || !reg_info.register_type || !exe_scope || !target_sp)
return;
CompilerType register_type =
@@ -119,13 +121,8 @@ void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s,
// Use a new stream so we can remove a trailing newline later.
StreamString register_type_stream;
- if (reg_info.byte_size == 4) {
- dump_type_value(register_type, reg_val.GetAsUInt32(), exe_scope,
- register_type_stream);
- } else {
- dump_type_value(register_type, reg_val.GetAsUInt64(), exe_scope,
- register_type_stream);
- }
+ dump_type_value(register_type, reg_val, reg_info, exe_scope,
+ register_type_stream);
// Registers are indented like:
// (lldb) register read foo
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index ebdac68ec752e..87cd8c1d8b9ca 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -245,6 +245,25 @@ const RegisterType *Arm64RegisterTypeDetector::DetectFPSRType(uint64_t hwcap,
return &fpsr_flags;
}
+const RegisterType *Arm64RegisterTypeDetector::DetectV0Type(uint64_t hwcap,
+ uint64_t hwcap2,
+ uint64_t hwcap3) {
+ (void)hwcap;
+ (void)hwcap2;
+ (void)hwcap3;
+
+ static RegisterTypeVector v0_vec8("v0_vec8", "uint8", 16);
+ static RegisterTypeVector v0_vec16("v0_vec16", "uint16", 8);
+ static RegisterTypeVector v0_vec32("v0_vec32", "uint32", 4);
+ static RegisterTypeVector v0_vec64("v0_vec64", "uint64", 2);
+ static RegisterTypeUnion v0_vec_union("v0_vec_union", {{"8", &v0_vec8},
+ {"16", &v0_vec16},
+ {"32", &v0_vec32},
+ {"64", &v0_vec64}});
+
+ return &v0_vec_union;
+}
+
const RegisterType *Arm64RegisterTypeDetector::DetectX0Type(uint64_t hwcap,
uint64_t hwcap2,
uint64_t hwcap3) {
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
index f411009c75723..e1f70c8cc4c2d 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.h
@@ -69,6 +69,8 @@ class Arm64RegisterTypeDetector {
uint64_t hwcap3);
static const RegisterType *DetectX0Type(uint64_t hwcap, uint64_t hwcap2,
uint64_t hwcap3);
+ static const RegisterType *DetectV0Type(uint64_t hwcap, uint64_t hwcap2,
+ uint64_t hwcap3);
static const RegisterType *
DetectGCSFeaturesType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3);
static const RegisterType *DetectPOREL0Type(uint64_t hwcap, uint64_t hwcap2,
@@ -81,7 +83,7 @@ class Arm64RegisterTypeDetector {
llvm::StringRef m_name;
const RegisterType *m_type;
DetectorFn m_detector;
- } m_registers[10] = {
+ } m_registers[11] = {
RegisterEntry("cpsr", 4, DetectCPSRType),
RegisterEntry("fpsr", 4, DetectFPSRType),
RegisterEntry("fpcr", 4, DetectFPCRType),
@@ -92,6 +94,7 @@ class Arm64RegisterTypeDetector {
RegisterEntry("gcs_features_locked", 8, DetectGCSFeaturesType),
RegisterEntry("por_el0", 8, DetectPOREL0Type),
RegisterEntry("x0", 8, DetectX0Type),
+ RegisterEntry("v0", 16, DetectV0Type),
};
// Becomes true once field detection has been run for all registers.
>From f556f1ceb09c54f160c0daccb8f63aba966a6cac Mon Sep 17 00:00:00 2001
From: David Spickett <david.spickett at arm.com>
Date: Wed, 25 Mar 2026 13:27:57 +0000
Subject: [PATCH 16/16] more testing
---
.../Process/Utility/RegisterTypeDetector_arm64.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
index 87cd8c1d8b9ca..b99493570491d 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterTypeDetector_arm64.cpp
@@ -256,10 +256,12 @@ const RegisterType *Arm64RegisterTypeDetector::DetectV0Type(uint64_t hwcap,
static RegisterTypeVector v0_vec16("v0_vec16", "uint16", 8);
static RegisterTypeVector v0_vec32("v0_vec32", "uint32", 4);
static RegisterTypeVector v0_vec64("v0_vec64", "uint64", 2);
+ static RegisterTypeVector v0_vec128("v0_vec128", "uint128", 1);
static RegisterTypeUnion v0_vec_union("v0_vec_union", {{"8", &v0_vec8},
{"16", &v0_vec16},
{"32", &v0_vec32},
- {"64", &v0_vec64}});
+ {"64", &v0_vec64},
+ {"128", &v0_vec128}});
return &v0_vec_union;
}
@@ -271,21 +273,22 @@ const RegisterType *Arm64RegisterTypeDetector::DetectX0Type(uint64_t hwcap,
(void)hwcap2;
(void)hwcap3;
- static RegisterTypeFlags x0_flags_lhs("x0_flags_lhs", 8, {
+ static RegisterTypeFlags x0_flags_big_little("x0_flags_big_little", 8, {
{"w", 16, 63}, {"x", 0, 15}});
- static RegisterTypeFlags x0_flags_rhs("x0_flags_rhs", 8, {
+ static RegisterTypeFlags x0_flags_little_big("x0_flags_little_big", 8, {
{"y", 48, 63}, {"z", 0, 47}});
static RegisterTypeVector x0_vec8( "x0_vec8", "uint8", 8);
static RegisterTypeVector x0_vec16("x0_vec16", "uint16", 4);
static RegisterTypeVector x0_vec32("x0_vec32", "uint32", 2);
+ static RegisterTypeVector x0_vec64("x0_vec64", "uint64", 1);
static RegisterTypeUnion x0_vec_union(
"x0_vec_union",
- {{"8", &x0_vec8}, {"16", &x0_vec16}, {"32", &x0_vec32}});
+ {{"8", &x0_vec8}, {"16", &x0_vec16}, {"32", &x0_vec32}, {"64", &x0_vec64}});
static RegisterTypeUnion x0_union(
"x0_union",
- {{"lhs", &x0_flags_lhs}, {"rhs", &x0_flags_rhs},
+ {{"big_little", &x0_flags_big_little}, {"little_big", &x0_flags_little_big},
{"vector", &x0_vec_union}});
return &x0_union;
More information about the lldb-commits
mailing list