162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * 32-bit syscall ABI conformance test.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2015 Denys Vlasenko
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci/*
862306a36Sopenharmony_ci * Can be built statically:
962306a36Sopenharmony_ci * gcc -Os -Wall -static -m32 test_syscall_vdso.c thunks_32.S
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#undef _GNU_SOURCE
1262306a36Sopenharmony_ci#define _GNU_SOURCE 1
1362306a36Sopenharmony_ci#undef __USE_GNU
1462306a36Sopenharmony_ci#define __USE_GNU 1
1562306a36Sopenharmony_ci#include <unistd.h>
1662306a36Sopenharmony_ci#include <stdlib.h>
1762306a36Sopenharmony_ci#include <string.h>
1862306a36Sopenharmony_ci#include <stdio.h>
1962306a36Sopenharmony_ci#include <signal.h>
2062306a36Sopenharmony_ci#include <sys/types.h>
2162306a36Sopenharmony_ci#include <sys/select.h>
2262306a36Sopenharmony_ci#include <sys/time.h>
2362306a36Sopenharmony_ci#include <elf.h>
2462306a36Sopenharmony_ci#include <sys/ptrace.h>
2562306a36Sopenharmony_ci#include <sys/wait.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#if !defined(__i386__)
2862306a36Sopenharmony_ciint main(int argc, char **argv, char **envp)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	printf("[SKIP]\tNot a 32-bit x86 userspace\n");
3162306a36Sopenharmony_ci	return 0;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci#else
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cilong syscall_addr;
3662306a36Sopenharmony_cilong get_syscall(char **envp)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	Elf32_auxv_t *auxv;
3962306a36Sopenharmony_ci	while (*envp++ != NULL)
4062306a36Sopenharmony_ci		continue;
4162306a36Sopenharmony_ci	for (auxv = (void *)envp; auxv->a_type != AT_NULL; auxv++)
4262306a36Sopenharmony_ci		if (auxv->a_type == AT_SYSINFO)
4362306a36Sopenharmony_ci			return auxv->a_un.a_val;
4462306a36Sopenharmony_ci	printf("[WARN]\tAT_SYSINFO not supplied\n");
4562306a36Sopenharmony_ci	return 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciasm (
4962306a36Sopenharmony_ci	"	.pushsection .text\n"
5062306a36Sopenharmony_ci	"	.global	int80\n"
5162306a36Sopenharmony_ci	"int80:\n"
5262306a36Sopenharmony_ci	"	int	$0x80\n"
5362306a36Sopenharmony_ci	"	ret\n"
5462306a36Sopenharmony_ci	"	.popsection\n"
5562306a36Sopenharmony_ci);
5662306a36Sopenharmony_ciextern char int80;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct regs64 {
5962306a36Sopenharmony_ci	uint64_t rax, rbx, rcx, rdx;
6062306a36Sopenharmony_ci	uint64_t rsi, rdi, rbp, rsp;
6162306a36Sopenharmony_ci	uint64_t r8,  r9,  r10, r11;
6262306a36Sopenharmony_ci	uint64_t r12, r13, r14, r15;
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_cistruct regs64 regs64;
6562306a36Sopenharmony_ciint kernel_is_64bit;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciasm (
6862306a36Sopenharmony_ci	"	.pushsection .text\n"
6962306a36Sopenharmony_ci	"	.code64\n"
7062306a36Sopenharmony_ci	"get_regs64:\n"
7162306a36Sopenharmony_ci	"	push	%rax\n"
7262306a36Sopenharmony_ci	"	mov	$regs64, %eax\n"
7362306a36Sopenharmony_ci	"	pop	0*8(%rax)\n"
7462306a36Sopenharmony_ci	"	movq	%rbx, 1*8(%rax)\n"
7562306a36Sopenharmony_ci	"	movq	%rcx, 2*8(%rax)\n"
7662306a36Sopenharmony_ci	"	movq	%rdx, 3*8(%rax)\n"
7762306a36Sopenharmony_ci	"	movq	%rsi, 4*8(%rax)\n"
7862306a36Sopenharmony_ci	"	movq	%rdi, 5*8(%rax)\n"
7962306a36Sopenharmony_ci	"	movq	%rbp, 6*8(%rax)\n"
8062306a36Sopenharmony_ci	"	movq	%rsp, 7*8(%rax)\n"
8162306a36Sopenharmony_ci	"	movq	%r8,  8*8(%rax)\n"
8262306a36Sopenharmony_ci	"	movq	%r9,  9*8(%rax)\n"
8362306a36Sopenharmony_ci	"	movq	%r10, 10*8(%rax)\n"
8462306a36Sopenharmony_ci	"	movq	%r11, 11*8(%rax)\n"
8562306a36Sopenharmony_ci	"	movq	%r12, 12*8(%rax)\n"
8662306a36Sopenharmony_ci	"	movq	%r13, 13*8(%rax)\n"
8762306a36Sopenharmony_ci	"	movq	%r14, 14*8(%rax)\n"
8862306a36Sopenharmony_ci	"	movq	%r15, 15*8(%rax)\n"
8962306a36Sopenharmony_ci	"	ret\n"
9062306a36Sopenharmony_ci	"poison_regs64:\n"
9162306a36Sopenharmony_ci	"	movq	$0x7f7f7f7f, %r8\n"
9262306a36Sopenharmony_ci	"	shl	$32, %r8\n"
9362306a36Sopenharmony_ci	"	orq	$0x7f7f7f7f, %r8\n"
9462306a36Sopenharmony_ci	"	movq	%r8, %r9\n"
9562306a36Sopenharmony_ci	"	incq	%r9\n"
9662306a36Sopenharmony_ci	"	movq	%r9, %r10\n"
9762306a36Sopenharmony_ci	"	incq	%r10\n"
9862306a36Sopenharmony_ci	"	movq	%r10, %r11\n"
9962306a36Sopenharmony_ci	"	incq	%r11\n"
10062306a36Sopenharmony_ci	"	movq	%r11, %r12\n"
10162306a36Sopenharmony_ci	"	incq	%r12\n"
10262306a36Sopenharmony_ci	"	movq	%r12, %r13\n"
10362306a36Sopenharmony_ci	"	incq	%r13\n"
10462306a36Sopenharmony_ci	"	movq	%r13, %r14\n"
10562306a36Sopenharmony_ci	"	incq	%r14\n"
10662306a36Sopenharmony_ci	"	movq	%r14, %r15\n"
10762306a36Sopenharmony_ci	"	incq	%r15\n"
10862306a36Sopenharmony_ci	"	ret\n"
10962306a36Sopenharmony_ci	"	.code32\n"
11062306a36Sopenharmony_ci	"	.popsection\n"
11162306a36Sopenharmony_ci);
11262306a36Sopenharmony_ciextern void get_regs64(void);
11362306a36Sopenharmony_ciextern void poison_regs64(void);
11462306a36Sopenharmony_ciextern unsigned long call64_from_32(void (*function)(void));
11562306a36Sopenharmony_civoid print_regs64(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	if (!kernel_is_64bit)
11862306a36Sopenharmony_ci		return;
11962306a36Sopenharmony_ci	printf("ax:%016llx bx:%016llx cx:%016llx dx:%016llx\n", regs64.rax,  regs64.rbx,  regs64.rcx,  regs64.rdx);
12062306a36Sopenharmony_ci	printf("si:%016llx di:%016llx bp:%016llx sp:%016llx\n", regs64.rsi,  regs64.rdi,  regs64.rbp,  regs64.rsp);
12162306a36Sopenharmony_ci	printf(" 8:%016llx  9:%016llx 10:%016llx 11:%016llx\n", regs64.r8 ,  regs64.r9 ,  regs64.r10,  regs64.r11);
12262306a36Sopenharmony_ci	printf("12:%016llx 13:%016llx 14:%016llx 15:%016llx\n", regs64.r12,  regs64.r13,  regs64.r14,  regs64.r15);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciint check_regs64(void)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int err = 0;
12862306a36Sopenharmony_ci	int num = 8;
12962306a36Sopenharmony_ci	uint64_t *r64 = &regs64.r8;
13062306a36Sopenharmony_ci	uint64_t expected = 0x7f7f7f7f7f7f7f7fULL;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (!kernel_is_64bit)
13362306a36Sopenharmony_ci		return 0;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	do {
13662306a36Sopenharmony_ci		if (*r64 == expected++)
13762306a36Sopenharmony_ci			continue; /* register did not change */
13862306a36Sopenharmony_ci		if (syscall_addr != (long)&int80) {
13962306a36Sopenharmony_ci			/*
14062306a36Sopenharmony_ci			 * Non-INT80 syscall entrypoints are allowed to clobber R8+ regs:
14162306a36Sopenharmony_ci			 * either clear them to 0, or for R11, load EFLAGS.
14262306a36Sopenharmony_ci			 */
14362306a36Sopenharmony_ci			if (*r64 == 0)
14462306a36Sopenharmony_ci				continue;
14562306a36Sopenharmony_ci			if (num == 11) {
14662306a36Sopenharmony_ci				printf("[NOTE]\tR11 has changed:%016llx - assuming clobbered by SYSRET insn\n", *r64);
14762306a36Sopenharmony_ci				continue;
14862306a36Sopenharmony_ci			}
14962306a36Sopenharmony_ci		} else {
15062306a36Sopenharmony_ci			/*
15162306a36Sopenharmony_ci			 * INT80 syscall entrypoint can be used by
15262306a36Sopenharmony_ci			 * 64-bit programs too, unlike SYSCALL/SYSENTER.
15362306a36Sopenharmony_ci			 * Therefore it must preserve R12+
15462306a36Sopenharmony_ci			 * (they are callee-saved registers in 64-bit C ABI).
15562306a36Sopenharmony_ci			 *
15662306a36Sopenharmony_ci			 * Starting in Linux 4.17 (and any kernel that
15762306a36Sopenharmony_ci			 * backports the change), R8..11 are preserved.
15862306a36Sopenharmony_ci			 * Historically (and probably unintentionally), they
15962306a36Sopenharmony_ci			 * were clobbered or zeroed.
16062306a36Sopenharmony_ci			 */
16162306a36Sopenharmony_ci		}
16262306a36Sopenharmony_ci		printf("[FAIL]\tR%d has changed:%016llx\n", num, *r64);
16362306a36Sopenharmony_ci		err++;
16462306a36Sopenharmony_ci	} while (r64++, ++num < 16);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	if (!err)
16762306a36Sopenharmony_ci		printf("[OK]\tR8..R15 did not leak kernel data\n");
16862306a36Sopenharmony_ci	return err;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ciint nfds;
17262306a36Sopenharmony_cifd_set rfds;
17362306a36Sopenharmony_cifd_set wfds;
17462306a36Sopenharmony_cifd_set efds;
17562306a36Sopenharmony_cistruct timespec timeout;
17662306a36Sopenharmony_cisigset_t sigmask;
17762306a36Sopenharmony_cistruct {
17862306a36Sopenharmony_ci	sigset_t *sp;
17962306a36Sopenharmony_ci	int sz;
18062306a36Sopenharmony_ci} sigmask_desc;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_civoid prep_args()
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	nfds = 42;
18562306a36Sopenharmony_ci	FD_ZERO(&rfds);
18662306a36Sopenharmony_ci	FD_ZERO(&wfds);
18762306a36Sopenharmony_ci	FD_ZERO(&efds);
18862306a36Sopenharmony_ci	FD_SET(0, &rfds);
18962306a36Sopenharmony_ci	FD_SET(1, &wfds);
19062306a36Sopenharmony_ci	FD_SET(2, &efds);
19162306a36Sopenharmony_ci	timeout.tv_sec = 0;
19262306a36Sopenharmony_ci	timeout.tv_nsec = 123;
19362306a36Sopenharmony_ci	sigemptyset(&sigmask);
19462306a36Sopenharmony_ci	sigaddset(&sigmask, SIGINT);
19562306a36Sopenharmony_ci	sigaddset(&sigmask, SIGUSR2);
19662306a36Sopenharmony_ci	sigaddset(&sigmask, SIGRTMAX);
19762306a36Sopenharmony_ci	sigmask_desc.sp = &sigmask;
19862306a36Sopenharmony_ci	sigmask_desc.sz = 8; /* bytes */
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_cistatic void print_flags(const char *name, unsigned long r)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	static const char *bitarray[] = {
20462306a36Sopenharmony_ci	"\n" ,"c\n" ,/* Carry Flag */
20562306a36Sopenharmony_ci	"0 " ,"1 "  ,/* Bit 1 - always on */
20662306a36Sopenharmony_ci	""   ,"p "  ,/* Parity Flag */
20762306a36Sopenharmony_ci	"0 " ,"3? " ,
20862306a36Sopenharmony_ci	""   ,"a "  ,/* Auxiliary carry Flag */
20962306a36Sopenharmony_ci	"0 " ,"5? " ,
21062306a36Sopenharmony_ci	""   ,"z "  ,/* Zero Flag */
21162306a36Sopenharmony_ci	""   ,"s "  ,/* Sign Flag */
21262306a36Sopenharmony_ci	""   ,"t "  ,/* Trap Flag */
21362306a36Sopenharmony_ci	""   ,"i "  ,/* Interrupt Flag */
21462306a36Sopenharmony_ci	""   ,"d "  ,/* Direction Flag */
21562306a36Sopenharmony_ci	""   ,"o "  ,/* Overflow Flag */
21662306a36Sopenharmony_ci	"0 " ,"1 "  ,/* I/O Privilege Level (2 bits) */
21762306a36Sopenharmony_ci	"0"  ,"1"   ,/* I/O Privilege Level (2 bits) */
21862306a36Sopenharmony_ci	""   ,"n "  ,/* Nested Task */
21962306a36Sopenharmony_ci	"0 " ,"15? ",
22062306a36Sopenharmony_ci	""   ,"r "  ,/* Resume Flag */
22162306a36Sopenharmony_ci	""   ,"v "  ,/* Virtual Mode */
22262306a36Sopenharmony_ci	""   ,"ac " ,/* Alignment Check/Access Control */
22362306a36Sopenharmony_ci	""   ,"vif ",/* Virtual Interrupt Flag */
22462306a36Sopenharmony_ci	""   ,"vip ",/* Virtual Interrupt Pending */
22562306a36Sopenharmony_ci	""   ,"id " ,/* CPUID detection */
22662306a36Sopenharmony_ci	NULL
22762306a36Sopenharmony_ci	};
22862306a36Sopenharmony_ci	const char **bitstr;
22962306a36Sopenharmony_ci	int bit;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	printf("%s=%016lx ", name, r);
23262306a36Sopenharmony_ci	bitstr = bitarray + 42;
23362306a36Sopenharmony_ci	bit = 21;
23462306a36Sopenharmony_ci	if ((r >> 22) != 0)
23562306a36Sopenharmony_ci		printf("(extra bits are set) ");
23662306a36Sopenharmony_ci	do {
23762306a36Sopenharmony_ci		if (bitstr[(r >> bit) & 1][0])
23862306a36Sopenharmony_ci			fputs(bitstr[(r >> bit) & 1], stdout);
23962306a36Sopenharmony_ci		bitstr -= 2;
24062306a36Sopenharmony_ci		bit--;
24162306a36Sopenharmony_ci	} while (bit >= 0);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ciint run_syscall(void)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	long flags, bad_arg;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	prep_args();
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (kernel_is_64bit)
25162306a36Sopenharmony_ci		call64_from_32(poison_regs64);
25262306a36Sopenharmony_ci	/*print_regs64();*/
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	asm("\n"
25562306a36Sopenharmony_ci	/* Try 6-arg syscall: pselect. It should return quickly */
25662306a36Sopenharmony_ci	"	push	%%ebp\n"
25762306a36Sopenharmony_ci	"	mov	$308, %%eax\n"     /* PSELECT */
25862306a36Sopenharmony_ci	"	mov	nfds, %%ebx\n"     /* ebx  arg1 */
25962306a36Sopenharmony_ci	"	mov	$rfds, %%ecx\n"    /* ecx  arg2 */
26062306a36Sopenharmony_ci	"	mov	$wfds, %%edx\n"    /* edx  arg3 */
26162306a36Sopenharmony_ci	"	mov	$efds, %%esi\n"    /* esi  arg4 */
26262306a36Sopenharmony_ci	"	mov	$timeout, %%edi\n" /* edi  arg5 */
26362306a36Sopenharmony_ci	"	mov	$sigmask_desc, %%ebp\n" /* %ebp arg6 */
26462306a36Sopenharmony_ci	"	push	$0x200ed7\n"      /* set almost all flags */
26562306a36Sopenharmony_ci	"	popf\n"		/* except TF, IOPL, NT, RF, VM, AC, VIF, VIP */
26662306a36Sopenharmony_ci	"	call	*syscall_addr\n"
26762306a36Sopenharmony_ci	/* Check that registers are not clobbered */
26862306a36Sopenharmony_ci	"	pushf\n"
26962306a36Sopenharmony_ci	"	pop	%%eax\n"
27062306a36Sopenharmony_ci	"	cld\n"
27162306a36Sopenharmony_ci	"	cmp	nfds, %%ebx\n"     /* ebx  arg1 */
27262306a36Sopenharmony_ci	"	mov	$1, %%ebx\n"
27362306a36Sopenharmony_ci	"	jne	1f\n"
27462306a36Sopenharmony_ci	"	cmp	$rfds, %%ecx\n"    /* ecx  arg2 */
27562306a36Sopenharmony_ci	"	mov	$2, %%ebx\n"
27662306a36Sopenharmony_ci	"	jne	1f\n"
27762306a36Sopenharmony_ci	"	cmp	$wfds, %%edx\n"    /* edx  arg3 */
27862306a36Sopenharmony_ci	"	mov	$3, %%ebx\n"
27962306a36Sopenharmony_ci	"	jne	1f\n"
28062306a36Sopenharmony_ci	"	cmp	$efds, %%esi\n"    /* esi  arg4 */
28162306a36Sopenharmony_ci	"	mov	$4, %%ebx\n"
28262306a36Sopenharmony_ci	"	jne	1f\n"
28362306a36Sopenharmony_ci	"	cmp	$timeout, %%edi\n" /* edi  arg5 */
28462306a36Sopenharmony_ci	"	mov	$5, %%ebx\n"
28562306a36Sopenharmony_ci	"	jne	1f\n"
28662306a36Sopenharmony_ci	"	cmpl	$sigmask_desc, %%ebp\n" /* %ebp arg6 */
28762306a36Sopenharmony_ci	"	mov	$6, %%ebx\n"
28862306a36Sopenharmony_ci	"	jne	1f\n"
28962306a36Sopenharmony_ci	"	mov	$0, %%ebx\n"
29062306a36Sopenharmony_ci	"1:\n"
29162306a36Sopenharmony_ci	"	pop	%%ebp\n"
29262306a36Sopenharmony_ci	: "=a" (flags), "=b" (bad_arg)
29362306a36Sopenharmony_ci	:
29462306a36Sopenharmony_ci	: "cx", "dx", "si", "di"
29562306a36Sopenharmony_ci	);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (kernel_is_64bit) {
29862306a36Sopenharmony_ci		memset(&regs64, 0x77, sizeof(regs64));
29962306a36Sopenharmony_ci		call64_from_32(get_regs64);
30062306a36Sopenharmony_ci		/*print_regs64();*/
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/*
30462306a36Sopenharmony_ci	 * On paravirt kernels, flags are not preserved across syscalls.
30562306a36Sopenharmony_ci	 * Thus, we do not consider it a bug if some are changed.
30662306a36Sopenharmony_ci	 * We just show ones which do.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	if ((0x200ed7 ^ flags) != 0) {
30962306a36Sopenharmony_ci		print_flags("[WARN]\tFlags before", 0x200ed7);
31062306a36Sopenharmony_ci		print_flags("[WARN]\tFlags  after", flags);
31162306a36Sopenharmony_ci		print_flags("[WARN]\tFlags change", (0x200ed7 ^ flags));
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (bad_arg) {
31562306a36Sopenharmony_ci		printf("[FAIL]\targ#%ld clobbered\n", bad_arg);
31662306a36Sopenharmony_ci		return 1;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci	printf("[OK]\tArguments are preserved across syscall\n");
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return check_regs64();
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ciint run_syscall_twice()
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int exitcode = 0;
32662306a36Sopenharmony_ci	long sv;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (syscall_addr) {
32962306a36Sopenharmony_ci		printf("[RUN]\tExecuting 6-argument 32-bit syscall via VDSO\n");
33062306a36Sopenharmony_ci		exitcode = run_syscall();
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	sv = syscall_addr;
33362306a36Sopenharmony_ci	syscall_addr = (long)&int80;
33462306a36Sopenharmony_ci	printf("[RUN]\tExecuting 6-argument 32-bit syscall via INT 80\n");
33562306a36Sopenharmony_ci	exitcode += run_syscall();
33662306a36Sopenharmony_ci	syscall_addr = sv;
33762306a36Sopenharmony_ci	return exitcode;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid ptrace_me()
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	pid_t pid;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	fflush(NULL);
34562306a36Sopenharmony_ci	pid = fork();
34662306a36Sopenharmony_ci	if (pid < 0)
34762306a36Sopenharmony_ci		exit(1);
34862306a36Sopenharmony_ci	if (pid == 0) {
34962306a36Sopenharmony_ci		/* child */
35062306a36Sopenharmony_ci		if (ptrace(PTRACE_TRACEME, 0L, 0L, 0L) != 0)
35162306a36Sopenharmony_ci			exit(0);
35262306a36Sopenharmony_ci		raise(SIGSTOP);
35362306a36Sopenharmony_ci		return;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	/* parent */
35662306a36Sopenharmony_ci	printf("[RUN]\tRunning tests under ptrace\n");
35762306a36Sopenharmony_ci	while (1) {
35862306a36Sopenharmony_ci		int status;
35962306a36Sopenharmony_ci		pid = waitpid(-1, &status, __WALL);
36062306a36Sopenharmony_ci		if (WIFEXITED(status))
36162306a36Sopenharmony_ci			exit(WEXITSTATUS(status));
36262306a36Sopenharmony_ci		if (WIFSIGNALED(status))
36362306a36Sopenharmony_ci			exit(WTERMSIG(status));
36462306a36Sopenharmony_ci		if (pid <= 0 || !WIFSTOPPED(status)) /* paranoia */
36562306a36Sopenharmony_ci			exit(255);
36662306a36Sopenharmony_ci		/*
36762306a36Sopenharmony_ci		 * Note: we do not inject sig = WSTOPSIG(status).
36862306a36Sopenharmony_ci		 * We probably should, but careful: do not inject SIGTRAP
36962306a36Sopenharmony_ci		 * generated by syscall entry/exit stops.
37062306a36Sopenharmony_ci		 * That kills the child.
37162306a36Sopenharmony_ci		 */
37262306a36Sopenharmony_ci		ptrace(PTRACE_SYSCALL, pid, 0L, 0L /*sig*/);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ciint main(int argc, char **argv, char **envp)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	int exitcode = 0;
37962306a36Sopenharmony_ci	int cs;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	asm("\n"
38262306a36Sopenharmony_ci	"	movl	%%cs, %%eax\n"
38362306a36Sopenharmony_ci	: "=a" (cs)
38462306a36Sopenharmony_ci	);
38562306a36Sopenharmony_ci	kernel_is_64bit = (cs == 0x23);
38662306a36Sopenharmony_ci	if (!kernel_is_64bit)
38762306a36Sopenharmony_ci		printf("[NOTE]\tNot a 64-bit kernel, won't test R8..R15 leaks\n");
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* This only works for non-static builds:
39062306a36Sopenharmony_ci	 * syscall_addr = dlsym(dlopen("linux-gate.so.1", RTLD_NOW), "__kernel_vsyscall");
39162306a36Sopenharmony_ci	 */
39262306a36Sopenharmony_ci	syscall_addr = get_syscall(envp);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	exitcode += run_syscall_twice();
39562306a36Sopenharmony_ci	ptrace_me();
39662306a36Sopenharmony_ci	exitcode += run_syscall_twice();
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	return exitcode;
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci#endif
401