summaryrefslogtreecommitdiff
path: root/lldb/unittests
diff options
context:
space:
mode:
authorDavid Spickett <david.spickett@linaro.org>2022-08-05 14:40:31 +0000
committerDavid Spickett <david.spickett@linaro.org>2023-04-13 10:54:52 +0000
commit6ea45e3007b8a489afa56af13a2b8bfcec201a93 (patch)
tree38638d18fd63abe44422cc99c0cde42ba3149072 /lldb/unittests
parent0bfbecf52e8fa04785cf0b5c38b25c13442fb53d (diff)
downloadllvm-6ea45e3007b8a489afa56af13a2b8bfcec201a93.tar.gz
[lldb] Add RegisterFlags class
This models the "flags" node from GDB's target XML: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html This node is used to describe the fields of registers like cpsr on AArch64. RegisterFlags is a class that contains a list of register fields. These fields will be extracted from the XML sent by the remote. We assume that there is at least one field, that the fields are sorted in descending order and do not overlap. That will be enforced by the XML processor (the GDB client code in our case). The fields may not cover the whole register. To account for this RegisterFields will add anonymous padding fields so that sizeof(all fields) == sizeof(register). This will save a lot of hasssle later. Reviewed By: jasonmolenda, JDevlieghere Differential Revision: https://reviews.llvm.org/D145566
Diffstat (limited to 'lldb/unittests')
-rw-r--r--lldb/unittests/Target/CMakeLists.txt1
-rw-r--r--lldb/unittests/Target/RegisterFlagsTest.cpp123
2 files changed, 124 insertions, 0 deletions
diff --git a/lldb/unittests/Target/CMakeLists.txt b/lldb/unittests/Target/CMakeLists.txt
index 772d5847b11c..99431435d293 100644
--- a/lldb/unittests/Target/CMakeLists.txt
+++ b/lldb/unittests/Target/CMakeLists.txt
@@ -7,6 +7,7 @@ add_lldb_unittest(TargetTests
MemoryTagMapTest.cpp
ModuleCacheTest.cpp
PathMappingListTest.cpp
+ RegisterFlagsTest.cpp
RemoteAwarePlatformTest.cpp
StackFrameRecognizerTest.cpp
FindFileTest.cpp
diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterFlagsTest.cpp
new file mode 100644
index 000000000000..04edb0caf117
--- /dev/null
+++ b/lldb/unittests/Target/RegisterFlagsTest.cpp
@@ -0,0 +1,123 @@
+//===-- RegisterFlagsTest.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/RegisterFlags.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+TEST(RegisterFlagsTest, Field) {
+ // We assume that start <= end is always true, so that is not tested here.
+
+ RegisterFlags::Field f1("abc", 0, 0);
+ ASSERT_EQ(f1.GetName(), "abc");
+ // 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);
+ ASSERT_FALSE(f3 < f1);
+ ASSERT_FALSE(f1 < f2);
+ ASSERT_FALSE(f1 < f1);
+}
+
+static RegisterFlags::Field make_field(unsigned start, unsigned end) {
+ return RegisterFlags::Field("", start, end);
+}
+
+TEST(RegisterFlagsTest, FieldOverlaps) {
+ // Single bit fields
+ ASSERT_FALSE(make_field(0, 0).Overlaps(make_field(1, 1)));
+ ASSERT_TRUE(make_field(1, 1).Overlaps(make_field(1, 1)));
+ ASSERT_FALSE(make_field(1, 1).Overlaps(make_field(3, 3)));
+
+ ASSERT_TRUE(make_field(0, 1).Overlaps(make_field(1, 2)));
+ ASSERT_TRUE(make_field(1, 2).Overlaps(make_field(0, 1)));
+ ASSERT_FALSE(make_field(0, 1).Overlaps(make_field(2, 3)));
+ ASSERT_FALSE(make_field(2, 3).Overlaps(make_field(0, 1)));
+
+ ASSERT_FALSE(make_field(1, 5).Overlaps(make_field(10, 20)));
+ ASSERT_FALSE(make_field(15, 30).Overlaps(make_field(7, 12)));
+}
+
+TEST(RegisterFlagsTest, 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.
+
+ // [field 1][field 2]
+ ASSERT_EQ(make_field(1, 1).PaddingDistance(make_field(0, 0)), 0ULL);
+ // [field 1][..][field 2]
+ ASSERT_EQ(make_field(2, 2).PaddingDistance(make_field(0, 0)), 1ULL);
+ // [field 1][field 1][field 2]
+ ASSERT_EQ(make_field(1, 2).PaddingDistance(make_field(0, 0)), 0ULL);
+ // [field 1][30 bits free][field 2]
+ ASSERT_EQ(make_field(31, 31).PaddingDistance(make_field(0, 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, 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, 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, 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)});
+}