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 (4*__pagesize) 49 #define MAPSIZE (2*FILESIZE) 50 static unsigned int __pagesize; 51 static char volatile *volatile mapping; 52 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 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 71 static int testaddr(void *addr, volatile void *want) 72 { 73 /* Some architectures (e.g. s390) just provide enough information to 74 resolve the page fault, but do not provide the offset within a page */ 75 #if defined(__s390__) 76 if (addr != (void *) ((unsigned long) want & ~0xffful)) { 77 #else 78 if (addr != want) { 79 #endif 80 fprintf(stderr, " FAIL: expected si_addr==%p, not %p\n", want, addr); 81 return 0; 82 } 83 return 1; 84 85 } 86 87 static void handler(int sig, siginfo_t *si, void *uc) 88 { 89 int ok = 1; 90 91 ok = ok && testsig(sig, cur_test->sig); 92 ok = ok && testcode(si->si_code, cur_test->code); 93 if (cur_test->addr) 94 ok = ok && testaddr(si->si_addr, cur_test->addr); 95 96 if (ok) 97 fprintf(stderr, " PASS\n"); 98 99 siglongjmp(escape, ok + 1); 100 } 101 102 103 static void test1(void) 104 { 105 *BADADDR = 'x'; 106 } 107 108 static void test2() 109 { 110 mapping[0] = 'x'; 111 } 112 113 static void test3() 114 { 115 mapping[FILESIZE+10]; 116 } 117 118 static void test4() 119 { 120 volatile int v = 44/zero(); 121 122 (void)v; 123 #if DIVISION_BY_ZERO_TRIGGERS_FPE == 0 124 raise(SIGFPE); 125 #endif 126 } 127 128 int main() 129 { 130 int fd, i; 131 static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP }; 132 struct sigaction sa; 133 __pagesize = (unsigned int)sysconf(_SC_PAGE_SIZE); 134 sa.sa_sigaction = handler; 135 sa.sa_flags = SA_SIGINFO; 136 sigfillset(&sa.sa_mask); 137 138 for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++) 139 sigaction(sigs[i], &sa, NULL); 140 141 /* we need O_RDWR for the truncate below */ 142 fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600); 143 if (fd == -1) { 144 perror("tmpfile"); 145 exit(1); 146 } 147 unlink("faultstatus.tmp"); 148 ftruncate(fd, FILESIZE); 149 150 mapping = mmap(0, MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0); 151 close(fd); 152 153 { 154 const struct test tests[] = { 155 #define T(n, sig, code, addr) { test##n, sig, code, addr } 156 T(1, SIGSEGV, SEGV_MAPERR, BADADDR), 157 T(2, SIGSEGV, SEGV_ACCERR, mapping), 158 T(3, SIGBUS, BUS_ADRERR, &mapping[FILESIZE+10]), 159 T(4, SIGFPE, DIVISION_BY_ZERO_SI_CODE, 0), 160 #undef T 161 }; 162 163 for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) { 164 cur_test = &tests[i]; 165 166 if (sigsetjmp(escape, 1) == 0) { 167 fprintf(stderr, "Test %d: ", i+1); 168 tests[i].test(); 169 fprintf(stderr, " FAIL: no fault, or handler returned\n"); 170 } 171 } 172 } 173 174 return 0; 175 } 176 177 static int zero() 178 { 179 return 0; 180 } 181