|
| 1 | +""" |
| 2 | +Test that memory tagging features work with Linux core files. |
| 3 | +""" |
| 4 | + |
| 5 | + |
| 6 | +import lldb |
| 7 | +from lldbsuite.test.decorators import * |
| 8 | +from lldbsuite.test.lldbtest import * |
| 9 | + |
| 10 | + |
| 11 | +class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): |
| 12 | + |
| 13 | + mydir = TestBase.compute_mydir(__file__) |
| 14 | + |
| 15 | + NO_DEBUG_INFO_TESTCASE = True |
| 16 | + |
| 17 | + MTE_BUF_ADDR = hex(0xffff82c74000) |
| 18 | + BUF_ADDR = hex(0xffff82c73000) |
| 19 | + |
| 20 | + @skipIfLLVMTargetMissing("AArch64") |
| 21 | + def test_mte_tag_core_file_memory_region(self): |
| 22 | + """ Test that memory regions are marked as tagged when there is a tag |
| 23 | + segment in the core file. """ |
| 24 | + self.runCmd("target create --core core.mte") |
| 25 | + |
| 26 | + # There should only be one tagged region. |
| 27 | + self.runCmd("memory region --all") |
| 28 | + got = self.res.GetOutput() |
| 29 | + found_tagged_region = False |
| 30 | + |
| 31 | + for line in got.splitlines(): |
| 32 | + if "memory tagging: enabled" in line: |
| 33 | + if found_tagged_region: |
| 34 | + self.fail("Expected only one tagged region.") |
| 35 | + found_tagged_region = True |
| 36 | + |
| 37 | + self.assertTrue(found_tagged_region, "Did not find a tagged memory region.") |
| 38 | + |
| 39 | + # mte_buf is tagged, buf is not. |
| 40 | + tagged = "memory tagging: enabled" |
| 41 | + self.expect("memory region {}".format(self.MTE_BUF_ADDR), |
| 42 | + patterns=[tagged]) |
| 43 | + self.expect("memory region {}".format(self.BUF_ADDR), |
| 44 | + patterns=[tagged], matching=False) |
| 45 | + |
| 46 | + @skipIfLLVMTargetMissing("AArch64") |
| 47 | + def test_mte_tag_core_file_tag_write(self): |
| 48 | + """ Test that "memory tag write" does not work with core files |
| 49 | + as they are read only. """ |
| 50 | + self.runCmd("target create --core core.mte") |
| 51 | + |
| 52 | + self.expect("memory tag write {} 1".format(self.MTE_BUF_ADDR), error=True, |
| 53 | + patterns=["error: elf-core does not support writing memory tags"]) |
| 54 | + |
| 55 | + @skipIfLLVMTargetMissing("AArch64") |
| 56 | + def test_mte_tag_core_file_tag_read(self): |
| 57 | + """ Test that "memory tag read" works with core files.""" |
| 58 | + self.runCmd("target create --core core.mte") |
| 59 | + |
| 60 | + # Tags are packed 2 per byte meaning that in addition to granule alignment |
| 61 | + # there is also 2 x granule alignment going on. |
| 62 | + |
| 63 | + # All input validation should work as normal. |
| 64 | + not_tagged_pattern = ("error: Address range 0x[A-Fa-f0-9]+:0x[A-Fa-f0-9]+ " |
| 65 | + "is not in a memory tagged region") |
| 66 | + self.expect("memory tag read {}".format(self.BUF_ADDR), |
| 67 | + error=True, patterns=[not_tagged_pattern]) |
| 68 | + # The first part of this range is not tagged. |
| 69 | + self.expect("memory tag read {addr}-16 {addr}+16".format( |
| 70 | + addr=self.MTE_BUF_ADDR), error=True, |
| 71 | + patterns=[not_tagged_pattern]) |
| 72 | + # The last part of this range is not tagged. |
| 73 | + self.expect("memory tag read {addr}+4096-16 {addr}+4096+16".format( |
| 74 | + addr=self.MTE_BUF_ADDR), error=True, |
| 75 | + patterns=[not_tagged_pattern]) |
| 76 | + |
| 77 | + self.expect("memory tag read {addr}+16 {addr}".format( |
| 78 | + addr=self.MTE_BUF_ADDR), error=True, |
| 79 | + patterns=["error: End address \(0x[A-Fa-f0-9]+\) " |
| 80 | + "must be greater than the start address " |
| 81 | + "\(0x[A-Fa-f0-9]+\)"]) |
| 82 | + |
| 83 | + # The simplest scenario. 2 granules means 1 byte of packed tags |
| 84 | + # with no realignment required. |
| 85 | + self.expect("memory tag read {addr} {addr}+32".format( |
| 86 | + addr=self.MTE_BUF_ADDR), |
| 87 | + patterns=[ |
| 88 | + "Allocation tags:\n" |
| 89 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| 90 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| 91 | + |
| 92 | + # Here we want just one tag so must use half of the first byte. |
| 93 | + # (start is aligned length is not) |
| 94 | + self.expect("memory tag read {addr} {addr}+16".format( |
| 95 | + addr=self.MTE_BUF_ADDR), |
| 96 | + patterns=[ |
| 97 | + "Allocation tags:\n" |
| 98 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"]) |
| 99 | + # Get the other half of the first byte. |
| 100 | + # (end is aligned start is not) |
| 101 | + self.expect("memory tag read {addr}+16 {addr}+32".format( |
| 102 | + addr=self.MTE_BUF_ADDR), |
| 103 | + patterns=[ |
| 104 | + "Allocation tags:\n" |
| 105 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| 106 | + |
| 107 | + # Same thing but with a starting range > 1 granule. |
| 108 | + self.expect("memory tag read {addr} {addr}+48".format( |
| 109 | + addr=self.MTE_BUF_ADDR), |
| 110 | + patterns=[ |
| 111 | + "Allocation tags:\n" |
| 112 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| 113 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| 114 | + "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"]) |
| 115 | + self.expect("memory tag read {addr}+16 {addr}+64".format( |
| 116 | + addr=self.MTE_BUF_ADDR), |
| 117 | + patterns=[ |
| 118 | + "Allocation tags:\n" |
| 119 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| 120 | + "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n" |
| 121 | + "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)$"]) |
| 122 | + # Here both start and end are unaligned. |
| 123 | + self.expect("memory tag read {addr}+16 {addr}+80".format( |
| 124 | + addr=self.MTE_BUF_ADDR), |
| 125 | + patterns=[ |
| 126 | + "Allocation tags:\n" |
| 127 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n" |
| 128 | + "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n" |
| 129 | + "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)\n" |
| 130 | + "\[0x[A-Fa-f0-9]+40, 0x[A-Fa-f0-9]+50\): 0x4 \(mismatch\)$"]) |
| 131 | + |
| 132 | + # For the intial alignment of start/end to granule boundaries the tag manager |
| 133 | + # is used, so this reads 1 tag as it would normally. |
| 134 | + self.expect("memory tag read {addr} {addr}+1".format( |
| 135 | + addr=self.MTE_BUF_ADDR), |
| 136 | + patterns=[ |
| 137 | + "Allocation tags:\n" |
| 138 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"]) |
| 139 | + |
| 140 | + # This range is aligned to granules as mte_buf to mte_buf+32 so the result |
| 141 | + # should be 2 granules. |
| 142 | + self.expect("memory tag read {addr} {addr}+17".format( |
| 143 | + addr=self.MTE_BUF_ADDR), |
| 144 | + patterns=[ |
| 145 | + "Allocation tags:\n" |
| 146 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| 147 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"]) |
| 148 | + |
| 149 | + # Alignment of this range causes it to become unaligned to 2*granule boundaries. |
| 150 | + self.expect("memory tag read {addr} {addr}+33".format( |
| 151 | + addr=self.MTE_BUF_ADDR), |
| 152 | + patterns=[ |
| 153 | + "Allocation tags:\n" |
| 154 | + "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n" |
| 155 | + "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n", |
| 156 | + "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"]) |
| 157 | + |
| 158 | + @skipIfLLVMTargetMissing("AArch64") |
| 159 | + def test_mte_commands_no_mte(self): |
| 160 | + """ Test that memory tagging commands fail on an AArch64 corefile without |
| 161 | + any tag segments.""" |
| 162 | + |
| 163 | + self.runCmd("target create --core core.nomte") |
| 164 | + |
| 165 | + self.expect("memory tag read 0 1", |
| 166 | + substrs=["error: Process does not support memory tagging"], error=True) |
| 167 | + # Note that this tells you memory tagging is not supported at all, versus |
| 168 | + # the MTE core file which does support it but does not allow writing tags. |
| 169 | + self.expect("memory tag write 0 1", |
| 170 | + substrs=["error: Process does not support memory tagging"], error=True) |
0 commit comments