1/* Test if values in rax, rbx, rcx, rdx, rsi and rdi are correctly propagated
2   into and out of a signal handler and also check that the same applies for
3   uninitialised values and 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
13static siginfo_t si;
14static ucontext_t uc;
15/* x0 is always zero, but is visible to Valgrind as uninitialised. */
16static long x0;
17
18void break_out(void);
19
20static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
21{
22   si = *sip;
23   uc = *ucp;
24
25   ucp->uc_mcontext.gregs[REG_RCX] = x0;
26
27   /* Break out of the endless loop. */
28   *(uintptr_t*)&ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t)break_out;
29}
30
31int main(void)
32{
33   struct sigaction sa;
34   long rax, rbx, rcx, rdx, rsi, rdi;
35   long y0;
36
37   /* Uninitialised, but we know px[0] is 0x0. */
38   long *px = malloc(sizeof(*px));
39   x0 = px[0];
40
41   /* Uninitialised, but we know py[0] is 0x0. */
42   long *py = malloc(sizeof(*py));
43   y0 = py[0];
44
45   sa.sa_handler = sighandler;
46   sa.sa_flags = SA_SIGINFO;
47   if (sigfillset(&sa.sa_mask)) {
48      perror("sigfillset");
49      return 1;
50   }
51   if (sigaction(SIGALRM, &sa, NULL)) {
52      perror("sigaction");
53      return 1;
54   }
55
56   alarm(2);
57
58   __asm__ __volatile__(
59      /* Set values in general purpose registers. */
60      "movq   $0xf0, %%rax\n"
61      "movq   %[y0], %%rbx\n"
62      "movq   $0xf1, %%rcx\n"
63      "movq   $0xf2, %%rdx\n"
64      "movq   $0xf3, %%rsi\n"
65      "movq   $0xf4, %%rdi\n"
66
67      /* Loopity loop, this is where the SIGALRM is triggered. */
68      "1:\n"
69      "jmp    1b\n"
70
71      "break_out:\n"
72      : "=a" (rax), "=b" (rbx), "=c" (rcx), "=d" (rdx), "=S" (rsi),
73        "=D" (rdi)
74      : [y0] "m" (y0)
75      : "cc", "memory");
76
77   printf("Values in the signal handler:\n");
78   printf("  rax=%#lx, rcx=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n",
79          uc.uc_mcontext.gregs[REG_RAX], uc.uc_mcontext.gregs[REG_RCX],
80          uc.uc_mcontext.gregs[REG_RDX], uc.uc_mcontext.gregs[REG_RSI],
81          uc.uc_mcontext.gregs[REG_RDI]);
82   /* Check that rbx contains an uninitialised value (origin is py[0]). */
83   if (uc.uc_mcontext.gregs[REG_RBX])
84      assert(0);
85
86   printf("Values after the return from the signal handler:\n");
87   printf("  rax=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n", rax, rdx, rsi, rdi);
88   /* Check that rbx and rcx contain uninitialised values (origin is py[0]
89      and px[0], respectively). */
90   if (rbx || rcx)
91      assert(0);
92
93   return 0;
94}
95
96