Home | History | Annotate | Download | only in tests
      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