DavidSpickett created this revision. Herald added subscribers: danielkiss, kristof.beyls. DavidSpickett requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
PackTags is used by to compress tags to go in the QMemTags packet and be passed to ptrace when writing memory tags. The behaviour of RepeatTagsForRange matches that described for QMemTags in the GDB documentation: https://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html#General-Query-Packets In addition, unpacking tags with number of tags 0 now means do not check that number of tags matches the range. This will be used by lldb-server to unpack tags before repeating them to fill the requested range. Repository: rG LLVM Github Monorepo 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,37 @@ 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).")); + + // If granules is zero then we don't check number of tags + llvm::Expected<std::vector<lldb::addr_t>> got_zero = + manager.UnpackTagsData(input, 0); + ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded()); + ASSERT_THAT(expected, testing::ContainerEq(*got)); +} + +TEST(MemoryTagManagerAArch64MTETest, PackTags) { + MemoryTagManagerAArch64MTE manager; + + 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 + 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 +149,51 @@ ASSERT_EQ(-32, manager.AddressDiff(0x5511222233334400, 0x4411222233334420)); ASSERT_EQ(65, manager.AddressDiff(0x9911222233334441, 0x6611222233334400)); } + +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 @@ -35,6 +35,13 @@ llvm::Expected<std::vector<lldb::addr_t>> UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules) 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 @@ -69,13 +69,16 @@ 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); + // 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 @@ -75,9 +75,42 @@ // 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. + // + // Set granules to 0 to skip checking the number of tags found. virtual llvm::Expected<std::vector<lldb::addr_t>> UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules) 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>> + RepeatTagsForRange(const std::vector<lldb::addr_t> &tags, + TagRange range) const = 0; + virtual ~MemoryTagManager() {} };
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits