| """ |
| Test that memory tagging features work with Linux core files. |
| """ |
| |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| |
| |
| class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): |
| |
| mydir = TestBase.compute_mydir(__file__) |
| |
| NO_DEBUG_INFO_TESTCASE = True |
| |
| MTE_BUF_ADDR = hex(0xffff82c74000) |
| BUF_ADDR = hex(0xffff82c73000) |
| |
| @skipIfLLVMTargetMissing("AArch64") |
| def test_mte_tag_core_file_memory_region(self): |
| """ Test that memory regions are marked as tagged when there is a tag |
| segment in the core file. """ |
| self.runCmd("target create --core core.mte") |
| |
| # There should only be one tagged region. |
| self.runCmd("memory region --all") |
| got = self.res.GetOutput() |
| found_tagged_region = False |
| |
| for line in got.splitlines(): |
| if "memory tagging: enabled" in line: |
| if found_tagged_region: |
| self.fail("Expected only one tagged region.") |
| found_tagged_region = True |
| |
| self.assertTrue(found_tagged_region, "Did not find a tagged memory region.") |
| |
| # mte_buf is tagged, buf is not. |
| tagged = "memory tagging: enabled" |
| self.expect("memory region {}".format(self.MTE_BUF_ADDR), |
| patterns=[tagged]) |
| self.expect("memory region {}".format(self.BUF_ADDR), |
| patterns=[tagged], matching=False) |
| |
| @skipIfLLVMTargetMissing("AArch64") |
| def test_mte_tag_core_file_tag_write(self): |
| """ Test that "memory tag write" does not work with core files |
| as they are read only. """ |
| self.runCmd("target create --core core.mte") |
| |
| self.expect("memory tag write {} 1".format(self.MTE_BUF_ADDR), error=True, |
| patterns=["error: elf-core does not support writing memory tags"]) |
| |
| @skipIfLLVMTargetMissing("AArch64") |
| def test_mte_tag_core_file_tag_read(self): |
| """ Test that "memory tag read" works with core files.""" |
| self.runCmd("target create --core core.mte") |
| |
| # Tags are packed 2 per byte meaning that in addition to granule alignment |
| # there is also 2 x granule alignment going on. |
| |
| # All input validation should work as normal. |
| not_tagged_pattern = ("error: Address range 0x[A-Fa-f0-9]+:0x[A-Fa-f0-9]+ " |
| "is not in a memory tagged region") |
| self.expect("memory tag read {}".format(self.BUF_ADDR), |
| error=True, patterns=[not_tagged_pattern]) |
| # The first part of this range is not tagged. |
| self.expect("memory tag read {addr}-16 {addr}+16".format( |
| addr=self.MTE_BUF_ADDR), error=True, |
| patterns=[not_tagged_pattern]) |
| # The last part of this range is not tagged. |
| self.expect("memory tag read {addr}+4096-16 {addr}+4096+16".format( |
| addr=self.MTE_BUF_ADDR), error=True, |
| patterns=[not_tagged_pattern]) |
| |
| self.expect("memory tag read {addr}+16 {addr}".format( |
| addr=self.MTE_BUF_ADDR), error=True, |
| patterns=["error: End address \(0x[A-Fa-f0-9]+\) " |
| "must be greater than the start address " |
| "\(0x[A-Fa-f0-9]+\)"]) |
| |
| # The simplest scenario. 2 granules means 1 byte of packed tags |
| # with no realignment required. |
| self.expect("memory tag read {addr} {addr}+32".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| |
| # Here we want just one tag so must use half of the first byte. |
| # (start is aligned length is not) |
| self.expect("memory tag read {addr} {addr}+16".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"]) |
| # Get the other half of the first byte. |
| # (end is aligned start is not) |
| self.expect("memory tag read {addr}+16 {addr}+32".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| |
| # Same thing but with a starting range > 1 granule. |
| self.expect("memory tag read {addr} {addr}+48".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"]) |
| self.expect("memory tag read {addr}+16 {addr}+64".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)$"]) |
| # Here both start and end are unaligned. |
| self.expect("memory tag read {addr}+16 {addr}+80".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)\n" |
| "\[0x[A-Fa-f0-9]+40, 0x[A-Fa-f0-9]+50\): 0x4 \(mismatch\)$"]) |
| |
| # For the intial alignment of start/end to granule boundaries the tag manager |
| # is used, so this reads 1 tag as it would normally. |
| self.expect("memory tag read {addr} {addr}+1".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"]) |
| |
| # This range is aligned to granules as mte_buf to mte_buf+32 so the result |
| # should be 2 granules. |
| self.expect("memory tag read {addr} {addr}+17".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| |
| # Alignment of this range causes it to become unaligned to 2*granule boundaries. |
| self.expect("memory tag read {addr} {addr}+33".format( |
| addr=self.MTE_BUF_ADDR), |
| patterns=[ |
| "Allocation tags:\n" |
| "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n", |
| "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"]) |
| |
| @skipIfLLVMTargetMissing("AArch64") |
| def test_mte_commands_no_mte(self): |
| """ Test that memory tagging commands fail on an AArch64 corefile without |
| any tag segments.""" |
| |
| self.runCmd("target create --core core.nomte") |
| |
| self.expect("memory tag read 0 1", |
| substrs=["error: Process does not support memory tagging"], error=True) |
| # Note that this tells you memory tagging is not supported at all, versus |
| # the MTE core file which does support it but does not allow writing tags. |
| self.expect("memory tag write 0 1", |
| substrs=["error: Process does not support memory tagging"], error=True) |