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__) || defined(__aarch64__) 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 /* Accessing non-mapped virtual address results in SIGBUS 33 * with si_code equal to BUS_ADRERR on Linux, whereas in SIGBUS 34 * with si_code equal to BUS_OBJERR on Solaris. On Solaris, 35 * BUS_ADRERR is used for bus time out while BUS_OBJERR is translated 36 * from underlying codes FC_OBJERR (x86) or ASYNC_BERR (sparc). 37 */ 38 #if defined(VGO_solaris) 39 # define BUS_ERROR_SI_CODE BUS_OBJERR 40 #else 41 # define BUS_ERROR_SI_CODE BUS_ADRERR 42 #endif 43 44 struct test { 45 void (*test)(void); 46 int sig; 47 int code; 48 volatile void *addr; 49 }; 50 51 static const struct test *cur_test; 52 53 static int zero(); 54 55 static sigjmp_buf escape; 56 57 #define BADADDR ((int *)0x1234) 58 59 #define FILESIZE (4*__pagesize) 60 #define MAPSIZE (2*FILESIZE) 61 static unsigned int __pagesize; 62 static char volatile *volatile mapping; 63 64 static int testsig(int sig, int want) 65 { 66 if (sig != want) { 67 fprintf(stderr, " FAIL: expected signal %d, not %d\n", want, sig); 68 return 0; 69 } 70 return 1; 71 } 72 73 static int testcode(int code, int want) 74 { 75 if (code != want) { 76 fprintf(stderr, " FAIL: expected si_code==%d, not %d\n", want, code); 77 return 0; 78 } 79 return 1; 80 } 81 82 static int testaddr(void *addr, volatile void *want) 83 { 84 /* Some architectures (e.g. s390) just provide enough information to 85 resolve the page fault, but do not provide the offset within a page */ 86 #if defined(__s390__) 87 if (addr != (void *) ((unsigned long) want & ~0xffful)) { 88 #else 89 if (addr != want) { 90 #endif 91 fprintf(stderr, " FAIL: expected si_addr==%p, not %p\n", want, addr); 92 return 0; 93 } 94 return 1; 95 96 } 97 98 static void handler(int sig, siginfo_t *si, void *uc) 99 { 100 int ok = 1; 101 102 ok = ok && testsig(sig, cur_test->sig); 103 ok = ok && testcode(si->si_code, cur_test->code); 104 if (cur_test->addr) 105 ok = ok && testaddr(si->si_addr, cur_test->addr); 106 107 if (ok) 108 fprintf(stderr, " PASS\n"); 109 110 siglongjmp(escape, ok + 1); 111 } 112 113 114 static void test1(void) 115 { 116 *BADADDR = 'x'; 117 } 118 119 static void test2() 120 { 121 mapping[0] = 'x'; 122 } 123 124 static void test3() 125 { 126 mapping[FILESIZE+10]; 127 } 128 129 static void test4() 130 { 131 volatile int v = 44/zero(); 132 133 (void)v; 134 #if DIVISION_BY_ZERO_TRIGGERS_FPE == 0 135 raise(SIGFPE); 136 #endif 137 } 138 139 int main() 140 { 141 int fd, i; 142 static const int sigs[] = { SIGSEGV, SIGILL, SIGBUS, SIGFPE, SIGTRAP }; 143 struct sigaction sa; 144 __pagesize = (unsigned int)sysconf(_SC_PAGE_SIZE); 145 sa.sa_sigaction = handler; 146 sa.sa_flags = SA_SIGINFO; 147 sigfillset(&sa.sa_mask); 148 149 for(i = 0; i < sizeof(sigs)/sizeof(*sigs); i++) 150 sigaction(sigs[i], &sa, NULL); 151 152 /* we need O_RDWR for the truncate below */ 153 fd = open("faultstatus.tmp", O_CREAT|O_TRUNC|O_EXCL|O_RDWR, 0600); 154 if (fd == -1) { 155 perror("tmpfile"); 156 exit(1); 157 } 158 unlink("faultstatus.tmp"); 159 ftruncate(fd, FILESIZE); 160 161 mapping = mmap(0, MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0); 162 close(fd); 163 164 { 165 const struct test tests[] = { 166 #define T(n, sig, code, addr) { test##n, sig, code, addr } 167 T(1, SIGSEGV, SEGV_MAPERR, BADADDR), 168 T(2, SIGSEGV, SEGV_ACCERR, mapping), 169 T(3, SIGBUS, BUS_ERROR_SI_CODE, &mapping[FILESIZE+10]), 170 T(4, SIGFPE, DIVISION_BY_ZERO_SI_CODE, 0), 171 #undef T 172 }; 173 174 for(i = 0; i < sizeof(tests)/sizeof(*tests); i++) { 175 cur_test = &tests[i]; 176 177 if (sigsetjmp(escape, 1) == 0) { 178 fprintf(stderr, "Test %d: ", i+1); 179 tests[i].test(); 180 fprintf(stderr, " FAIL: no fault, or handler returned\n"); 181 } 182 } 183 } 184 185 return 0; 186 } 187 188 static int zero() 189 { 190 return 0; 191 } 192