1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check that a fault signal handler gets the expected info
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <signal.h>
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <fcntl.h>
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <setjmp.h>
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "tests/asm.h"
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "tests/sys_mman.h"
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstruct test {
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	void (*test)(void);
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int sig;
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int code;
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	volatile void *addr;
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown};
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const struct test *cur_test;
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic jmp_buf escape;
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define BADADDR	((int *)0x1234)
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define FILESIZE	(16*1024)
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define MAPSIZE		(2*FILESIZE)
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic char volatile *volatile mapping;
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int testsig(int sig, int want)
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (sig != want) {
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		fprintf(stderr, "  FAIL: expected signal %d, not %d\n", want, sig);
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return 0;
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 1;
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int testcode(int code, int want)
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (code != want) {
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		fprintf(stderr, "  FAIL: expected si_code==%d, not %d\n", want, code);
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return 0;
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 1;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int testaddr(void *addr, volatile void *want)
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (addr != want) {
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		fprintf(stderr, "  FAIL: expected si_addr==%p, not %p\n", want, addr);
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		return 0;
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 1;
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void handler(int sig, siginfo_t *si, void *uc)
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int ok = 1;
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ok = ok && testsig(sig, cur_test->sig);
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ok = ok && testcode(si->si_code, cur_test->code);
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (cur_test->addr)
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		ok = ok && testaddr(si->si_addr, cur_test->addr);
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (ok)
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		fprintf(stderr, "  PASS\n");
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	siglongjmp(escape, ok + 1);
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern char test1_ill;
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void test1()
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	asm volatile(VG_SYM(test1_ill) ": ud2");
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void test2()
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	asm volatile ("int3");
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void test3()
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	asm volatile ("int $0x10");
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void test4()
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	volatile int a;
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	asm volatile ("add $1, %0;"/* set OF */
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      "into"
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		      : "=a" (a) : "0" (0x7fffffff) : "cc");
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void test5()
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	static int limit[2] = { 0, 10 };
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	asm volatile ("bound %0, %1" : : "r" (11), "m" (limit[0]));
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main()
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int fd, i;
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP };
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	struct sigaction sa;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	sa.sa_sigaction = handler;
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	sa.sa_flags = SA_SIGINFO;
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	sigfillset(&sa.sa_mask);
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++)
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		sigaction(sigs[i], &sa, NULL);
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL, 0600);
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (fd == -1) {
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		perror("tmpfile");
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		exit(1);
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	unlink("faultstatus.tmp");
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ftruncate(fd, FILESIZE);
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	mapping = mmap(0, MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0);
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	close(fd);
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	{
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		const struct test tests[] = {
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define T(n, sig, code, addr) { test##n, sig, code, addr }
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			T(1, SIGILL,	ILL_ILLOPN,     &test1_ill),
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			T(2, SIGTRAP,	128,		0), /* TRAP_BRKPT? */
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			T(3, SIGSEGV,	128,		0),
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			T(4, SIGSEGV,   128,		0),
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			/* This is an expected failure - Valgrind
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			   doesn't implement the BOUND instruction,
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			   and so issues a SIGILL instead. */
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			T(5, SIGSEGV,   128,		0),
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef T
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		};
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			cur_test = &tests[i];
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			if (sigsetjmp(escape, 1) == 0) {
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				fprintf(stderr, "Test %d: ", i+1);
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				tests[i].test();
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown				fprintf(stderr, "  FAIL: no fault, or handler returned\n");
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			}
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		}
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162