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 33struct test { 34 void (*test)(void); 35 int sig; 36 int code; 37 volatile void *addr; 38}; 39 40static const struct test *cur_test; 41 42static int zero(); 43 44static jmp_buf escape; 45 46#define BADADDR ((int *)0x1234) 47 48#define FILESIZE (4*__pagesize) 49#define MAPSIZE (2*FILESIZE) 50static unsigned int __pagesize; 51static char volatile *volatile mapping; 52 53static 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 62static 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 71static 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 87static 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 103static void test1(void) 104{ 105 *BADADDR = 'x'; 106} 107 108static void test2() 109{ 110 mapping[0] = 'x'; 111} 112 113static void test3() 114{ 115 mapping[FILESIZE+10]; 116} 117 118static 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 128int 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 177static int zero() 178{ 179 return 0; 180} 181