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

source code of lldb/test/API/linux/aarch64/mte_core_file/main.c