FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / none / tests / faultstatus.c
blobcdb1a80ba3287fb043553835f4557fbea9193ae2
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 #include "../../config.h"
13 /* Division by zero triggers a SIGFPE on x86 and x86_64,
14 but not on the PowerPC architecture.
16 On ARM-Linux, we do get a SIGFPE, but not from the faulting of a
17 division instruction (there isn't any such thing) but rather
18 because the process exits via tgkill, sending itself a SIGFPE.
19 Hence we get a SIGFPE but the SI_CODE is different from that on
20 x86/amd64-linux.
22 #if defined(__powerpc__) || defined(__aarch64__)
23 # define DIVISION_BY_ZERO_TRIGGERS_FPE 0
24 #if defined(VGO_freebsd)
25 # define DIVISION_BY_ZERO_SI_CODE SI_LWP
26 #else
27 # define DIVISION_BY_ZERO_SI_CODE SI_TKILL
28 #endif
29 #elif defined(__arm__)
30 # define DIVISION_BY_ZERO_TRIGGERS_FPE 1
31 # define DIVISION_BY_ZERO_SI_CODE SI_TKILL
32 #else
33 # define DIVISION_BY_ZERO_TRIGGERS_FPE 1
34 # define DIVISION_BY_ZERO_SI_CODE FPE_INTDIV
35 #endif
37 /* Accessing non-mapped virtual address results in SIGBUS
38 * with si_code equal to BUS_ADRERR on Linux, whereas in SIGBUS
39 * with si_code equal to BUS_OBJERR on Solaris. On Solaris,
40 * BUS_ADRERR is used for bus time out while BUS_OBJERR is translated
41 * from underlying codes FC_OBJERR (x86) or ASYNC_BERR (sparc).
43 #if defined(VGO_solaris) || (defined(VGO_freebsd) && (FREEBSD_VERS >= FREEBSD_12_2))
44 # define BUS_ERROR_SI_CODE BUS_OBJERR
45 #else
46 # define BUS_ERROR_SI_CODE BUS_ADRERR
47 #endif
49 struct test {
50 void (*test)(void);
51 int sig;
52 int code;
53 volatile void *addr;
56 static const struct test *cur_test;
58 static int zero();
60 static sigjmp_buf escape;
62 #define BADADDR ((int *)0x1234)
64 #define FILESIZE (4*__pagesize)
65 #define MAPSIZE (2*FILESIZE)
66 static unsigned int __pagesize;
67 static char volatile *volatile mapping;
69 static int testsig(int sig, int want)
71 if (sig != want) {
72 fprintf(stderr, " FAIL: expected signal %d, not %d\n", want, sig);
73 return 0;
75 return 1;
78 static int testcode(int code, int want)
80 if (code != want) {
81 fprintf(stderr, " FAIL: expected si_code==%d, not %d\n", want, code);
82 return 0;
84 return 1;
87 static int testaddr(void *addr, volatile void *want)
89 /* Some architectures (e.g. s390) just provide enough information to
90 resolve the page fault, but do not provide the offset within a page */
91 #if defined(__s390__)
92 if (addr != (void *) ((unsigned long) want & ~0xffful)) {
93 #else
94 if (addr != want) {
95 #endif
96 fprintf(stderr, " FAIL: expected si_addr==%p, not %p\n", want, addr);
97 return 0;
99 return 1;
103 static void handler(int sig, siginfo_t *si, void *uc)
105 int ok = 1;
107 ok = ok && testsig(sig, cur_test->sig);
108 ok = ok && testcode(si->si_code, cur_test->code);
109 if (cur_test->addr)
110 ok = ok && testaddr(si->si_addr, cur_test->addr);
112 if (ok)
113 fprintf(stderr, " PASS\n");
115 siglongjmp(escape, ok + 1);
119 static void test1(void)
121 *BADADDR = 'x';
124 static void test2()
126 mapping[0] = 'x';
129 static void test3()
131 mapping[FILESIZE+10];
134 static void test4()
136 volatile int v = 44/zero();
138 (void)v;
139 #if DIVISION_BY_ZERO_TRIGGERS_FPE == 0
140 raise(SIGFPE);
141 #endif
144 int main()
146 int fd, i;
147 static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP };
148 struct sigaction sa;
149 __pagesize = (unsigned int)sysconf(_SC_PAGE_SIZE);
150 sa.sa_sigaction = handler;
151 sa.sa_flags = SA_SIGINFO;
152 sigfillset(&sa.sa_mask);
154 for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++)
155 sigaction(sigs[i], &sa, NULL);
157 /* we need O_RDWR for the truncate below */
158 fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600);
159 if (fd == -1) {
160 perror("tmpfile");
161 exit(1);
163 unlink("faultstatus.tmp");
164 ftruncate(fd, FILESIZE);
166 mapping = mmap(0, MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0);
167 close(fd);
170 const struct test tests[] = {
171 #define T(n, sig, code, addr) { test##n, sig, code, addr }
172 T(1, SIGSEGV, SEGV_MAPERR, BADADDR),
173 T(2, SIGSEGV, SEGV_ACCERR, mapping),
174 #if defined(VGO_freebsd) && (FREEBSD_VERS < FREEBSD_12_2)
175 T(3, SIGSEGV, BUS_ERROR_SI_CODE, &mapping[FILESIZE+10]),
176 #else
177 T(3, SIGBUS, BUS_ERROR_SI_CODE, &mapping[FILESIZE+10]),
178 #endif
179 T(4, SIGFPE, DIVISION_BY_ZERO_SI_CODE, 0),
180 #undef T
183 for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) {
184 cur_test = &tests[i];
186 if (sigsetjmp(escape, 1) == 0) {
187 fprintf(stderr, "Test %d: ", i+1);
188 tests[i].test();
189 fprintf(stderr, " FAIL: no fault, or handler returned\n");
194 return 0;
197 static volatile int s_zero;
199 static int zero()
201 return s_zero;