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 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 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 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 97 static void test1(void) 98 { 99 *BADADDR = 'x'; 100 } 101 102 static void test2() 103 { 104 mapping[0] = 'x'; 105 } 106 107 static void test3() 108 { 109 mapping[FILESIZE+10]; 110 } 111 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 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 170 static int zero() 171 { 172 return 0; 173 } 174