xref: /llvm-project/lldb/test/API/tools/lldb-server/memory-tagging/TestGdbRemoteMemoryTagging.py (revision d4a0154902fb9b0611ed857134b26a64a1d5ad1e)
1import gdbremote_testcase
2from lldbsuite.test.decorators import *
3from lldbsuite.test.lldbtest import *
4from lldbsuite.test import lldbutil
5
6"""
7Check that lldb-server correctly processes qMemTags and QMemTags packets.
8
9In the tests below E03 means the packet wasn't formed correctly
10and E01 means it was but we had some other error acting upon it.
11
12We do not test reading or writing over a page boundary
13within the same mapping. That logic is handled in the kernel
14so it's just a single ptrace call for lldb-server.
15"""
16
17
18class TestGdbRemoteMemoryTagging(gdbremote_testcase.GdbRemoteTestCaseBase):
19    def check_memtags_response(self, packet_name, body, expected):
20        self.test_sequence.add_log_lines(
21            [
22                "read packet: ${}:{}#00".format(packet_name, body),
23                "send packet: ${}#00".format(expected),
24            ],
25            True,
26        )
27        self.expect_gdbremote_sequence()
28
29    def check_tag_read(self, body, expected):
30        self.check_memtags_response("qMemTags", body, expected)
31
32    def prep_memtags_test(self):
33        self.build()
34        self.set_inferior_startup_launch()
35        procs = self.prep_debug_monitor_and_inferior()
36
37        # We don't use isAArch64MTE here because we cannot do runCmd in an
38        # lldb-server test. Instead we run the example and skip if it fails
39        # to allocate an MTE buffer.
40
41        # Run the process
42        self.test_sequence.add_log_lines(
43            [
44                # Start running after initial stop
45                "read packet: $c#63",
46                # Match the address of the MTE page
47                {
48                    "type": "output_match",
49                    "regex": self.maybe_strict_output_regex(
50                        r"buffer: (.+) page_size: (.+)\r\n"
51                    ),
52                    "capture": {1: "buffer", 2: "page_size"},
53                },
54                # Now stop the inferior
55                "read packet: {}".format(chr(3)),
56                # And wait for the stop notification
57                {
58                    "direction": "send",
59                    "regex": r"^\$T[0-9a-fA-F]{2}thread:[0-9a-fA-F]+;",
60                },
61            ],
62            True,
63        )
64
65        # Run the packet stream
66        context = self.expect_gdbremote_sequence()
67        self.assertIsNotNone(context)
68
69        buf_address = context.get("buffer")
70        self.assertIsNotNone(buf_address)
71        page_size = context.get("page_size")
72        self.assertIsNotNone(page_size)
73
74        # nil means we couldn't set up a tagged page because the
75        # target doesn't support it.
76        if buf_address == "(nil)":
77            self.skipTest("Target must support MTE.")
78
79        buf_address = int(buf_address, 16)
80        page_size = int(page_size, 16)
81
82        return buf_address, page_size
83
84    @skipUnlessArch("aarch64")
85    @skipUnlessPlatform(["linux"])
86    @skipUnlessAArch64MTELinuxCompiler
87    def test_tag_read_qMemTags_packets(self):
88        """Test that qMemTags packets are parsed correctly and/or rejected."""
89        buf_address, page_size = self.prep_memtags_test()
90
91        # Sanity check that address is correct
92        self.check_tag_read("{:x},20:1".format(buf_address), "m0001")
93
94        # Invalid packets
95
96        # No content
97        self.check_tag_read("", "E03")
98        # Only address
99        self.check_tag_read("{:x}".format(buf_address), "E03")
100        # Only address and length
101        self.check_tag_read("{:x},20".format(buf_address), "E03")
102        # Empty address
103        self.check_tag_read(",20:1", "E03")
104        # Invalid addresses
105        self.check_tag_read("aardvark,20:1", "E03")
106        self.check_tag_read("-100,20:1", "E03")
107        self.check_tag_read("cafe?,20:1", "E03")
108        # Empty length
109        self.check_tag_read("{:x},:1".format(buf_address), "E03")
110        # Invalid lengths
111        self.check_tag_read("{:x},food:1".format(buf_address), "E03")
112        self.check_tag_read("{:x},-1:1".format(buf_address), "E03")
113        self.check_tag_read("{:x},12??:1".format(buf_address), "E03")
114        # Empty type
115        self.check_tag_read("{:x},10:".format(buf_address), "E03")
116        # Types we don't support
117        self.check_tag_read("{:x},10:FF".format(buf_address), "E01")
118        # Types can also be negative, -1 in this case.
119        # So this is E01 for not supported, instead of E03 for invalid formatting.
120        self.check_tag_read("{:x},10:FFFFFFFF".format(buf_address), "E01")
121        # (even if the length of the read is zero)
122        self.check_tag_read("{:x},0:FF".format(buf_address), "E01")
123        # Invalid type format
124        self.check_tag_read("{:x},10:cat".format(buf_address), "E03")
125        self.check_tag_read("{:x},10:?11".format(buf_address), "E03")
126        # Type is signed but in packet as raw bytes, no +/-.
127        self.check_tag_read("{:x},10:-1".format(buf_address), "E03")
128        self.check_tag_read("{:x},10:+20".format(buf_address), "E03")
129        # We do use a uint64_t for unpacking but that's just an implementation
130        # detail. Any value > 32 bit is invalid.
131        self.check_tag_read("{:x},10:123412341".format(buf_address), "E03")
132
133        # Valid packets
134
135        # Reading nothing is allowed
136        self.check_tag_read("{:x},0:1".format(buf_address), "m")
137        # A range that's already aligned
138        self.check_tag_read("{:x},20:1".format(buf_address), "m0001")
139        # lldb-server should re-align the range
140        # Here we read from 1/2 way through a granule, into the next. Expands to 2 granules
141        self.check_tag_read("{:x},10:1".format(buf_address + 64 - 8), "m0304")
142        # Read up to the end of an MTE page.
143        # We know that the last tag should be 0xF since page size will always be a
144        # multiple of 256 bytes, which is 16 granules and we have 16 tags to use.
145        self.check_tag_read("{:x},10:1".format(buf_address + page_size - 16), "m0f")
146        # Here we read off of the end of the MTE range so ptrace gives us one tag,
147        # then fails on the second call. To lldb-server this means the response
148        # should just be an error, not a partial read.
149        self.check_tag_read("{:x},20:1".format(buf_address + page_size - 16), "E01")
150
151    def check_tag_write(self, body, expected):
152        self.check_memtags_response("QMemTags", body, expected)
153
154    @skipUnlessArch("aarch64")
155    @skipUnlessPlatform(["linux"])
156    @skipUnlessAArch64MTELinuxCompiler
157    def test_tag_write_QMemTags_packets(self):
158        """Test that QMemTags packets are parsed correctly and/or rejected."""
159        buf_address, page_size = self.prep_memtags_test()
160
161        # Sanity check that address is correct
162        self.check_tag_write("{:x},10:1:0e".format(buf_address), "OK")
163        self.check_tag_read("{:x},10:1".format(buf_address), "m0e")
164
165        # No content
166        self.check_tag_write("", "E03")
167        # Only address
168        self.check_tag_write("{:x}".format(buf_address), "E03")
169        # Only address and length
170        self.check_tag_write("{:x},20".format(buf_address), "E03")
171        # Missing data
172        self.check_tag_write("{:x},20:1".format(buf_address), "E03")
173        # Zero length write must still include separator after type
174        self.check_tag_write("{:x},0:1".format(buf_address), "E03")
175        # Empty address
176        self.check_tag_write(",10:1:01", "E03")
177        # Invalid addresses
178        self.check_tag_write("aardvark,10:1:01", "E03")
179        self.check_tag_write("-100,10:1:01", "E03")
180        self.check_tag_write("cafe?,10:1:01", "E03")
181        # Empty length
182        self.check_tag_write("{:x},:1:01".format(buf_address), "E03")
183        # Invalid lengths
184        self.check_tag_write("{:x},food:1:01".format(buf_address), "E03")
185        self.check_tag_write("{:x},-1:1:01".format(buf_address), "E03")
186        self.check_tag_write("{:x},12??:1:01".format(buf_address), "E03")
187        # Empty type
188        self.check_tag_write("{:x},10::01".format(buf_address), "E03")
189        # Types we don't support
190        self.check_tag_write("{:x},10:FF:01".format(buf_address), "E01")
191        # (even if the length of the write is zero)
192        self.check_tag_write("{:x},0:FF:".format(buf_address), "E01")
193        # Invalid type format
194        self.check_tag_write("{:x},0:cat:".format(buf_address), "E03")
195        self.check_tag_write("{:x},0:?11:".format(buf_address), "E03")
196        # Leading +/- not allowed
197        self.check_tag_write("{:x},10:-1:".format(buf_address), "E03")
198        self.check_tag_write("{:x},10:+20:".format(buf_address), "E03")
199        # We use a uint64_t when parsing, but dont expect anything > 32 bits
200        self.check_tag_write("{:x},10:123412341:".format(buf_address), "E03")
201        # Invalid tag data
202        self.check_tag_write("{:x},10:1:??".format(buf_address), "E03")
203        self.check_tag_write("{:x},10:1:45?".format(buf_address), "E03")
204        # (must be 2 chars per byte)
205        self.check_tag_write("{:x},10:1:123".format(buf_address), "E03")
206        # Tag out of range
207        self.check_tag_write("{:x},10:1:23".format(buf_address), "E01")
208        # Non-zero length write must include some tag data
209        self.check_tag_write("{:x},10:1:".format(buf_address), "E01")
210
211        # Valid packets
212
213        # Zero length write doesn't need any tag data (but should include the :)
214        self.check_tag_write("{:x},0:1:".format(buf_address), "OK")
215        # Zero length unaligned is the same
216        self.check_tag_write("{:x},0:1:".format(buf_address + 8), "OK")
217        # Ranges can be aligned already
218        self.check_tag_write("{:x},20:1:0405".format(buf_address), "OK")
219        self.check_tag_read("{:x},20:1".format(buf_address), "m0405")
220        # Unaliged ranges will be aligned by the server
221        self.check_tag_write("{:x},10:1:0607".format(buf_address + 8), "OK")
222        self.check_tag_read("{:x},20:1".format(buf_address), "m0607")
223        # Tags will be repeated as needed to cover the range
224        self.check_tag_write("{:x},30:1:09".format(buf_address), "OK")
225        self.check_tag_read("{:x},30:1".format(buf_address), "m090909")
226        # One more repeating tags for good measure, part repetition this time
227        # (for full tests see the MemoryTagManagerAArch64MTE unittests)
228        self.check_tag_write("{:x},30:1:0a0b".format(buf_address), "OK")
229        self.check_tag_read("{:x},30:1".format(buf_address), "m0a0b0a")
230        # We can write up to the end of the MTE page
231        last_granule = buf_address + page_size - 16
232        self.check_tag_write("{:x},10:1:0c".format(last_granule), "OK")
233        self.check_tag_read("{:x},10:1".format(last_granule), "m0c")
234        # Writing over the end of the page is an error
235        self.check_tag_write("{:x},20:1:0d".format(last_granule), "E01")
236        # The last tag in the page was written thought, and we do not
237        # attempt to restore its original value.
238        self.check_tag_read("{:x},10:1".format(last_granule), "m0d")
239