10bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
20bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj#undef _GNU_SOURCE
30bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj#define _GNU_SOURCE 1
40bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
50bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj#include <signal.h>
60bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj#include <stdio.h>
70bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj#include <sys/ucontext.h>
80bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
90bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardjstatic char* rip_at_sig = NULL;
100bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
110bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardjstatic void int_handler(int signum, siginfo_t *si, void *uc_arg)
120bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj{
130bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   ucontext_t *uc = (ucontext_t *)uc_arg;
140bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   /* Note that uc->uc_mcontext is an embedded struct, not a pointer */
150bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   mcontext_t *mc = &(uc->uc_mcontext);
160bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   void *pc = (void*)mc->gregs[REG_RIP];
170bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   printf("in int_handler, RIP is ...\n");
180bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   rip_at_sig = pc;
190bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj}
200bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
210bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardjstatic void register_handler(int sig, void *handler)
220bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj{
230bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   struct sigaction sa;
240bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   sa.sa_flags = SA_RESTART | SA_SIGINFO;
250bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   sigfillset(&sa.sa_mask);
260bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   sa.sa_sigaction = handler;
270bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   sigaction(sig, &sa, NULL);
280bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj}
290bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj
300bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardjint main(void) {
310bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   char *intaddr = NULL;
320bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   puts("main");
330bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   register_handler(SIGTRAP, int_handler);
340bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   asm volatile(
350bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      "movabsq $zz_int, %%rdx\n"
360bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      "mov %%rdx, %0\n"
370bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      "zz_int:\n"
380bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      "int $3\n"
390bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      : /* no outputs */
400bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      : "m" (intaddr) /* input: address of var to store target addr to */
410bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      : /* clobbers */ "rdx"
420bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      );
430bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   /* intaddr is the address of the int 3 insn.  rip_at_sig is the PC
440bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      after the exception, which should be the next insn along.
450bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj      Hence: */
460bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   if (intaddr != NULL && rip_at_sig != NULL
470bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj       && rip_at_sig == intaddr+1)
480bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj     printf("PASS\n");
490bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   else
500bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj     printf("FAIL\n");
510bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj   return 0;
520bfd9e6acef6d8c34e58646ece7c94967702c4d2sewardj}
53