2 Check that a fault signal handler gets the expected info
9 #include "tests/sys_mman.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
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
27 # define DIVISION_BY_ZERO_SI_CODE SI_TKILL
29 #elif defined(__arm__)
30 # define DIVISION_BY_ZERO_TRIGGERS_FPE 1
31 # define DIVISION_BY_ZERO_SI_CODE SI_TKILL
33 # define DIVISION_BY_ZERO_TRIGGERS_FPE 1
34 # define DIVISION_BY_ZERO_SI_CODE FPE_INTDIV
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
46 # define BUS_ERROR_SI_CODE BUS_ADRERR
56 static const struct test
*cur_test
;
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
)
72 fprintf(stderr
, " FAIL: expected signal %d, not %d\n", want
, sig
);
78 static int testcode(int code
, int want
)
81 fprintf(stderr
, " FAIL: expected si_code==%d, not %d\n", want
, code
);
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 */
92 if (addr
!= (void *) ((unsigned long) want
& ~0xffful
)) {
96 fprintf(stderr
, " FAIL: expected si_addr==%p, not %p\n", want
, addr
);
103 static void handler(int sig
, siginfo_t
*si
, void *uc
)
107 ok
= ok
&& testsig(sig
, cur_test
->sig
);
108 ok
= ok
&& testcode(si
->si_code
, cur_test
->code
);
110 ok
= ok
&& testaddr(si
->si_addr
, cur_test
->addr
);
113 fprintf(stderr
, " PASS\n");
115 siglongjmp(escape
, ok
+ 1);
119 static void test1(void)
131 mapping
[FILESIZE
+10];
136 volatile int v
= 44/zero();
139 #if DIVISION_BY_ZERO_TRIGGERS_FPE == 0
147 static const int sigs
[] = { SIGSEGV
, SIGILL
, SIGBUS
, SIGFPE
, SIGTRAP
};
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);
163 unlink("faultstatus.tmp");
164 ftruncate(fd
, FILESIZE
);
166 mapping
= mmap(0, MAPSIZE
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
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]),
177 T(3, SIGBUS
, BUS_ERROR_SI_CODE
, &mapping
[FILESIZE
+10]),
179 T(4, SIGFPE
, DIVISION_BY_ZERO_SI_CODE
, 0),
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);
189 fprintf(stderr
, " FAIL: no fault, or handler returned\n");
197 static volatile int s_zero
;