sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 1 | /* Test if x87 FP valus are correctly propagated in and out of a signal |
| 2 | handler and also check that the same applies for uninitialised values and |
| 3 | their origins. */ |
| 4 | |
| 5 | #include <assert.h> |
| 6 | #include <signal.h> |
| 7 | #include <stdio.h> |
| 8 | #include <stdlib.h> |
| 9 | #include <unistd.h> |
| 10 | #include <sys/syscall.h> |
| 11 | #include <sys/ucontext.h> |
| 12 | |
| 13 | static siginfo_t si; |
| 14 | static ucontext_t uc; |
| 15 | static float inhandler[8]; |
| 16 | |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 17 | static void sighandler(int sig, siginfo_t *sip, void *arg) |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 18 | { |
| 19 | int i; |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 20 | ucontext_t *ucp = (ucontext_t *) arg; |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 21 | |
| 22 | si = *sip; |
| 23 | uc = *ucp; |
| 24 | |
| 25 | /* Reset the FP stack so it's possible to push other values onto it. (It |
| 26 | is fully filled in main() before triggering the signal handler). Note |
| 27 | that VEX also clears all FP values when the finit instruction is |
| 28 | executed. This provides another level of validation that the restore |
| 29 | code is correct. */ |
| 30 | __asm__ __volatile__( |
| 31 | "finit\n"); |
| 32 | |
| 33 | /* Convert 80b values in mcontext to 32b values in the inhandler array. */ |
| 34 | for (i = 0; i < 8; i++) { |
| 35 | __asm__ __volatile__( |
| 36 | "fldt %[in]\n" |
| 37 | "fstps %[out]\n" |
| 38 | : [out] "=m" (inhandler[i]) |
| 39 | : [in] "m" (*(char*)&ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st[i])); |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | int main(void) |
| 44 | { |
| 45 | struct sigaction sa; |
| 46 | pid_t pid; |
| 47 | float out[8]; |
| 48 | float x0; |
| 49 | |
| 50 | /* Uninitialised, but we know px[0] is 0x0. */ |
| 51 | float *px = malloc(sizeof(*px)); |
| 52 | x0 = px[0]; |
| 53 | |
Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 54 | sa.sa_sigaction = sighandler; |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 55 | sa.sa_flags = SA_SIGINFO; |
| 56 | if (sigfillset(&sa.sa_mask)) { |
| 57 | perror("sigfillset"); |
| 58 | return 1; |
| 59 | } |
| 60 | if (sigaction(SIGUSR1, &sa, NULL)) { |
| 61 | perror("sigaction"); |
| 62 | return 1; |
| 63 | } |
| 64 | |
| 65 | pid = getpid(); |
| 66 | |
| 67 | __asm__ __volatile__( |
| 68 | /* Set values in the FP stack. */ |
| 69 | "flds %[x0]\n" |
| 70 | "fld1\n" |
| 71 | "flds %[x0]\n" |
| 72 | "fld1\n" |
| 73 | "flds %[x0]\n" |
| 74 | "fld1\n" |
| 75 | "flds %[x0]\n" |
| 76 | "fld1\n" |
| 77 | |
| 78 | /* Trigger the signal handler. */ |
| 79 | "syscall\n" |
| 80 | "fstps 0x00 + %[out]\n" |
| 81 | "fstps 0x04 + %[out]\n" |
| 82 | "fstps 0x08 + %[out]\n" |
| 83 | "fstps 0x0c + %[out]\n" |
| 84 | "fstps 0x10 + %[out]\n" |
| 85 | "fstps 0x14 + %[out]\n" |
| 86 | "fstps 0x18 + %[out]\n" |
| 87 | "fstps 0x1c + %[out]\n" |
| 88 | : [out] "=m" (out[0]) |
| 89 | : "a" (SYS_kill), "D" (pid), "S" (SIGUSR1), [x0] "m" (x0) |
| 90 | : "rdx", "cc", "memory"); |
| 91 | |
| 92 | printf("Values in the signal handler:\n"); |
| 93 | printf(" fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n", |
| 94 | inhandler[0], inhandler[2], inhandler[4], inhandler[6]); |
| 95 | /* Check that inhandler[1], inhandler[3], inhandler[5] and inhandler[7] |
| 96 | contain uninitialised values (origin is px[0]). */ |
| 97 | if (inhandler[1] || inhandler[3] || inhandler[5] || inhandler[7]) |
| 98 | assert(0); |
| 99 | |
| 100 | printf("Values after the return from the signal handler:\n"); |
| 101 | printf(" fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n", |
| 102 | out[0], out[2], out[4], out[6]); |
| 103 | /* Check that out[1], out[3], out[5] and out[7] contain uninitialised |
| 104 | values (origin is px[0]). */ |
| 105 | if (out[1] || out[3] || out[5] || out[7]) |
| 106 | assert(0); |
| 107 | |
| 108 | return 0; |
| 109 | } |
| 110 | |