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