162306a36Sopenharmony_ci#if defined __amd64__ || defined __i386__
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2022 Alexey Dobriyan <adobriyan@gmail.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Create a process without mappings by unmapping everything at once and
1962306a36Sopenharmony_ci * holding it with ptrace(2). See what happens to
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci *	/proc/${pid}/maps
2262306a36Sopenharmony_ci *	/proc/${pid}/numa_maps
2362306a36Sopenharmony_ci *	/proc/${pid}/smaps
2462306a36Sopenharmony_ci *	/proc/${pid}/smaps_rollup
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci#undef NDEBUG
2762306a36Sopenharmony_ci#include <assert.h>
2862306a36Sopenharmony_ci#include <errno.h>
2962306a36Sopenharmony_ci#include <stdint.h>
3062306a36Sopenharmony_ci#include <stdio.h>
3162306a36Sopenharmony_ci#include <stdlib.h>
3262306a36Sopenharmony_ci#include <string.h>
3362306a36Sopenharmony_ci#include <fcntl.h>
3462306a36Sopenharmony_ci#include <sys/mman.h>
3562306a36Sopenharmony_ci#include <sys/ptrace.h>
3662306a36Sopenharmony_ci#include <sys/resource.h>
3762306a36Sopenharmony_ci#include <sys/types.h>
3862306a36Sopenharmony_ci#include <sys/wait.h>
3962306a36Sopenharmony_ci#include <unistd.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#ifdef __amd64__
4262306a36Sopenharmony_ci#define TEST_VSYSCALL
4362306a36Sopenharmony_ci#endif
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/*
4662306a36Sopenharmony_ci * 0: vsyscall VMA doesn't exist	vsyscall=none
4762306a36Sopenharmony_ci * 1: vsyscall VMA is --xp		vsyscall=xonly
4862306a36Sopenharmony_ci * 2: vsyscall VMA is r-xp		vsyscall=emulate
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_cistatic volatile int g_vsyscall;
5162306a36Sopenharmony_cistatic const char *g_proc_pid_maps_vsyscall;
5262306a36Sopenharmony_cistatic const char *g_proc_pid_smaps_vsyscall;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic const char proc_pid_maps_vsyscall_0[] = "";
5562306a36Sopenharmony_cistatic const char proc_pid_maps_vsyscall_1[] =
5662306a36Sopenharmony_ci"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]\n";
5762306a36Sopenharmony_cistatic const char proc_pid_maps_vsyscall_2[] =
5862306a36Sopenharmony_ci"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]\n";
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic const char proc_pid_smaps_vsyscall_0[] = "";
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic const char proc_pid_smaps_vsyscall_1[] =
6362306a36Sopenharmony_ci"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]\n"
6462306a36Sopenharmony_ci"Size:                  4 kB\n"
6562306a36Sopenharmony_ci"KernelPageSize:        4 kB\n"
6662306a36Sopenharmony_ci"MMUPageSize:           4 kB\n"
6762306a36Sopenharmony_ci"Rss:                   0 kB\n"
6862306a36Sopenharmony_ci"Pss:                   0 kB\n"
6962306a36Sopenharmony_ci"Pss_Dirty:             0 kB\n"
7062306a36Sopenharmony_ci"Shared_Clean:          0 kB\n"
7162306a36Sopenharmony_ci"Shared_Dirty:          0 kB\n"
7262306a36Sopenharmony_ci"Private_Clean:         0 kB\n"
7362306a36Sopenharmony_ci"Private_Dirty:         0 kB\n"
7462306a36Sopenharmony_ci"Referenced:            0 kB\n"
7562306a36Sopenharmony_ci"Anonymous:             0 kB\n"
7662306a36Sopenharmony_ci"LazyFree:              0 kB\n"
7762306a36Sopenharmony_ci"AnonHugePages:         0 kB\n"
7862306a36Sopenharmony_ci"ShmemPmdMapped:        0 kB\n"
7962306a36Sopenharmony_ci"FilePmdMapped:         0 kB\n"
8062306a36Sopenharmony_ci"Shared_Hugetlb:        0 kB\n"
8162306a36Sopenharmony_ci"Private_Hugetlb:       0 kB\n"
8262306a36Sopenharmony_ci"Swap:                  0 kB\n"
8362306a36Sopenharmony_ci"SwapPss:               0 kB\n"
8462306a36Sopenharmony_ci"Locked:                0 kB\n"
8562306a36Sopenharmony_ci"THPeligible:           0\n"
8662306a36Sopenharmony_ci/*
8762306a36Sopenharmony_ci * "ProtectionKey:" field is conditional. It is possible to check it as well,
8862306a36Sopenharmony_ci * but I don't have such machine.
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ci;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic const char proc_pid_smaps_vsyscall_2[] =
9362306a36Sopenharmony_ci"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]\n"
9462306a36Sopenharmony_ci"Size:                  4 kB\n"
9562306a36Sopenharmony_ci"KernelPageSize:        4 kB\n"
9662306a36Sopenharmony_ci"MMUPageSize:           4 kB\n"
9762306a36Sopenharmony_ci"Rss:                   0 kB\n"
9862306a36Sopenharmony_ci"Pss:                   0 kB\n"
9962306a36Sopenharmony_ci"Pss_Dirty:             0 kB\n"
10062306a36Sopenharmony_ci"Shared_Clean:          0 kB\n"
10162306a36Sopenharmony_ci"Shared_Dirty:          0 kB\n"
10262306a36Sopenharmony_ci"Private_Clean:         0 kB\n"
10362306a36Sopenharmony_ci"Private_Dirty:         0 kB\n"
10462306a36Sopenharmony_ci"Referenced:            0 kB\n"
10562306a36Sopenharmony_ci"Anonymous:             0 kB\n"
10662306a36Sopenharmony_ci"LazyFree:              0 kB\n"
10762306a36Sopenharmony_ci"AnonHugePages:         0 kB\n"
10862306a36Sopenharmony_ci"ShmemPmdMapped:        0 kB\n"
10962306a36Sopenharmony_ci"FilePmdMapped:         0 kB\n"
11062306a36Sopenharmony_ci"Shared_Hugetlb:        0 kB\n"
11162306a36Sopenharmony_ci"Private_Hugetlb:       0 kB\n"
11262306a36Sopenharmony_ci"Swap:                  0 kB\n"
11362306a36Sopenharmony_ci"SwapPss:               0 kB\n"
11462306a36Sopenharmony_ci"Locked:                0 kB\n"
11562306a36Sopenharmony_ci"THPeligible:           0\n"
11662306a36Sopenharmony_ci/*
11762306a36Sopenharmony_ci * "ProtectionKey:" field is conditional. It is possible to check it as well,
11862306a36Sopenharmony_ci * but I'm too tired.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_ci;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	_exit(EXIT_FAILURE);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#ifdef TEST_VSYSCALL
12862306a36Sopenharmony_cistatic void sigaction_SIGSEGV_vsyscall(int _, siginfo_t *__, void *___)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	_exit(g_vsyscall);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * vsyscall page can't be unmapped, probe it directly.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic void vsyscall(void)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	pid_t pid;
13962306a36Sopenharmony_ci	int wstatus;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	pid = fork();
14262306a36Sopenharmony_ci	if (pid < 0) {
14362306a36Sopenharmony_ci		fprintf(stderr, "fork, errno %d\n", errno);
14462306a36Sopenharmony_ci		exit(1);
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci	if (pid == 0) {
14762306a36Sopenharmony_ci		setrlimit(RLIMIT_CORE, &(struct rlimit){});
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci		/* Hide "segfault at ffffffffff600000" messages. */
15062306a36Sopenharmony_ci		struct sigaction act = {};
15162306a36Sopenharmony_ci		act.sa_flags = SA_SIGINFO;
15262306a36Sopenharmony_ci		act.sa_sigaction = sigaction_SIGSEGV_vsyscall;
15362306a36Sopenharmony_ci		sigaction(SIGSEGV, &act, NULL);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		g_vsyscall = 0;
15662306a36Sopenharmony_ci		/* gettimeofday(NULL, NULL); */
15762306a36Sopenharmony_ci		uint64_t rax = 0xffffffffff600000;
15862306a36Sopenharmony_ci		asm volatile (
15962306a36Sopenharmony_ci			"call *%[rax]"
16062306a36Sopenharmony_ci			: [rax] "+a" (rax)
16162306a36Sopenharmony_ci			: "D" (NULL), "S" (NULL)
16262306a36Sopenharmony_ci			: "rcx", "r11"
16362306a36Sopenharmony_ci		);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		g_vsyscall = 1;
16662306a36Sopenharmony_ci		*(volatile int *)0xffffffffff600000UL;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		g_vsyscall = 2;
16962306a36Sopenharmony_ci		exit(g_vsyscall);
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	waitpid(pid, &wstatus, 0);
17262306a36Sopenharmony_ci	if (WIFEXITED(wstatus)) {
17362306a36Sopenharmony_ci		g_vsyscall = WEXITSTATUS(wstatus);
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		fprintf(stderr, "error: vsyscall wstatus %08x\n", wstatus);
17662306a36Sopenharmony_ci		exit(1);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci#endif
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int test_proc_pid_maps(pid_t pid)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	char buf[4096];
18462306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "/proc/%u/maps", pid);
18562306a36Sopenharmony_ci	int fd = open(buf, O_RDONLY);
18662306a36Sopenharmony_ci	if (fd == -1) {
18762306a36Sopenharmony_ci		perror("open /proc/${pid}/maps");
18862306a36Sopenharmony_ci		return EXIT_FAILURE;
18962306a36Sopenharmony_ci	} else {
19062306a36Sopenharmony_ci		ssize_t rv = read(fd, buf, sizeof(buf));
19162306a36Sopenharmony_ci		close(fd);
19262306a36Sopenharmony_ci		if (g_vsyscall == 0) {
19362306a36Sopenharmony_ci			assert(rv == 0);
19462306a36Sopenharmony_ci		} else {
19562306a36Sopenharmony_ci			size_t len = strlen(g_proc_pid_maps_vsyscall);
19662306a36Sopenharmony_ci			assert(rv == len);
19762306a36Sopenharmony_ci			assert(memcmp(buf, g_proc_pid_maps_vsyscall, len) == 0);
19862306a36Sopenharmony_ci		}
19962306a36Sopenharmony_ci		return EXIT_SUCCESS;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int test_proc_pid_numa_maps(pid_t pid)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	char buf[4096];
20662306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "/proc/%u/numa_maps", pid);
20762306a36Sopenharmony_ci	int fd = open(buf, O_RDONLY);
20862306a36Sopenharmony_ci	if (fd == -1) {
20962306a36Sopenharmony_ci		if (errno == ENOENT) {
21062306a36Sopenharmony_ci			/*
21162306a36Sopenharmony_ci			 * /proc/${pid}/numa_maps is under CONFIG_NUMA,
21262306a36Sopenharmony_ci			 * it doesn't necessarily exist.
21362306a36Sopenharmony_ci			 */
21462306a36Sopenharmony_ci			return EXIT_SUCCESS;
21562306a36Sopenharmony_ci		}
21662306a36Sopenharmony_ci		perror("open /proc/${pid}/numa_maps");
21762306a36Sopenharmony_ci		return EXIT_FAILURE;
21862306a36Sopenharmony_ci	} else {
21962306a36Sopenharmony_ci		ssize_t rv = read(fd, buf, sizeof(buf));
22062306a36Sopenharmony_ci		close(fd);
22162306a36Sopenharmony_ci		assert(rv == 0);
22262306a36Sopenharmony_ci		return EXIT_SUCCESS;
22362306a36Sopenharmony_ci	}
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int test_proc_pid_smaps(pid_t pid)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	char buf[4096];
22962306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "/proc/%u/smaps", pid);
23062306a36Sopenharmony_ci	int fd = open(buf, O_RDONLY);
23162306a36Sopenharmony_ci	if (fd == -1) {
23262306a36Sopenharmony_ci		if (errno == ENOENT) {
23362306a36Sopenharmony_ci			/*
23462306a36Sopenharmony_ci			 * /proc/${pid}/smaps is under CONFIG_PROC_PAGE_MONITOR,
23562306a36Sopenharmony_ci			 * it doesn't necessarily exist.
23662306a36Sopenharmony_ci			 */
23762306a36Sopenharmony_ci			return EXIT_SUCCESS;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci		perror("open /proc/${pid}/smaps");
24062306a36Sopenharmony_ci		return EXIT_FAILURE;
24162306a36Sopenharmony_ci	} else {
24262306a36Sopenharmony_ci		ssize_t rv = read(fd, buf, sizeof(buf));
24362306a36Sopenharmony_ci		close(fd);
24462306a36Sopenharmony_ci		if (g_vsyscall == 0) {
24562306a36Sopenharmony_ci			assert(rv == 0);
24662306a36Sopenharmony_ci		} else {
24762306a36Sopenharmony_ci			size_t len = strlen(g_proc_pid_maps_vsyscall);
24862306a36Sopenharmony_ci			/* TODO "ProtectionKey:" */
24962306a36Sopenharmony_ci			assert(rv > len);
25062306a36Sopenharmony_ci			assert(memcmp(buf, g_proc_pid_maps_vsyscall, len) == 0);
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci		return EXIT_SUCCESS;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic const char g_smaps_rollup[] =
25762306a36Sopenharmony_ci"00000000-00000000 ---p 00000000 00:00 0                                  [rollup]\n"
25862306a36Sopenharmony_ci"Rss:                   0 kB\n"
25962306a36Sopenharmony_ci"Pss:                   0 kB\n"
26062306a36Sopenharmony_ci"Pss_Dirty:             0 kB\n"
26162306a36Sopenharmony_ci"Pss_Anon:              0 kB\n"
26262306a36Sopenharmony_ci"Pss_File:              0 kB\n"
26362306a36Sopenharmony_ci"Pss_Shmem:             0 kB\n"
26462306a36Sopenharmony_ci"Shared_Clean:          0 kB\n"
26562306a36Sopenharmony_ci"Shared_Dirty:          0 kB\n"
26662306a36Sopenharmony_ci"Private_Clean:         0 kB\n"
26762306a36Sopenharmony_ci"Private_Dirty:         0 kB\n"
26862306a36Sopenharmony_ci"Referenced:            0 kB\n"
26962306a36Sopenharmony_ci"Anonymous:             0 kB\n"
27062306a36Sopenharmony_ci"KSM:                   0 kB\n"
27162306a36Sopenharmony_ci"LazyFree:              0 kB\n"
27262306a36Sopenharmony_ci"AnonHugePages:         0 kB\n"
27362306a36Sopenharmony_ci"ShmemPmdMapped:        0 kB\n"
27462306a36Sopenharmony_ci"FilePmdMapped:         0 kB\n"
27562306a36Sopenharmony_ci"Shared_Hugetlb:        0 kB\n"
27662306a36Sopenharmony_ci"Private_Hugetlb:       0 kB\n"
27762306a36Sopenharmony_ci"Swap:                  0 kB\n"
27862306a36Sopenharmony_ci"SwapPss:               0 kB\n"
27962306a36Sopenharmony_ci"Locked:                0 kB\n"
28062306a36Sopenharmony_ci;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int test_proc_pid_smaps_rollup(pid_t pid)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	char buf[4096];
28562306a36Sopenharmony_ci	snprintf(buf, sizeof(buf), "/proc/%u/smaps_rollup", pid);
28662306a36Sopenharmony_ci	int fd = open(buf, O_RDONLY);
28762306a36Sopenharmony_ci	if (fd == -1) {
28862306a36Sopenharmony_ci		if (errno == ENOENT) {
28962306a36Sopenharmony_ci			/*
29062306a36Sopenharmony_ci			 * /proc/${pid}/smaps_rollup is under CONFIG_PROC_PAGE_MONITOR,
29162306a36Sopenharmony_ci			 * it doesn't necessarily exist.
29262306a36Sopenharmony_ci			 */
29362306a36Sopenharmony_ci			return EXIT_SUCCESS;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci		perror("open /proc/${pid}/smaps_rollup");
29662306a36Sopenharmony_ci		return EXIT_FAILURE;
29762306a36Sopenharmony_ci	} else {
29862306a36Sopenharmony_ci		ssize_t rv = read(fd, buf, sizeof(buf));
29962306a36Sopenharmony_ci		close(fd);
30062306a36Sopenharmony_ci		assert(rv == sizeof(g_smaps_rollup) - 1);
30162306a36Sopenharmony_ci		assert(memcmp(buf, g_smaps_rollup, sizeof(g_smaps_rollup) - 1) == 0);
30262306a36Sopenharmony_ci		return EXIT_SUCCESS;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ciint main(void)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	int rv = EXIT_SUCCESS;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci#ifdef TEST_VSYSCALL
31162306a36Sopenharmony_ci	vsyscall();
31262306a36Sopenharmony_ci#endif
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	switch (g_vsyscall) {
31562306a36Sopenharmony_ci	case 0:
31662306a36Sopenharmony_ci		g_proc_pid_maps_vsyscall  = proc_pid_maps_vsyscall_0;
31762306a36Sopenharmony_ci		g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_0;
31862306a36Sopenharmony_ci		break;
31962306a36Sopenharmony_ci	case 1:
32062306a36Sopenharmony_ci		g_proc_pid_maps_vsyscall  = proc_pid_maps_vsyscall_1;
32162306a36Sopenharmony_ci		g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_1;
32262306a36Sopenharmony_ci		break;
32362306a36Sopenharmony_ci	case 2:
32462306a36Sopenharmony_ci		g_proc_pid_maps_vsyscall  = proc_pid_maps_vsyscall_2;
32562306a36Sopenharmony_ci		g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_2;
32662306a36Sopenharmony_ci		break;
32762306a36Sopenharmony_ci	default:
32862306a36Sopenharmony_ci		abort();
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	pid_t pid = fork();
33262306a36Sopenharmony_ci	if (pid == -1) {
33362306a36Sopenharmony_ci		perror("fork");
33462306a36Sopenharmony_ci		return EXIT_FAILURE;
33562306a36Sopenharmony_ci	} else if (pid == 0) {
33662306a36Sopenharmony_ci		rv = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
33762306a36Sopenharmony_ci		if (rv != 0) {
33862306a36Sopenharmony_ci			if (errno == EPERM) {
33962306a36Sopenharmony_ci				fprintf(stderr,
34062306a36Sopenharmony_ci"Did you know? ptrace(PTRACE_TRACEME) doesn't work under strace.\n"
34162306a36Sopenharmony_ci				);
34262306a36Sopenharmony_ci				kill(getppid(), SIGTERM);
34362306a36Sopenharmony_ci				return EXIT_FAILURE;
34462306a36Sopenharmony_ci			}
34562306a36Sopenharmony_ci			perror("ptrace PTRACE_TRACEME");
34662306a36Sopenharmony_ci			return EXIT_FAILURE;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		/*
35062306a36Sopenharmony_ci		 * Hide "segfault at ..." messages. Signal handler won't run.
35162306a36Sopenharmony_ci		 */
35262306a36Sopenharmony_ci		struct sigaction act = {};
35362306a36Sopenharmony_ci		act.sa_flags = SA_SIGINFO;
35462306a36Sopenharmony_ci		act.sa_sigaction = sigaction_SIGSEGV;
35562306a36Sopenharmony_ci		sigaction(SIGSEGV, &act, NULL);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci#ifdef __amd64__
35862306a36Sopenharmony_ci		munmap(NULL, ((size_t)1 << 47) - 4096);
35962306a36Sopenharmony_ci#elif defined __i386__
36062306a36Sopenharmony_ci		{
36162306a36Sopenharmony_ci			size_t len;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci			for (len = -4096;; len -= 4096) {
36462306a36Sopenharmony_ci				munmap(NULL, len);
36562306a36Sopenharmony_ci			}
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci#else
36862306a36Sopenharmony_ci#error "implement 'unmap everything'"
36962306a36Sopenharmony_ci#endif
37062306a36Sopenharmony_ci		return EXIT_FAILURE;
37162306a36Sopenharmony_ci	} else {
37262306a36Sopenharmony_ci		/*
37362306a36Sopenharmony_ci		 * TODO find reliable way to signal parent that munmap(2) completed.
37462306a36Sopenharmony_ci		 * Child can't do it directly because it effectively doesn't exist
37562306a36Sopenharmony_ci		 * anymore. Looking at child's VM files isn't 100% reliable either:
37662306a36Sopenharmony_ci		 * due to a bug they may not become empty or empty-like.
37762306a36Sopenharmony_ci		 */
37862306a36Sopenharmony_ci		sleep(1);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		if (rv == EXIT_SUCCESS) {
38162306a36Sopenharmony_ci			rv = test_proc_pid_maps(pid);
38262306a36Sopenharmony_ci		}
38362306a36Sopenharmony_ci		if (rv == EXIT_SUCCESS) {
38462306a36Sopenharmony_ci			rv = test_proc_pid_numa_maps(pid);
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci		if (rv == EXIT_SUCCESS) {
38762306a36Sopenharmony_ci			rv = test_proc_pid_smaps(pid);
38862306a36Sopenharmony_ci		}
38962306a36Sopenharmony_ci		if (rv == EXIT_SUCCESS) {
39062306a36Sopenharmony_ci			rv = test_proc_pid_smaps_rollup(pid);
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci		/*
39362306a36Sopenharmony_ci		 * TODO test /proc/${pid}/statm, task_statm()
39462306a36Sopenharmony_ci		 * ->start_code, ->end_code aren't updated by munmap().
39562306a36Sopenharmony_ci		 * Output can be "0 0 0 2 0 0 0\n" where "2" can be anything.
39662306a36Sopenharmony_ci		 */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		/* Cut the rope. */
39962306a36Sopenharmony_ci		int wstatus;
40062306a36Sopenharmony_ci		waitpid(pid, &wstatus, 0);
40162306a36Sopenharmony_ci		assert(WIFSTOPPED(wstatus));
40262306a36Sopenharmony_ci		assert(WSTOPSIG(wstatus) == SIGSEGV);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return rv;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci#else
40862306a36Sopenharmony_ciint main(void)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	return 4;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci#endif
413