• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "tests/sys_mman.h"
10 #include <unistd.h>
11 
12 /* Division by zero triggers a SIGFPE on x86 and x86_64,
13    but not on the PowerPC architecture.
14 
15    On ARM-Linux, we do get a SIGFPE, but not from the faulting of a
16    division instruction (there isn't any such thing) but rather
17    because the process exits via tgkill, sending itself a SIGFPE.
18    Hence we get a SIGFPE but the SI_CODE is different from that on
19    x86/amd64-linux.
20  */
21 #if defined(__powerpc__)
22 #  define DIVISION_BY_ZERO_TRIGGERS_FPE 0
23 #  define DIVISION_BY_ZERO_SI_CODE      SI_TKILL
24 #elif defined(__arm__)
25 #  define DIVISION_BY_ZERO_TRIGGERS_FPE 1
26 #  define DIVISION_BY_ZERO_SI_CODE      SI_TKILL
27 #else
28 #  define DIVISION_BY_ZERO_TRIGGERS_FPE 1
29 #  define DIVISION_BY_ZERO_SI_CODE      FPE_INTDIV
30 #endif
31 
32 
33 struct test {
34 	void (*test)(void);
35 	int sig;
36 	int code;
37 	volatile void *addr;
38 };
39 
40 static const struct test *cur_test;
41 
42 static int zero();
43 
44 static jmp_buf escape;
45 
46 #define BADADDR	((int *)0x1234)
47 
48 #define FILESIZE	(16*1024)
49 #define MAPSIZE		(2*FILESIZE)
50 
51 static char volatile *volatile mapping;
52 
testsig(int sig,int want)53 static int testsig(int sig, int want)
54 {
55 	if (sig != want) {
56 		fprintf(stderr, "  FAIL: expected signal %d, not %d\n", want, sig);
57 		return 0;
58 	}
59 	return 1;
60 }
61 
testcode(int code,int want)62 static int testcode(int code, int want)
63 {
64 	if (code != want) {
65 		fprintf(stderr, "  FAIL: expected si_code==%d, not %d\n", want, code);
66 		return 0;
67 	}
68 	return 1;
69 }
70 
testaddr(void * addr,volatile void * want)71 static int testaddr(void *addr, volatile void *want)
72 {
73 	if (addr != want) {
74 		fprintf(stderr, "  FAIL: expected si_addr==%p, not %p\n", want, addr);
75 		return 0;
76 	}
77 	return 1;
78 
79 }
80 
handler(int sig,siginfo_t * si,void * uc)81 static void handler(int sig, siginfo_t *si, void *uc)
82 {
83 	int ok = 1;
84 
85 	ok = ok && testsig(sig, cur_test->sig);
86 	ok = ok && testcode(si->si_code, cur_test->code);
87 	if (cur_test->addr)
88 		ok = ok && testaddr(si->si_addr, cur_test->addr);
89 
90 	if (ok)
91 		fprintf(stderr, "  PASS\n");
92 
93 	siglongjmp(escape, ok + 1);
94 }
95 
96 
test1(void)97 static void test1(void)
98 {
99 	*BADADDR = 'x';
100 }
101 
test2()102 static void test2()
103 {
104 	mapping[0] = 'x';
105 }
106 
test3()107 static void test3()
108 {
109 	mapping[FILESIZE+10];
110 }
111 
test4()112 static void test4()
113 {
114 	volatile int v = 44/zero();
115 
116 	(void)v;
117 #if DIVISION_BY_ZERO_TRIGGERS_FPE == 0
118 	raise(SIGFPE);
119 #endif
120 }
121 
main()122 int main()
123 {
124 	int fd, i;
125 	static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP };
126 	struct sigaction sa;
127 
128 	sa.sa_sigaction = handler;
129 	sa.sa_flags = SA_SIGINFO;
130 	sigfillset(&sa.sa_mask);
131 
132 	for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++)
133 		sigaction(sigs[i], &sa, NULL);
134 
135 	fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL, 0600);
136 	if (fd == -1) {
137 		perror("tmpfile");
138 		exit(1);
139 	}
140 	unlink("faultstatus.tmp");
141 	ftruncate(fd, FILESIZE);
142 
143 	mapping = mmap(0, MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0);
144 	close(fd);
145 
146 	{
147 		const struct test tests[] = {
148 #define T(n, sig, code, addr) { test##n, sig, code, addr }
149 			T(1, SIGSEGV,	SEGV_MAPERR,	BADADDR),
150 			T(2, SIGSEGV,	SEGV_ACCERR,	mapping),
151 			T(3, SIGBUS,	BUS_ADRERR,	&mapping[FILESIZE+10]),
152 			T(4, SIGFPE,    DIVISION_BY_ZERO_SI_CODE, 0),
153 #undef T
154 		};
155 
156 		for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
157 			cur_test = &tests[i];
158 
159 			if (sigsetjmp(escape, 1) == 0) {
160 				fprintf(stderr, "Test %d: ", i+1);
161 				tests[i].test();
162 				fprintf(stderr, "  FAIL: no fault, or handler returned\n");
163 			}
164 		}
165 	}
166 
167 	return 0;
168 }
169 
zero()170 static int zero()
171 {
172 	return 0;
173 }
174