xref: /llvm-project/lldb/test/API/linux/aarch64/mte_core_file/main.c (revision 2f9fa9ef5387de3d87b0c866c678d93695c1c1f3)
1 // Program to generate core files to test MTE tag features.
2 //
3 // This file uses ACLE intrinsics as detailed in:
4 // https://developer.arm.com/documentation/101028/0012/10--Memory-tagging-intrinsics?lang=en
5 //
6 // Compile with:
7 // <gcc or clang> -march=armv8.5-a+memtag -g main.c -o a.out.mte
8 // <gcc or clang> -march=armv8.5-a+memtag -g main.c -DNO_MTE -o a.out.nomte
9 //
10 // /proc/self/coredump_filter was set to 2 when the core files were made.
11 
12 #include <arm_acle.h>
13 #include <asm/mman.h>
14 #include <stdio.h>
15 #include <sys/mman.h>
16 #include <sys/prctl.h>
17 #include <unistd.h>
18 
main(int argc,char const * argv[])19 int main(int argc, char const *argv[]) {
20 #ifdef NO_MTE
21   *(char *)(0) = 0;
22 #endif
23 
24   if (prctl(PR_SET_TAGGED_ADDR_CTRL,
25             PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
26                 // Allow all tags to be generated by the addg
27                 // instruction __arm_mte_increment_tag produces.
28                 (0xffff << PR_MTE_TAG_SHIFT),
29             0, 0, 0)) {
30     return 1;
31   }
32 
33   size_t page_size = sysconf(_SC_PAGESIZE);
34   char *mte_buf = mmap(0, page_size, PROT_READ | PROT_WRITE | PROT_MTE,
35                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
36   if (!mte_buf)
37     return 1;
38 
39   printf("mte_buf: %p\n", mte_buf);
40 
41   // Allocate some untagged memory before the tagged memory.
42   char *buf = mmap(0, page_size, PROT_READ | PROT_WRITE,
43                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
44   if (!buf)
45     return 1;
46 
47   printf("buf: %p\n", buf);
48 
49   // This write means that the memory for buf is included in the corefile.
50   // So we can read from the end of it into mte_buf during the test.
51   *buf = 1;
52 
53   // These must be next to each other for the tests to work.
54   // <high address>
55   // mte_buf
56   // buf
57   // <low address>
58   if ((mte_buf - buf) != page_size) {
59     return 1;
60   }
61 
62   // Set incrementing tags until end of the page.
63   char *tagged_ptr = mte_buf;
64   // This ignores tag bits when subtracting the addresses.
65   while (__arm_mte_ptrdiff(tagged_ptr, mte_buf) < page_size) {
66     // Set the allocation tag for this location.
67     __arm_mte_set_tag(tagged_ptr);
68     // + 16 for 16 byte granules.
69     // Earlier we allowed all tag values, so this will give us an
70     // incrementing pattern 0-0xF wrapping back to 0.
71     tagged_ptr = __arm_mte_increment_tag(tagged_ptr + 16, 1);
72   }
73 
74   // Will fault because logical tag 0 != allocation tag 1.
75   *(mte_buf + 16) = 1;
76 
77   return 0;
78 }
79