DavidSpickett updated this revision to Diff 358978.
DavidSpickett added a comment.
Rebase
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105182/new/
https://reviews.llvm.org/D105182
Files:
lldb/source/Commands/CommandObjectMemoryTag.cpp
lldb/test/API/functionalities/memory/tag/TestMemoryTag.py
lldb/test/API/linux/aarch64/mte_tag_access/Makefile
lldb/test/API/linux/aarch64/mte_tag_access/TestAArch64LinuxMTEMemoryTagAccess.py
lldb/test/API/linux/aarch64/mte_tag_access/main.c
lldb/test/API/linux/aarch64/mte_tag_read/Makefile
lldb/test/API/linux/aarch64/mte_tag_read/TestAArch64LinuxMTEMemoryTagRead.py
lldb/test/API/linux/aarch64/mte_tag_read/main.c
Index: lldb/test/API/linux/aarch64/mte_tag_read/TestAArch64LinuxMTEMemoryTagRead.py
===================================================================
--- lldb/test/API/linux/aarch64/mte_tag_read/TestAArch64LinuxMTEMemoryTagRead.py
+++ /dev/null
@@ -1,126 +0,0 @@
-"""
-Test "memory tag read" command on AArch64 Linux with MTE.
-"""
-
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class AArch64LinuxMTEMemoryTagReadTestCase(TestBase):
-
- mydir = TestBase.compute_mydir(__file__)
-
- NO_DEBUG_INFO_TESTCASE = True
-
- @skipUnlessArch("aarch64")
- @skipUnlessPlatform(["linux"])
- @skipUnlessAArch64MTELinuxCompiler
- def test_mte_tag_read(self):
- if not self.isAArch64MTE():
- self.skipTest('Target must support MTE.')
-
- self.build()
- self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
-
- lldbutil.run_break_set_by_file_and_line(self, "main.c",
- line_number('main.c', '// Breakpoint here'),
- num_expected_locations=1)
-
- self.runCmd("run", RUN_SUCCEEDED)
-
- if self.process().GetState() == lldb.eStateExited:
- self.fail("Test program failed to run.")
-
- self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
- substrs=['stopped',
- 'stop reason = breakpoint'])
-
- # Argument validation
- self.expect("memory tag read",
- substrs=["error: wrong number of arguments; expected at least <address-expression>, "
- "at most <address-expression> <end-address-expression>"],
- error=True)
- self.expect("memory tag read buf buf+16 32",
- substrs=["error: wrong number of arguments; expected at least <address-expression>, "
- "at most <address-expression> <end-address-expression>"],
- error=True)
- self.expect("memory tag read not_a_symbol",
- substrs=["error: Invalid address expression, address expression \"not_a_symbol\" "
- "evaluation failed"],
- error=True)
- self.expect("memory tag read buf not_a_symbol",
- substrs=["error: Invalid end address expression, address expression \"not_a_symbol\" "
- "evaluation failed"],
- error=True)
- # Inverted range
- self.expect("memory tag read buf buf-16",
- patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
- "greater than the start address \(0x[A-Fa-f0-9]+\)"],
- error=True)
- # Range of length 0
- self.expect("memory tag read buf buf",
- patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
- "greater than the start address \(0x[A-Fa-f0-9]+\)"],
- error=True)
-
-
- # Can't read from a region without tagging
- self.expect("memory tag read non_mte_buf",
- patterns=["error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 is not "
- "in a memory tagged region"],
- error=True)
-
- # If there's no end address we assume 1 granule
- self.expect("memory tag read buf",
- patterns=["Logical tag: 0x9\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
-
- # Range of <1 granule is rounded up to 1 granule
- self.expect("memory tag read buf buf+8",
- patterns=["Logical tag: 0x9\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
-
- # Start address is aligned down, end aligned up
- self.expect("memory tag read buf+8 buf+24",
- patterns=["Logical tag: 0x9\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0\n"
- "\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x1$"])
-
- # You may read up to the end of the tagged region
- # Layout is buf (MTE), buf2 (MTE), <unmapped/non MTE>
- # so we read from the end of buf2 here.
- self.expect("memory tag read buf2+page_size-16 buf2+page_size",
- patterns=["Logical tag: 0x0\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+, 0x[0-9A-Fa-f]+\): 0x0$"])
-
- # Ranges with any part outside the region will error
- self.expect("memory tag read buf2+page_size-16 buf2+page_size+32",
- patterns=["error: Address range 0x[0-9A-fa-f]+f0:0x[0-9A-Fa-f]+20 "
- "is not in a memory tagged region"],
- error=True)
- self.expect("memory tag read buf2+page_size",
- patterns=["error: Address range 0x[0-9A-fa-f]+00:0x[0-9A-Fa-f]+10 "
- "is not in a memory tagged region"],
- error=True)
-
- # You can read a range that spans more than one mapping
- # This spills into buf2 which is also MTE
- self.expect("memory tag read buf+page_size-16 buf+page_size+16",
- patterns=["Logical tag: 0x9\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+f0, 0x[0-9A-Fa-f]+00\): 0xf\n"
- "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
-
- # Tags in start/end are ignored when creating the range.
- # So this is not an error despite start/end having different tags
- self.expect("memory tag read buf buf_alt_tag+16 ",
- patterns=["Logical tag: 0x9\n"
- "Allocation tags:\n"
- "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
Index: lldb/test/API/linux/aarch64/mte_tag_access/main.c
===================================================================
--- lldb/test/API/linux/aarch64/mte_tag_access/main.c
+++ lldb/test/API/linux/aarch64/mte_tag_access/main.c
@@ -1,11 +1,19 @@
#include <arm_acle.h>
#include <asm/hwcap.h>
#include <asm/mman.h>
+#include <stdlib.h>
#include <sys/auxv.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
+char *checked_mmap(size_t page_size, int prot) {
+ char *ptr = mmap(0, page_size, prot, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (ptr == MAP_FAILED)
+ exit(1);
+ return ptr;
+}
+
int main(int argc, char const *argv[]) {
// We assume that the test runner has checked we're on an MTE system
@@ -20,38 +28,32 @@
size_t page_size = sysconf(_SC_PAGESIZE);
- // Allocate memory with MTE
- // We ask for two pages. One is read only so that we get
- // 2 mappings in /proc/.../smaps so we can check reading
- // a range across mappings.
- // The first allocation will start at the highest address,
- // so we allocate buf2 first to get:
- // <low address> | buf | buf2 | <high address>
- int prot = PROT_READ | PROT_MTE;
- int flags = MAP_PRIVATE | MAP_ANONYMOUS;
-
- char *buf2 = mmap(0, page_size, prot, flags, -1, 0);
- if (buf2 == MAP_FAILED)
- return 1;
-
- // Writeable so we can set tags on it later
- char *buf = mmap(0, page_size, prot | PROT_WRITE, flags, -1, 0);
- if (buf == MAP_FAILED)
- return 1;
+ // We're going to mmap pages in this order:
+ // <high addres>
+ // MTE read/write
+ // MTE read/write executable
+ // non MTE
+ // MTE read only
+ // <low address>
+ //
+ // This means that the first two MTE pages end up next
+ // to each other. Since the second one is also executable
+ // it will create a new entry in /proc/smaps.
+ int mte_prot = PROT_READ | PROT_MTE;
+ char *mte_buf_2 = checked_mmap(page_size, mte_prot | PROT_WRITE);
+ char *mte_buf = checked_mmap(page_size, mte_prot | PROT_WRITE | PROT_EXEC);
// We expect the mappings to be next to each other
- if (buf2 - buf != page_size)
+ if (mte_buf_2 - mte_buf != page_size)
return 1;
- // And without MTE
- char *non_mte_buf = mmap(0, page_size, PROT_READ | PROT_WRITE, flags, -1, 0);
- if (non_mte_buf == MAP_FAILED)
- return 1;
+ char *non_mte_buf = checked_mmap(page_size, PROT_READ);
+ char *mte_read_only = checked_mmap(page_size, mte_prot);
// Set incrementing tags until end of the first page
- char *tagged_ptr = buf;
+ char *tagged_ptr = mte_buf;
// This ignores tag bits when subtracting the addresses
- while (__arm_mte_ptrdiff(tagged_ptr, buf) < page_size) {
+ while (__arm_mte_ptrdiff(tagged_ptr, mte_buf) < page_size) {
// Set the allocation tag for this location
__arm_mte_set_tag(tagged_ptr);
// + 16 for 16 byte granules
@@ -61,16 +63,17 @@
}
// Tag the original pointer with 9
- buf = __arm_mte_create_random_tag(buf, ~(1 << 9));
+ mte_buf = __arm_mte_create_random_tag(mte_buf, ~(1 << 9));
// A different tag so that buf_alt_tag > buf if you don't handle the tag
- char *buf_alt_tag = __arm_mte_create_random_tag(buf, ~(1 << 10));
+ char *mte_buf_alt_tag = __arm_mte_create_random_tag(mte_buf, ~(1 << 10));
// lldb should be removing the whole top byte, not just the tags.
// So fill 63-60 with something non zero so we'll fail if we only remove tags.
#define SET_TOP_NIBBLE(ptr) (char *)((size_t)(ptr) | (0xA << 60))
- buf = SET_TOP_NIBBLE(buf);
- buf_alt_tag = SET_TOP_NIBBLE(buf_alt_tag);
- buf2 = SET_TOP_NIBBLE(buf2);
+ mte_buf = SET_TOP_NIBBLE(mte_buf);
+ mte_buf_alt_tag = SET_TOP_NIBBLE(mte_buf_alt_tag);
+ mte_buf_2 = SET_TOP_NIBBLE(mte_buf_2);
+ mte_read_only = SET_TOP_NIBBLE(mte_read_only);
// Breakpoint here
return 0;
Index: lldb/test/API/linux/aarch64/mte_tag_access/TestAArch64LinuxMTEMemoryTagAccess.py
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/mte_tag_access/TestAArch64LinuxMTEMemoryTagAccess.py
@@ -0,0 +1,218 @@
+"""
+Test "memory tag read" and "memory tag write" commands
+on AArch64 Linux with MTE.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class AArch64LinuxMTEMemoryTagAccessTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def setup_mte_test(self):
+ if not self.isAArch64MTE():
+ self.skipTest('Target must support MTE.')
+
+ self.build()
+ self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+ lldbutil.run_break_set_by_file_and_line(self, "main.c",
+ line_number('main.c', '// Breakpoint here'),
+ num_expected_locations=1)
+
+ self.runCmd("run", RUN_SUCCEEDED)
+
+ if self.process().GetState() == lldb.eStateExited:
+ self.fail("Test program failed to run.")
+
+ self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+ substrs=['stopped',
+ 'stop reason = breakpoint'])
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ @skipUnlessAArch64MTELinuxCompiler
+ def test_mte_tag_read(self):
+ self.setup_mte_test()
+
+ # Argument validation
+ self.expect("memory tag read",
+ substrs=["error: wrong number of arguments; expected at least <address-expression>, "
+ "at most <address-expression> <end-address-expression>"],
+ error=True)
+ self.expect("memory tag read mte_buf buf+16 32",
+ substrs=["error: wrong number of arguments; expected at least <address-expression>, "
+ "at most <address-expression> <end-address-expression>"],
+ error=True)
+ self.expect("memory tag read not_a_symbol",
+ substrs=["error: Invalid address expression, address expression \"not_a_symbol\" "
+ "evaluation failed"],
+ error=True)
+ self.expect("memory tag read mte_buf not_a_symbol",
+ substrs=["error: Invalid end address expression, address expression \"not_a_symbol\" "
+ "evaluation failed"],
+ error=True)
+ # Inverted range
+ self.expect("memory tag read mte_buf mte_buf-16",
+ patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
+ "greater than the start address \(0x[A-Fa-f0-9]+\)"],
+ error=True)
+ # Range of length 0
+ self.expect("memory tag read mte_buf mte_buf",
+ patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
+ "greater than the start address \(0x[A-Fa-f0-9]+\)"],
+ error=True)
+
+
+ # Can't read from a region without tagging
+ self.expect("memory tag read non_mte_buf",
+ patterns=["error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 is not "
+ "in a memory tagged region"],
+ error=True)
+
+ # If there's no end address we assume 1 granule
+ self.expect("memory tag read mte_buf",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
+
+ # Range of <1 granule is rounded up to 1 granule
+ self.expect("memory tag read mte_buf mte_buf+8",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
+
+ # Start address is aligned down, end aligned up
+ self.expect("memory tag read mte_buf+8 mte_buf+24",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0\n"
+ "\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x1$"])
+
+ # You may read up to the end of the tagged region
+ # Layout is mte_buf, mte_buf_2, non_mte_buf.
+ # So we read from the end of mte_buf_2 here.
+ self.expect("memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size",
+ patterns=["Logical tag: 0x0\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+, 0x[0-9A-Fa-f]+\): 0x0$"])
+
+ # Ranges with any part outside the region will error
+ self.expect("memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size+32",
+ patterns=["error: Address range 0x[0-9A-fa-f]+f0:0x[0-9A-Fa-f]+20 "
+ "is not in a memory tagged region"],
+ error=True)
+ self.expect("memory tag read mte_buf_2+page_size",
+ patterns=["error: Address range 0x[0-9A-fa-f]+00:0x[0-9A-Fa-f]+10 "
+ "is not in a memory tagged region"],
+ error=True)
+
+ # You can read a range that spans more than one mapping
+ # This spills into mte_buf2 which is also MTE
+ self.expect("memory tag read mte_buf+page_size-16 mte_buf+page_size+16",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+f0, 0x[0-9A-Fa-f]+00\): 0xf\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
+
+ # Tags in start/end are ignored when creating the range.
+ # So this is not an error despite start/end having different tags
+ self.expect("memory tag read mte_buf mte_buf_alt_tag+16 ",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0$"])
+
+ @skipUnlessArch("aarch64")
+ @skipUnlessPlatform(["linux"])
+ @skipUnlessAArch64MTELinuxCompiler
+ def test_mte_tag_write(self):
+ self.setup_mte_test()
+
+ # Argument validation
+ self.expect("memory tag write",
+ substrs=[" wrong number of arguments; expected "
+ "<address-expression> <tag> [<tag> [...]]"],
+ error=True)
+ self.expect("memory tag write mte_buf",
+ substrs=[" wrong number of arguments; expected "
+ "<address-expression> <tag> [<tag> [...]]"],
+ error=True)
+ self.expect("memory tag write not_a_symbol 9",
+ substrs=["error: Invalid address expression, address expression \"not_a_symbol\" "
+ "evaluation failed"],
+ error=True)
+
+ # Can't write to a region without tagging
+ self.expect("memory tag write non_mte_buf 9",
+ patterns=["error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 is not "
+ "in a memory tagged region"],
+ error=True)
+
+ # Start address is aligned down so we write to the granule that contains it
+ self.expect("memory tag write mte_buf+8 9")
+ # Make sure we only modified the first granule
+ self.expect("memory tag read mte_buf mte_buf+32",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x9\n"
+ "\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x1$"])
+
+ # You can write multiple tags, range calculated for you
+ self.expect("memory tag write mte_buf 10 11 12")
+ self.expect("memory tag read mte_buf mte_buf+48",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0xa\n"
+ "\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0xb\n"
+ "\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0xc$"])
+
+ # You may write up to the end of a tagged region
+ # (mte_buf_2's intial tags will all be 0)
+ self.expect("memory tag write mte_buf_2+page_size-16 0xe")
+ self.expect("memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size",
+ patterns=["Logical tag: 0x0\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+, 0x[0-9A-Fa-f]+\): 0xe$"])
+
+ # Ranges with any part outside the region will error
+ self.expect("memory tag write mte_buf_2+page_size-16 6 7",
+ patterns=["error: Address range 0x[0-9A-fa-f]+f0:0x[0-9A-Fa-f]+10 "
+ "is not in a memory tagged region"],
+ error=True)
+ self.expect("memory tag write mte_buf_2+page_size 6",
+ patterns=["error: Address range 0x[0-9A-fa-f]+00:0x[0-9A-Fa-f]+10 "
+ "is not in a memory tagged region"],
+ error=True)
+ self.expect("memory tag write mte_buf_2+page_size 6 7 8",
+ patterns=["error: Address range 0x[0-9A-fa-f]+00:0x[0-9A-Fa-f]+30 "
+ "is not in a memory tagged region"],
+ error=True)
+
+ # You can write to a range that spans two mappings, as long
+ # as they are both tagged.
+ # buf and buf2 are next to each other so this wirtes into buf2.
+ self.expect("memory tag write mte_buf+page_size-16 1 2")
+ self.expect("memory tag read mte_buf+page_size-16 mte_buf+page_size+16",
+ patterns=["Logical tag: 0x9\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+f0, 0x[0-9A-Fa-f]+00\): 0x1\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x2$"])
+
+ # Even if a page is read only the debugger can still write to it
+ self.expect("memory tag write mte_read_only 1")
+ self.expect("memory tag read mte_read_only",
+ patterns=["Logical tag: 0x0\n"
+ "Allocation tags:\n"
+ "\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x1$"])
+
+ # Trying to write a value > maximum tag value is an error
+ self.expect("memory tag write mte_buf 99",
+ patterns=["error: Found tag 0x63 which is > max MTE tag value of 0xf."],
+ error=True)
Index: lldb/test/API/linux/aarch64/mte_tag_read/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/linux/aarch64/mte_tag_read/Makefile
@@ -1,4 +0,0 @@
-C_SOURCES := main.c
-CFLAGS_EXTRAS := -march=armv8.5-a+memtag
-
-include Makefile.rules
Index: lldb/test/API/functionalities/memory/tag/TestMemoryTag.py
===================================================================
--- lldb/test/API/functionalities/memory/tag/TestMemoryTag.py
+++ lldb/test/API/functionalities/memory/tag/TestMemoryTag.py
@@ -39,3 +39,4 @@
expected = "error: This architecture does not support memory tagging"
self.expect("memory tag read 0 1", substrs=[expected], error=True)
+ self.expect("memory tag write 0 1 2", substrs=[expected], error=True)
Index: lldb/source/Commands/CommandObjectMemoryTag.cpp
===================================================================
--- lldb/source/Commands/CommandObjectMemoryTag.cpp
+++ lldb/source/Commands/CommandObjectMemoryTag.cpp
@@ -115,6 +115,114 @@
}
};
+#define LLDB_OPTIONS_memory_tag_write
+#include "CommandOptions.inc"
+
+class CommandObjectMemoryTagWrite : public CommandObjectParsed {
+public:
+ CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "tag",
+ "Write memory tags starting from the granule that "
+ "contains the given address.",
+ nullptr,
+ eCommandRequiresTarget | eCommandRequiresProcess |
+ eCommandProcessMustBePaused) {
+ // Address
+ m_arguments.push_back(
+ CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)});
+ // One or more tag values
+ m_arguments.push_back(CommandArgumentEntry{
+ CommandArgumentData(eArgTypeValue, eArgRepeatPlus)});
+ }
+
+ ~CommandObjectMemoryTagWrite() override = default;
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ if (command.GetArgumentCount() < 2) {
+ result.AppendError("wrong number of arguments; expected "
+ "<address-expression> <tag> [<tag> [...]]");
+ return false;
+ }
+
+ Status error;
+ addr_t start_addr = OptionArgParser::ToAddress(
+ &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
+ if (start_addr == LLDB_INVALID_ADDRESS) {
+ result.AppendErrorWithFormatv("Invalid address expression, {0}",
+ error.AsCString());
+ return false;
+ }
+
+ command.Shift(); // shift off start address
+
+ std::vector<lldb::addr_t> tags;
+ for (auto &entry : command) {
+ lldb::addr_t tag_value;
+ // getAsInteger returns true on failure
+ if (entry.ref().getAsInteger(0, tag_value)) {
+ result.AppendErrorWithFormat(
+ "'%s' is not a valid unsigned decimal string value.\n",
+ entry.c_str());
+ return false;
+ }
+ tags.push_back(tag_value);
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ process->GetMemoryTagManager();
+
+ if (!tag_manager_or_err) {
+ result.SetError(Status(tag_manager_or_err.takeError()));
+ return false;
+ }
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+
+ MemoryRegionInfos memory_regions;
+ // If this fails the list of regions is cleared, so we don't need to read
+ // the return status here.
+ process->GetMemoryRegions(memory_regions);
+
+ // We have to assume start_addr is not granule aligned.
+ // So if we simply made a range:
+ // (start_addr, start_addr + (N * granule_size))
+ // We would end up with a range that isn't N granules but N+1
+ // granules. To avoid this we'll align the start first using the method that
+ // doesn't check memory attributes. (if the final range is untagged we'll
+ // handle that error later)
+ lldb::addr_t aligned_start_addr =
+ tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1))
+ .GetRangeBase();
+
+ // Now we've aligned the start address so if we ask for another range
+ // using the number of tags N, we'll get back a range that is also N
+ // granules in size.
+ llvm::Expected<MemoryTagManager::TagRange> tagged_range =
+ tag_manager->MakeTaggedRange(
+ aligned_start_addr,
+ aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize()),
+ memory_regions);
+
+ if (!tagged_range) {
+ result.SetError(Status(tagged_range.takeError()));
+ return false;
+ }
+
+ Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(),
+ tagged_range->GetByteSize(), tags);
+
+ if (status.Fail()) {
+ result.SetError(status);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+};
+
CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "tag", "Commands for manipulating memory tags",
@@ -123,6 +231,11 @@
new CommandObjectMemoryTagRead(interpreter));
read_command_object->SetCommandName("memory tag read");
LoadSubCommand("read", read_command_object);
+
+ CommandObjectSP write_command_object(
+ new CommandObjectMemoryTagWrite(interpreter));
+ write_command_object->SetCommandName("memory tag write");
+ LoadSubCommand("write", write_command_object);
}
CommandObjectMemoryTag::~CommandObjectMemoryTag() = default;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits