faultstatus.c revision 9bea4c13fca0e3bb4b719dcb3ed63d47d479294e
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 (16*1024) 49#define MAPSIZE (2*FILESIZE) 50 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 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 81static 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 97static void test1(void) 98{ 99 *BADADDR = 'x'; 100} 101 102static void test2() 103{ 104 mapping[0] = 'x'; 105} 106 107static void test3() 108{ 109 mapping[FILESIZE+10]; 110} 111 112static 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 122int 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 170static int zero() 171{ 172 return 0; 173} 174