Commit | Line | Data |
---|---|---|
88b9d363 | 1 | # Copyright (C) 2021-2022 Free Software Foundation, Inc. |
bf0aecce LM |
2 | |
3 | # This program is free software; you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation; either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | # Test a binary that uses MTE and exercise various MTE-related scenarios. | |
17 | ||
18 | global hex | |
19 | global decimal | |
20 | ||
21 | # Return TAG in hex format with no leading zeroes. | |
22 | proc get_hex_tag { tag } { | |
23 | return [format "%x" $tag] | |
24 | } | |
25 | ||
26 | # Return TAG in the NN format where N is 4 bits of the byte. | |
27 | proc get_tag_nn { tag } { | |
28 | return [format "%02x" $tag] | |
29 | } | |
30 | ||
31 | # Return the address of PTR with a tag of TAG. | |
32 | proc get_tagged_ptr { tag ptr } { | |
33 | set addr [get_hexadecimal_valueof $ptr -1] | |
34 | return [get_valueof "/x" \ | |
35 | "${addr} & (0xf0ffffffffffffff) | ((unsigned long) ${tag} << 56)" \ | |
36 | "0" "fetch pointer ${ptr} with tag ${tag}"] | |
37 | } | |
38 | ||
39 | # Return the logical TAG from PTR. | |
40 | proc get_ltag_from_ptr { ptr } { | |
41 | set addr [get_hexadecimal_valueof $ptr -1] | |
42 | return [get_valueof "/x" "${addr} >> 56 & 0xf" -1 \ | |
43 | "fetch tag from pointer ${ptr}"] | |
44 | } | |
45 | ||
46 | if {![is_aarch64_target]} { | |
47 | verbose "Skipping ${gdb_test_file_name}." | |
48 | return | |
49 | } | |
50 | ||
51 | standard_testfile | |
52 | if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { | |
53 | return -1 | |
54 | } | |
55 | ||
56 | if ![runto_main] { | |
57 | untested "could not run to main" | |
58 | return -1 | |
59 | } | |
60 | ||
61 | # Targets that don't support memory tagging should not execute the | |
62 | # runtime memory tagging tests. | |
63 | if {![supports_memtag]} { | |
64 | unsupported "memory tagging unsupported" | |
65 | return -1 | |
66 | } | |
67 | ||
68 | gdb_breakpoint "access_memory" | |
69 | ||
70 | if [gdb_continue "access_memory"] { | |
71 | return -1 | |
72 | } | |
73 | ||
74 | # Fetch a known pointer to an area mapped with PROT_MTE. | |
75 | set tagged_ptr_symbol "tagged_ptr" | |
76 | set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1] | |
77 | ||
78 | if {$tagged_ptr_addr == -1} { | |
79 | unresolved "unexpected pointer or tag value" | |
80 | return -1 | |
81 | } | |
82 | ||
83 | # Fetch a known pointer to an area not mapped with PROT_MTE. | |
84 | set untagged_ptr_symbol "untagged_ptr" | |
85 | set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1] | |
86 | ||
87 | if {$untagged_ptr_addr == -1} { | |
88 | unresolved "unexpected pointer or tag value" | |
89 | return -1 | |
90 | } | |
91 | ||
92 | with_test_prefix "literals" { | |
93 | # Test inspecting an allocation tag from a pointer to a memory area that | |
94 | # is not mapped with PROT_MTE. | |
95 | set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\." | |
96 | gdb_test "memory-tag print-allocation-tag ${untagged_ptr_addr}" $msg \ | |
97 | "memory-tag print-allocation-tag with an untagged address" | |
98 | ||
99 | gdb_test "memory-tag set-allocation-tag ${untagged_ptr_addr} 1 00" $msg \ | |
100 | "memory-tag set-allocation-tag with an untagged address" | |
101 | ||
102 | set addr_tagged 0 | |
103 | set addr_tagged_valid 0 | |
104 | ||
105 | # Test setting and showing the logical tags for a literal address. | |
106 | for {set i 0} {$i < 32} {incr i} { | |
107 | with_test_prefix "tag ${i}" { | |
108 | set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}] | |
109 | } | |
110 | ||
111 | set tag_hexnz [get_hex_tag [expr $i % 16]] | |
112 | gdb_test "memory-tag print-logical-tag ${addr_tagged}" \ | |
113 | " = 0x${tag_hexnz}" \ | |
114 | "print-logical-tag with tag ${i}" | |
115 | ||
116 | set tag_hexnn [get_tag_nn $i] | |
117 | gdb_test "memory-tag with-logical-tag ${addr_tagged} ${tag_hexnn}" \ | |
118 | " = \\(void \\*\\) ${addr_tagged}" \ | |
119 | "with-logical-tag with tag ${i}" | |
120 | } | |
121 | ||
122 | set atag_msg "Allocation tag\\(s\\) updated successfully\." | |
123 | # Test setting and showing the allocation tags. | |
124 | for {set i 0} {$i < 32} {incr i} { | |
125 | ||
126 | set tag_hexnn [get_tag_nn $i] | |
127 | gdb_test "memory-tag set-allocation-tag ${tagged_ptr_addr} 1 ${tag_hexnn}" \ | |
128 | $atag_msg \ | |
129 | "set-allocation-tag with tag ${i}" | |
130 | ||
131 | set tag_hexnz [get_hex_tag [expr $i % 16]] | |
132 | gdb_test "memory-tag print-allocation-tag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \ | |
133 | "print-allocation-tag with tag ${i}" | |
134 | } | |
135 | ||
136 | # Test tag mismatches. | |
137 | with_test_prefix "tag mismatches" { | |
138 | for {set i 0} {$i < 32} {incr i} { | |
139 | ||
140 | # Set the allocation tag to a known value. | |
141 | set tag_hexnn [get_tag_nn $i] | |
142 | gdb_test "memory-tag set-allocation-tag ${tagged_ptr_addr} 1 ${tag_hexnn}" \ | |
143 | $atag_msg \ | |
144 | "set-allocation-tag with tag ${i}" | |
145 | ||
146 | set atag_hexnz [get_hex_tag [expr $i % 16]] | |
147 | ||
148 | # Validate that the logical tag matches the allocation tag. | |
149 | with_test_prefix "tag ${i}" { | |
150 | set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}] | |
151 | } | |
152 | ||
153 | gdb_test "memory-tag check ${addr_tagged}" \ | |
154 | "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \ | |
155 | "check match with tag ${i}" | |
156 | ||
157 | # Get a pointer with the logical tag that does not match the | |
158 | # allocation tag. | |
159 | set ltag [expr $i + 1] | |
160 | with_test_prefix "fetch mismatch tag ${i}" { | |
161 | set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}] | |
162 | } | |
163 | ||
164 | # Validate that the logical tag does not match the allocation | |
165 | # tag. | |
166 | set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]] | |
167 | gdb_test "memory-tag check ${addr_tagged}" \ | |
168 | "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \ | |
169 | "check mismatch with tag ${i}" | |
170 | } | |
171 | } | |
172 | } | |
173 | ||
174 | with_test_prefix "symbolic" { | |
175 | # Test inspecting an allocation tag from a pointer to a memory area that | |
176 | # is not mapped with PROT_MTE. | |
177 | set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\." | |
178 | gdb_test "memory-tag print-allocation-tag ${untagged_ptr_symbol}" $msg \ | |
179 | "memory-tag print-allocation-tag with an untagged address" | |
180 | ||
181 | gdb_test "memory-tag set-allocation-tag ${untagged_ptr_symbol} 1 00" $msg \ | |
182 | "memory-tag set-allocation-tag with an untagged address" | |
183 | ||
184 | # Test setting and showing the logical tags for a literal address. | |
185 | for {set i 0} {$i < 32} {incr i} { | |
186 | set addr_tagged 0 | |
187 | ||
188 | with_test_prefix "tag ${i}" { | |
189 | set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}] | |
190 | gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \ | |
191 | "update value of symbol ${tagged_ptr_symbol}" | |
192 | } | |
193 | ||
194 | set tag_hexnz [get_hex_tag [expr $i % 16]] | |
195 | gdb_test "memory-tag print-logical-tag ${tagged_ptr_symbol}" \ | |
196 | " = 0x${tag_hexnz}" \ | |
197 | "print-logical-tag with tag ${i}" | |
198 | ||
199 | set tag_hexnn [get_tag_nn $i] | |
200 | gdb_test "memory-tag with-logical-tag ${tagged_ptr_symbol} ${tag_hexnn}" \ | |
201 | " = \\(void \\*\\) ${addr_tagged}" \ | |
202 | "with-logical-tag with tag ${i}" | |
203 | } | |
204 | ||
205 | # Reset the tagged ptr to its original value | |
206 | gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \ | |
207 | "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}" | |
208 | ||
209 | set atag_msg "Allocation tag\\(s\\) updated successfully\." | |
210 | # Test setting and showing the allocation tags. | |
211 | for {set i 0} {$i < 32} {incr i} { | |
212 | ||
213 | set tag_hexnn [get_tag_nn $i] | |
214 | gdb_test "memory-tag set-allocation-tag ${tagged_ptr_symbol} 1 ${tag_hexnn}" \ | |
215 | $atag_msg \ | |
216 | "set-allocation-tag with tag ${i}" | |
217 | ||
218 | set tag_hexnz [get_hex_tag [expr $i % 16]] | |
219 | gdb_test "memory-tag print-allocation-tag ${tagged_ptr_symbol}" \ | |
220 | " = 0x${tag_hexnz}" \ | |
221 | "print-allocation-tag with tag ${i}" | |
222 | } | |
223 | ||
224 | # Test tag mismatches. | |
225 | with_test_prefix "tag mismatches" { | |
226 | for {set i 0} {$i < 32} {incr i} { | |
227 | ||
228 | # Set the allocation tag to a known value (0). | |
229 | set tag_hexnn [get_tag_nn $i] | |
230 | gdb_test "memory-tag set-allocation-tag ${tagged_ptr_symbol} 1 ${tag_hexnn}" \ | |
231 | $atag_msg \ | |
232 | "set-allocation-tag with tag ${i}" | |
233 | ||
234 | set atag_hexnz [get_hex_tag [expr $i % 16]] | |
235 | ||
236 | # Validate that the logical tag matches the allocation tag. | |
237 | with_test_prefix "tag ${i}" { | |
238 | set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}] | |
239 | } | |
240 | ||
241 | with_test_prefix "tag ${i}" { | |
242 | gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \ | |
243 | "set ${tagged_ptr_symbol} to a matching logical tag" | |
244 | } | |
245 | ||
246 | gdb_test "memory-tag check ${tagged_ptr_symbol}" \ | |
247 | "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \ | |
248 | "check match with tag ${i}" | |
249 | ||
250 | # Get a pointer with the logical tag that does not match the | |
251 | # allocation tag. | |
252 | set ltag [expr $i + 1] | |
253 | with_test_prefix "fetch mismatch tag ${i}" { | |
254 | set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}] | |
255 | } | |
256 | ||
257 | with_test_prefix "tag ${i}" { | |
258 | gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \ | |
259 | "set ${tagged_ptr_symbol} to a mismatching logical tag" | |
260 | } | |
261 | ||
262 | # Validate that the logical tag does not match the allocation | |
263 | # tag. | |
264 | set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]] | |
265 | gdb_test "memory-tag check ${tagged_ptr_symbol}" \ | |
266 | "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \ | |
267 | "check mismatch with tag ${i}" | |
268 | } | |
269 | # Reset the tagged ptr to its original value | |
270 | gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \ | |
271 | "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}" | |
272 | } | |
273 | } | |
274 | ||
275 | # Test the memory tagging extensions for the "print" command. | |
276 | with_test_prefix "print command" { | |
277 | set untagged_ptr [get_tagged_ptr 0 ${tagged_ptr_addr}] | |
278 | ||
279 | with_test_prefix "fetch ltag" { | |
280 | set ltag [get_ltag_from_ptr ${tagged_ptr_addr}] | |
281 | } | |
282 | ||
283 | if {$ltag == -1} { | |
284 | unresolved "unexpected tag value" | |
285 | return -1 | |
286 | } | |
287 | ||
288 | set atag [expr [expr $ltag + 1] % 16] | |
289 | set atag_hexnn [get_tag_nn $atag] | |
290 | ||
291 | gdb_test "memory-tag set-allocation-tag ${tagged_ptr_symbol} 1 ${atag_hexnn}" \ | |
292 | $atag_msg \ | |
293 | "make atag and ltag different" | |
294 | ||
295 | set atag_hexnz [get_hex_tag $atag] | |
296 | gdb_test "p/x ${tagged_ptr_symbol}" \ | |
297 | [multi_line \ | |
298 | "Logical tag \\(${ltag}\\) does not match the allocation tag \\(0x${atag_hexnz}\\)\." \ | |
299 | "\\\$\[0-9\]+ = ${untagged_ptr}"] \ | |
300 | "show tag mismatch" | |
301 | } | |
302 | ||
303 | # Test the memory tagging extensions for the "x" command. | |
304 | with_test_prefix "x command" { | |
305 | ||
306 | # Check if the allocation tags match what we expect. | |
307 | gdb_test "x/gxm ${tagged_ptr_symbol}" \ | |
308 | [multi_line \ | |
309 | "<Allocation Tag $hex for range \\\[$hex,$hex\\)>" \ | |
310 | "$hex:\[ \t\]+$hex"] \ | |
311 | "outputs tag information" | |
312 | ||
313 | # Also make sure no tag information is output for memory areas without | |
314 | # PROT_MTE mappings. | |
315 | gdb_test "x/gxm ${untagged_ptr_symbol}" \ | |
316 | "$hex:\[ \t\]+$hex" \ | |
317 | "does not output tag information" | |
318 | } | |
319 | ||
320 | # Validate the presence of the MTE registers. | |
321 | foreach reg {"tag_ctl" } { | |
322 | gdb_test "info registers $reg" \ | |
323 | "$reg\[ \t\]+$hex\[ \t\]+$decimal" \ | |
324 | "register $reg available" | |
325 | } | |
326 | ||
327 | # Run until a crash and confirm GDB displays memory tag violation | |
328 | # information. | |
329 | gdb_test "continue" \ | |
330 | [multi_line \ | |
331 | "Program received signal SIGSEGV, Segmentation fault" \ | |
332 | "Memory tag violation while accessing address $hex" \ | |
333 | "Allocation tag $hex" \ | |
334 | "Logical tag $hex\." \ | |
335 | "$hex in access_memory \\(.*\\) at .*" \ | |
336 | ".*tagged_ptr\\\[0\\\] = 'a';"] \ | |
337 | "display tag violation information" | |
338 | ||
339 | # Restart to execute the async tag fault test. | |
340 | with_test_prefix "async" { | |
341 | if ![runto_main] { | |
342 | untested "could not run to main" | |
343 | return -1 | |
344 | } | |
345 | ||
346 | gdb_breakpoint "access_memory" | |
347 | ||
348 | if [gdb_continue "access_memory"] { | |
349 | fail "could not run to tagged memory test function" | |
350 | return -1 | |
351 | } | |
352 | ||
353 | # Force a tag fault. | |
354 | gdb_test "memory-tag set-allocation-tag tagged_ptr 1 05" \ | |
355 | $atag_msg \ | |
356 | "make atag and ltag different" | |
357 | ||
358 | # Force the tag fault to be async. | |
359 | gdb_test_no_output "set \$tag_ctl=0x7fff5" "set tag_ctl to async" | |
360 | ||
361 | # Run until a crash and confirm GDB displays memory tag violation | |
362 | # information for async mode | |
363 | gdb_test "continue" \ | |
364 | [multi_line \ | |
365 | "Program received signal SIGSEGV, Segmentation fault" \ | |
366 | "Memory tag violation" \ | |
367 | "Fault address unavailable\." \ | |
368 | "$hex in .* \\(.*\\) .*"] \ | |
369 | "display tag violation information" | |
370 | } |