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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PAT... David Spickett via Phabricator via lldb-commits
    • [Lldb-commits]... Muhammad Omair Javaid via Phabricator via lldb-commits
    • [Lldb-commits]... David Spickett via Phabricator via lldb-commits

Reply via email to