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