DavidSpickett updated this revision to Diff 356900.
DavidSpickett added a comment.
- Make granules default to 0 for UnpackTagsData
- Add more comments to tests
(I'll add a method to repeat packed tags in the later patch
that'll use it)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105179/new/
https://reviews.llvm.org/D105179
Files:
lldb/include/lldb/Target/MemoryTagManager.h
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp
Index: lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp
===================================================================
--- lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp
+++ lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp
@@ -21,7 +21,7 @@
manager.UnpackTagsData(input, 2),
llvm::FailedWithMessage(
"Packed tag data size does not match expected number of tags. "
- "Expected 2 tag(s) for 2 granules, got 0 tag(s)."));
+ "Expected 2 tag(s) for 2 granule(s), got 0 tag(s)."));
// This is out of the valid tag range
input.push_back(0x1f);
@@ -41,6 +41,43 @@
manager.UnpackTagsData(input, 2);
ASSERT_THAT_EXPECTED(got, llvm::Succeeded());
ASSERT_THAT(expected, testing::ContainerEq(*got));
+
+ // Error for too much tag data
+ ASSERT_THAT_EXPECTED(
+ manager.UnpackTagsData(input, 1),
+ llvm::FailedWithMessage(
+ "Packed tag data size does not match expected number of tags. "
+ "Expected 1 tag(s) for 1 granule(s), got 2 tag(s)."));
+
+ // By default, we don't check number of tags
+ llvm::Expected<std::vector<lldb::addr_t>> got_zero =
+ manager.UnpackTagsData(input);
+ ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded());
+ ASSERT_THAT(expected, testing::ContainerEq(*got));
+
+ // Which is the same as granules=0
+ got_zero = manager.UnpackTagsData(input, 0);
+ ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded());
+ ASSERT_THAT(expected, testing::ContainerEq(*got));
+}
+
+TEST(MemoryTagManagerAArch64MTETest, PackTags) {
+ MemoryTagManagerAArch64MTE manager;
+
+ // Error for tag out of range
+ llvm::Expected<std::vector<uint8_t>> invalid_tag_err =
+ manager.PackTags({0x10});
+ ASSERT_THAT_EXPECTED(
+ invalid_tag_err,
+ llvm::FailedWithMessage(
+ "Found tag 0x10 which is > max MTE tag value of 0xf."));
+
+ // 0xf here is the max tag value that we can pack
+ std::vector<lldb::addr_t> tags{0, 1, 0xf};
+ std::vector<uint8_t> expected{0, 1, 0xf};
+ llvm::Expected<std::vector<uint8_t>> packed = manager.PackTags(tags);
+ ASSERT_THAT_EXPECTED(packed, llvm::Succeeded());
+ ASSERT_THAT(expected, testing::ContainerEq(*packed));
}
TEST(MemoryTagManagerAArch64MTETest, GetLogicalTag) {
@@ -118,3 +155,53 @@
ASSERT_EQ(-32, manager.AddressDiff(0x5511222233334400, 0x4411222233334420));
ASSERT_EQ(65, manager.AddressDiff(0x9911222233334441, 0x6611222233334400));
}
+
+// Helper to check that repeating "tags" over "range" gives you
+// "expected_tags".
+static void
+test_repeating_tags(const std::vector<lldb::addr_t> &tags,
+ MemoryTagManagerAArch64MTE::TagRange range,
+ const std::vector<lldb::addr_t> &expected_tags) {
+ MemoryTagManagerAArch64MTE manager;
+ llvm::Expected<std::vector<lldb::addr_t>> tags_or_err =
+ manager.RepeatTagsForRange(tags, range);
+ ASSERT_THAT_EXPECTED(tags_or_err, llvm::Succeeded());
+ ASSERT_THAT(expected_tags, testing::ContainerEq(*tags_or_err));
+}
+
+TEST(MemoryTagManagerAArch64MTETest, RepeatTagsForRange) {
+ MemoryTagManagerAArch64MTE manager;
+
+ // Must have some tags if your range is not empty
+ llvm::Expected<std::vector<lldb::addr_t>> no_tags_err =
+ manager.RepeatTagsForRange({},
+ MemoryTagManagerAArch64MTE::TagRange{0, 16});
+ ASSERT_THAT_EXPECTED(
+ no_tags_err, llvm::FailedWithMessage(
+ "Expected some tags to cover given range, got zero."));
+
+ // If the range is empty, you get no tags back
+ test_repeating_tags({1, 2, 3}, MemoryTagManagerAArch64MTE::TagRange{0, 0},
+ {});
+ // And you don't need tags for an empty range
+ test_repeating_tags({}, MemoryTagManagerAArch64MTE::TagRange{0, 0}, {});
+
+ // A single tag will just be multiplied as many times as needed
+ test_repeating_tags({5}, MemoryTagManagerAArch64MTE::TagRange{0, 16}, {5});
+ test_repeating_tags({6}, MemoryTagManagerAArch64MTE::TagRange{0, 32}, {6, 6});
+
+ // If you've got as many tags as granules, it's a roundtrip
+ test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 32},
+ {7, 8});
+
+ // If you've got fewer tags than granules, they repeat. Exactly or partially
+ // as needed.
+ test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 64},
+ {7, 8, 7, 8});
+ test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 48},
+ {7, 8, 7});
+
+ // If you've got more tags than granules you get back only those needed
+ test_repeating_tags({1, 2, 3, 4}, MemoryTagManagerAArch64MTE::TagRange{0, 32},
+ {1, 2});
+}
Index: lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
===================================================================
--- lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
+++ lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h
@@ -34,7 +34,14 @@
llvm::Expected<std::vector<lldb::addr_t>>
UnpackTagsData(const std::vector<uint8_t> &tags,
- size_t granules) const override;
+ size_t granules = 0) const override;
+
+ llvm::Expected<std::vector<uint8_t>>
+ PackTags(const std::vector<lldb::addr_t> &tags) const override;
+
+ llvm::Expected<std::vector<lldb::addr_t>>
+ RepeatTagsForRange(const std::vector<lldb::addr_t> &tags,
+ TagRange range) const override;
};
} // namespace lldb_private
Index: lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
+++ lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp
@@ -68,14 +68,17 @@
llvm::Expected<std::vector<lldb::addr_t>>
MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags,
- size_t granules) const {
- size_t num_tags = tags.size() / GetTagSizeInBytes();
- if (num_tags != granules) {
- return llvm::createStringError(
- llvm::inconvertibleErrorCode(),
- "Packed tag data size does not match expected number of tags. "
- "Expected %zu tag(s) for %zu granules, got %zu tag(s).",
- granules, granules, num_tags);
+ size_t granules /*=0*/) const {
+ // 0 means don't check the number of tags before unpacking
+ if (granules) {
+ size_t num_tags = tags.size() / GetTagSizeInBytes();
+ if (num_tags != granules) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Packed tag data size does not match expected number of tags. "
+ "Expected %zu tag(s) for %zu granule(s), got %zu tag(s).",
+ granules, granules, num_tags);
+ }
}
// (if bytes per tag was not 1, we would reconstruct them here)
@@ -95,3 +98,46 @@
return unpacked;
}
+
+llvm::Expected<std::vector<uint8_t>> MemoryTagManagerAArch64MTE::PackTags(
+ const std::vector<lldb::addr_t> &tags) const {
+ std::vector<uint8_t> packed;
+ packed.reserve(tags.size() * GetTagSizeInBytes());
+
+ for (auto tag : tags) {
+ if (tag > MTE_TAG_MAX) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Found tag 0x%x which is > max MTE tag value of 0x%x.", tag,
+ MTE_TAG_MAX);
+ }
+ packed.push_back(static_cast<uint8_t>(tag));
+ }
+
+ return packed;
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+MemoryTagManagerAArch64MTE::RepeatTagsForRange(
+ const std::vector<lldb::addr_t> &tags, TagRange range) const {
+ std::vector<lldb::addr_t> new_tags;
+
+ // If the range is not empty
+ if (range.IsValid()) {
+ if (tags.empty()) {
+ return llvm::createStringError(
+ llvm::inconvertibleErrorCode(),
+ "Expected some tags to cover given range, got zero.");
+ }
+
+ // We assume that this range has already been expanded/aligned to granules
+ size_t granules = range.GetByteSize() / GetGranuleSize();
+ new_tags.reserve(granules);
+ for (size_t to_copy = 0; granules > 0; granules -= to_copy) {
+ to_copy = granules > tags.size() ? tags.size() : granules;
+ new_tags.insert(new_tags.end(), tags.begin(), tags.begin() + to_copy);
+ }
+ }
+
+ return new_tags;
+}
Index: lldb/include/lldb/Target/MemoryTagManager.h
===================================================================
--- lldb/include/lldb/Target/MemoryTagManager.h
+++ lldb/include/lldb/Target/MemoryTagManager.h
@@ -72,11 +72,45 @@
virtual size_t GetTagSizeInBytes() const = 0;
// Unpack tags from their stored format (e.g. gdb qMemTags data) into seperate
- // tags. Checks that each tag is within the expected value range and that the
- // number of tags found matches the number of granules we originally asked
- // for.
+ // tags.
+ //
+ // Checks that each tag is within the expected value range and if granules is
+ // set to non-zero, that the number of tags found matches the number of
+ // granules we expected to cover.
+ virtual llvm::Expected<std::vector<lldb::addr_t>>
+ UnpackTagsData(const std::vector<uint8_t> &tags,
+ size_t granules = 0) const = 0;
+
+ // Pack uncompressed tags into their storage format (e.g. for gdb QMemTags).
+ // Checks that each tag is within the expected value range.
+ // We do not check the number of tags or range they apply to because
+ // it is up to the remote to repeat them as needed.
+ virtual llvm::Expected<std::vector<uint8_t>>
+ PackTags(const std::vector<lldb::addr_t> &tags) const = 0;
+
+ // Take a set of tags and repeat them as much as needed to cover the given
+ // range. We assume that this range has been previously expanded/aligned to
+ // granules. (this method is used by lldb-server to implement QMemTags
+ // packet handling)
+ //
+ // If the range is empty, zero tags are returned.
+ // If the range is not empty and...
+ // * there are no tags, an error is returned.
+ // * there are fewer tags than granules, the tags are repeated to fill the
+ // range.
+ // * there are more tags than granules, only the tags required to cover
+ // the range are returned.
+ //
+ // When repeating tags it will not always return a multiple of the original
+ // list. For example if your range is 3 granules and your tags are 1 and 2.
+ // You will get tags 1, 2 and 1 returned. Rather than getting 1, 2, 1, 2,
+ // which would be one too many tags for the range.
+ //
+ // A single tag will just be repeated as you'd expected. Tag 1 over 3 granules
+ // would return 1, 1, 1.
virtual llvm::Expected<std::vector<lldb::addr_t>>
- UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules) const = 0;
+ RepeatTagsForRange(const std::vector<lldb::addr_t> &tags,
+ TagRange range) const = 0;
virtual ~MemoryTagManager() {}
};
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits