| 1 | # |
| 2 | # Test GDB memory-tag commands that exercise the stubs for the qIsAddressTagged, |
| 3 | # qMemTag, and QMemTag packets, which are used for manipulating allocation tags. |
| 4 | # Logical tags-related commands rely on local operations, hence don't exercise |
| 5 | # any stub and so are not used in this test. |
| 6 | # |
| 7 | # The test consists in breaking just after a tag is set in a specific memory |
| 8 | # chunk, and then using the GDB 'memory-tagging' subcommands to set/get tags in |
| 9 | # different memory locations and ranges in the MTE-enabled memory chunk. |
| 10 | # |
| 11 | # This is launched via tests/guest-debug/run-test.py |
| 12 | # |
| 13 | |
| 14 | |
| 15 | try: |
| 16 | import gdb |
| 17 | except ModuleNotFoundError: |
| 18 | from sys import exit |
| 19 | exit("This script must be launched via tests/guest-debug/run-test.py!") |
| 20 | import re |
| 21 | from sys import argv |
| 22 | from test_gdbstub import arg_parser, main, report |
| 23 | |
| 24 | |
| 25 | PATTERN_0 = r"Memory tags for address 0x[0-9a-f]+ match \(0x[0-9a-f]+\)." |
| 26 | PATTERN_1 = r".*(0x[0-9a-f]+)" |
| 27 | |
| 28 | |
| 29 | def run_test(): |
| 30 | p = arg_parser(prog="test-mte.py", description="TCG MTE tests.") |
| 31 | p.add_argument("--mode", help="Run test for QEMU system or user mode.", |
| 32 | required=True, choices=['system','user']) |
| 33 | |
| 34 | args = p.parse_args(args=argv) |
| 35 | |
| 36 | if args.mode == "system": |
| 37 | # Break address: where to break before performing the tests |
| 38 | # See mte.S for details about this label. |
| 39 | ba = "main_end" |
| 40 | # Tagged address: the start of the MTE-enabled memory chunk to be tested |
| 41 | # 'tagged_addr' (x1) is a pointer to the MTE-enabled page. See mte.S. |
| 42 | ta = "$x1" |
| 43 | else: # mode="user" |
| 44 | # Line 95 in mte-8.c |
| 45 | ba = "95" |
| 46 | # 'a' array. See mte-8.c |
| 47 | ta = "a" |
| 48 | |
| 49 | gdb.execute(f"break {ba}", False, True) |
| 50 | gdb.execute("continue", False, True) |
| 51 | |
| 52 | try: |
| 53 | # Test if we can check correctly that the allocation tag for the address |
| 54 | # in {ta} matches the logical tag in {ta}. |
| 55 | co = gdb.execute(f"memory-tag check {ta}", False, True) |
| 56 | tags_match = re.findall(PATTERN_0, co, re.MULTILINE) |
| 57 | if tags_match: |
| 58 | report(True, f"{tags_match[0]}") |
| 59 | else: |
| 60 | report(False, "Logical and allocation tags don't match!") |
| 61 | |
| 62 | # Test allocation tag 'set and print' commands. Commands on logical |
| 63 | # tags rely on local operation and so don't exercise any stub. |
| 64 | |
| 65 | # Set the allocation tag for the first granule (16 bytes) of |
| 66 | # address starting at {ta} address to a known value, i.e. 0x04. |
| 67 | gdb.execute(f"memory-tag set-allocation-tag {ta} 1 04", False, True) |
| 68 | |
| 69 | # Then set the allocation tag for the second granule to a known |
| 70 | # value, i.e. 0x06. This tests that contiguous tag granules are |
| 71 | # set correctly and don't run over each other. |
| 72 | gdb.execute(f"memory-tag set-allocation-tag {ta}+16 1 06", False, True) |
| 73 | |
| 74 | # Read the known values back and check if they remain the same. |
| 75 | |
| 76 | co = gdb.execute(f"memory-tag print-allocation-tag {ta}", False, True) |
| 77 | first_tag = re.match(PATTERN_1, co)[1] |
| 78 | |
| 79 | co = gdb.execute(f"memory-tag print-allocation-tag {ta}+16", False, True) |
| 80 | second_tag = re.match(PATTERN_1, co)[1] |
| 81 | |
| 82 | if first_tag == "0x4" and second_tag == "0x6": |
| 83 | report(True, "Allocation tags are correctly set/printed.") |
| 84 | else: |
| 85 | report(False, "Can't set/print allocation tags!") |
| 86 | |
| 87 | # Now test fill pattern by setting a whole page with a pattern. |
| 88 | gdb.execute(f"memory-tag set-allocation-tag {ta} 4096 0a0b", False, True) |
| 89 | |
| 90 | # And read back the tags of the last two granules in page so |
| 91 | # we also test if the pattern is set correctly up to the end of |
| 92 | # the page. |
| 93 | co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-32", False, True) |
| 94 | tag = re.match(PATTERN_1, co)[1] |
| 95 | |
| 96 | co = gdb.execute(f"memory-tag print-allocation-tag {ta}+4096-16", False, True) |
| 97 | last_tag = re.match(PATTERN_1, co)[1] |
| 98 | |
| 99 | if tag == "0xa" and last_tag == "0xb": |
| 100 | report(True, "Fill pattern is ok.") |
| 101 | else: |
| 102 | report(False, "Fill pattern failed!") |
| 103 | |
| 104 | except gdb.error: |
| 105 | # This usually happens because a GDB version that does not support |
| 106 | # memory tagging was used to run the test. |
| 107 | report(False, "'memory-tag' command failed!") |
| 108 | |
| 109 | |
| 110 | main(run_test, expected_arch="aarch64") |