$(addsuffix .stderr.exp,$(INSN_TESTS)) \
$(addsuffix .stdout.exp,$(INSN_TESTS)) \
$(addsuffix .vgtest,$(INSN_TESTS)) \
+ int3-x86.vgtest int3-x86.stderr.exp int3-x86.stdout.exp \
pushfpopf.stderr.exp pushfpopf.stdout.exp pushfpopf.vgtest \
pushpopmem.stderr.exp pushpopmem.stdout.exp pushpopmem.vgtest \
scalar.stderr.exp scalar.stderr.exp2 scalar.vgtest \
check_PROGRAMS = \
bug133694 \
espindola2 \
+ int3-x86 \
scalar_exit_group scalar_fork scalar_supp scalar_vfork \
fpeflags pushfpopf pushpopmem scalar sse_memory tronical \
more_x86_fp fprem xor-undef-x86
--- /dev/null
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE 1
+
+#include <signal.h>
+#include <stdio.h>
+#include <sys/ucontext.h>
+
+static char* eip_at_sig = NULL;
+
+static void int_handler(int signum, siginfo_t *si, void *uc_arg)
+{
+ ucontext_t *uc = (ucontext_t *)uc_arg;
+ /* Note that uc->uc_mcontext is an embedded struct, not a pointer */
+ mcontext_t *mc = &(uc->uc_mcontext);
+ void *pc = (void*)mc->gregs[REG_EIP];
+ printf("in int_handler, EIP is ...\n");
+ eip_at_sig = pc;
+}
+
+static void register_handler(int sig, void *handler)
+{
+ struct sigaction sa;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ sigfillset(&sa.sa_mask);
+ sa.sa_sigaction = handler;
+ sigaction(sig, &sa, NULL);
+}
+
+int main(void) {
+ char *intaddr = NULL;
+ puts("main");
+ register_handler(SIGTRAP, int_handler);
+ asm volatile(
+ "movl $zz_int, %%edx\n"
+ "mov %%edx, %0\n"
+ "zz_int:\n"
+ "int $3\n"
+ : /* no outputs */
+ : "m" (intaddr) /* input: address of var to store target addr to */
+ : /* clobbers */ "edx"
+ );
+ /* intaddr is the address of the int 3 insn. eip_at_sig is the PC
+ after the exception, which should be the next insn along.
+ Hence: */
+ if (intaddr != NULL && eip_at_sig != NULL
+ && eip_at_sig == intaddr+1)
+ printf("PASS\n");
+ else
+ printf("FAIL\n");
+ return 0;
+}