// Program to generate core files to test MTE tag features.
//
// This file uses ACLE intrinsics as detailed in:
// https://developer.arm.com/documentation/101028/0012/10--Memory-tagging-intrinsics?lang=en
//
// Compile with:
// <gcc or clang> -march=armv8.5-a+memtag -g main.c -o a.out.mte
// <gcc or clang> -march=armv8.5-a+memtag -g main.c -DNO_MTE -o a.out.nomte
//
// /proc/self/coredump_filter was set to 2 when the core files were made.
#include <arm_acle.h>
#include <asm/mman.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
#ifdef NO_MTE
*(char *)(0) = 0;
#endif
if (prctl(PR_SET_TAGGED_ADDR_CTRL,
PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
// Allow all tags to be generated by the addg
// instruction __arm_mte_increment_tag produces.
(0xffff << PR_MTE_TAG_SHIFT),
0, 0, 0)) {
return 1;
}
size_t page_size = sysconf(_SC_PAGESIZE);
char *mte_buf = mmap(0, page_size, PROT_READ | PROT_WRITE | PROT_MTE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (!mte_buf)
return 1;
printf("mte_buf: %p\n", mte_buf);
// Allocate some untagged memory before the tagged memory.
char *buf = mmap(0, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (!buf)
return 1;
printf("buf: %p\n", buf);
// This write means that the memory for buf is included in the corefile.
// So we can read from the end of it into mte_buf during the test.
*buf = 1;
// These must be next to each other for the tests to work.
// <high address>
// mte_buf
// buf
// <low address>
if ((mte_buf - buf) != page_size) {
return 1;
}
// Set incrementing tags until end of the page.
char *tagged_ptr = mte_buf;
// This ignores tag bits when subtracting the addresses.
while (__arm_mte_ptrdiff(tagged_ptr, mte_buf) < page_size) {
// Set the allocation tag for this location.
__arm_mte_set_tag(tagged_ptr);
// + 16 for 16 byte granules.
// Earlier we allowed all tag values, so this will give us an
// incrementing pattern 0-0xF wrapping back to 0.
tagged_ptr = __arm_mte_increment_tag(tagged_ptr + 16, 1);
}
// Will fault because logical tag 0 != allocation tag 1.
*(mte_buf + 16) = 1;
return 0;
}