18eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* Test if values in rax, rbx, rcx, rdx, rsi and rdi are correctly propagated
28eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   into and out of a signal handler and also check that the same applies for
38eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   uninitialised values and their origins. */
48eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
58eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <assert.h>
68eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <signal.h>
78eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <stdio.h>
88eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <stdlib.h>
98eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <unistd.h>
10a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes#include <sys/regset.h>
118eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <sys/syscall.h>
128eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#include <sys/ucontext.h>
138eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
148eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic siginfo_t si;
158eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic ucontext_t uc;
168eb8bab992e3998c33770b0cdb16059a8b918a06sewardj/* x0 is always zero, but is visible to Valgrind as uninitialised. */
178eb8bab992e3998c33770b0cdb16059a8b918a06sewardjstatic long x0;
188eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
198eb8bab992e3998c33770b0cdb16059a8b918a06sewardjvoid break_out(void);
208eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
21a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughesstatic void sighandler(int sig, siginfo_t *sip, void *arg)
228eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
23a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   ucontext_t *ucp = (ucontext_t *) arg;
24a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes
258eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   si = *sip;
268eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   uc = *ucp;
278eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
288eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   ucp->uc_mcontext.gregs[REG_RCX] = x0;
298eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
308eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Break out of the endless loop. */
318eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   *(uintptr_t*)&ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t)break_out;
328eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
338eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
348eb8bab992e3998c33770b0cdb16059a8b918a06sewardjint main(void)
358eb8bab992e3998c33770b0cdb16059a8b918a06sewardj{
368eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   struct sigaction sa;
378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   long rax, rbx, rcx, rdx, rsi, rdi;
388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   long y0;
398eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
408eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Uninitialised, but we know px[0] is 0x0. */
418eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   long *px = malloc(sizeof(*px));
428eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   x0 = px[0];
438eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
448eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Uninitialised, but we know py[0] is 0x0. */
458eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   long *py = malloc(sizeof(*py));
468eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   y0 = py[0];
478eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
48a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   sa.sa_sigaction = sighandler;
498eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   sa.sa_flags = SA_SIGINFO;
508eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (sigfillset(&sa.sa_mask)) {
518eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      perror("sigfillset");
528eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return 1;
538eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
548eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (sigaction(SIGALRM, &sa, NULL)) {
558eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      perror("sigaction");
568eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      return 1;
578eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   }
588eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
598eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   alarm(2);
608eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
618eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   __asm__ __volatile__(
628eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Set values in general purpose registers. */
638eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   $0xf0, %%rax\n"
648eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   %[y0], %%rbx\n"
658eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   $0xf1, %%rcx\n"
668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   $0xf2, %%rdx\n"
678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   $0xf3, %%rsi\n"
688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "movq   $0xf4, %%rdi\n"
698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
708eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      /* Loopity loop, this is where the SIGALRM is triggered. */
718eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "1:\n"
728eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "jmp    1b\n"
738eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      "break_out:\n"
758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : "=a" (rax), "=b" (rbx), "=c" (rcx), "=d" (rdx), "=S" (rsi),
768eb8bab992e3998c33770b0cdb16059a8b918a06sewardj        "=D" (rdi)
778eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : [y0] "m" (y0)
788eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      : "cc", "memory");
798eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
808eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("Values in the signal handler:\n");
818eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("  rax=%#lx, rcx=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n",
828eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          uc.uc_mcontext.gregs[REG_RAX], uc.uc_mcontext.gregs[REG_RCX],
838eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          uc.uc_mcontext.gregs[REG_RDX], uc.uc_mcontext.gregs[REG_RSI],
848eb8bab992e3998c33770b0cdb16059a8b918a06sewardj          uc.uc_mcontext.gregs[REG_RDI]);
858eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Check that rbx contains an uninitialised value (origin is py[0]). */
868eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (uc.uc_mcontext.gregs[REG_RBX])
878eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      assert(0);
888eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
898eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("Values after the return from the signal handler:\n");
908eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   printf("  rax=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n", rax, rdx, rsi, rdi);
918eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   /* Check that rbx and rcx contain uninitialised values (origin is py[0]
928eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      and px[0], respectively). */
938eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   if (rbx || rcx)
948eb8bab992e3998c33770b0cdb16059a8b918a06sewardj      assert(0);
958eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
968eb8bab992e3998c33770b0cdb16059a8b918a06sewardj   return 0;
978eb8bab992e3998c33770b0cdb16059a8b918a06sewardj}
988eb8bab992e3998c33770b0cdb16059a8b918a06sewardj
99