1
2#undef _GNU_SOURCE
3#define _GNU_SOURCE 1
4
5#include <signal.h>
6#include <stdio.h>
7#include <sys/ucontext.h>
8
9static char* eip_at_sig = NULL;
10
11static void int_handler(int signum, siginfo_t *si, void *uc_arg)
12{
13   ucontext_t *uc = (ucontext_t *)uc_arg;
14   /* Note that uc->uc_mcontext is an embedded struct, not a pointer */
15   mcontext_t *mc = &(uc->uc_mcontext);
16   void *pc = (void*)mc->gregs[REG_EIP];
17   printf("in int_handler, EIP is ...\n");
18   eip_at_sig = pc;
19}
20
21static void register_handler(int sig, void *handler)
22{
23   struct sigaction sa;
24   sa.sa_flags = SA_RESTART | SA_SIGINFO;
25   sigfillset(&sa.sa_mask);
26   sa.sa_sigaction = handler;
27   sigaction(sig, &sa, NULL);
28}
29
30int main(void) {
31   char *intaddr = NULL;
32   puts("main");
33   register_handler(SIGTRAP, int_handler);
34   asm volatile(
35      "movl $zz_int, %%edx\n"
36      "mov %%edx, %0\n"
37      "zz_int:\n"
38      "int $3\n"
39      : /* no outputs */
40      : "m" (intaddr) /* input: address of var to store target addr to */
41      : /* clobbers */ "edx"
42      );
43   /* intaddr is the address of the int 3 insn.  eip_at_sig is the PC
44      after the exception, which should be the next insn along.
45      Hence: */
46   if (intaddr != NULL && eip_at_sig != NULL
47       && eip_at_sig == intaddr+1)
48     printf("PASS\n");
49   else
50     printf("FAIL\n");
51   return 0;
52}
53