Handle a SIGSEGV by having the main loop load from a dummy
authorMatt Mullins <mmullins@mmlx.us>
Sat, 21 Sep 2013 22:59:41 +0000 (22:59 +0000)
committerMatt Mullins <mmullins@mmlx.us>
Sat, 21 Sep 2013 23:02:35 +0000 (23:02 +0000)
This is by far the dirtiest signal handler I've ever written.  I can't believe
glibc gives me access to the registers so darn easily.

mmap_everything.c

index d2db52d..13d343d 100644 (file)
@@ -1,6 +1,10 @@
+#define _GNU_SOURCE foo
+
 #include <limits.h>
+#include <signal.h>
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <sys/ucontext.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -9,6 +13,25 @@
 
 #define MAX_BITS (sizeof(size_t) * CHAR_BIT - 1)
 
+int dummy = 13;
+int *pi;
+
+static void catch_sigsegv(int signal, siginfo_t *info, void *p) {
+       (void)(signal);
+
+       ucontext_t *uctx = (ucontext_t*)p;
+       greg_t rip = uctx->uc_mcontext.gregs[REG_RIP];
+
+       fprintf(stderr, "Caught a segfault at %p\n", info->si_addr);
+       fflush(stderr);
+
+       // Point it at a variable we can always load
+       pi = &dummy;
+       // Roll back %rip so we can reload *pi before dereferencing
+       rip -= 7; // length of mov    0x2006b4(%rip),%rax        # 0x6012b0 <pi>
+       uctx->uc_mcontext.gregs[REG_RIP] = rip;
+}
+
 int main() {
        pid_t pid = getpid();
        printf("My pid is: %d\n", pid);
@@ -44,10 +67,18 @@ int main() {
                }
        }
 
+       sigset_t empty;
+       sigemptyset(&empty);
+       struct sigaction sigsegv_action = {
+               .sa_sigaction = catch_sigsegv,
+               .sa_mask = empty,
+               .sa_flags = SA_SIGINFO
+       };
+       sigaction(SIGSEGV, &sigsegv_action, NULL);
+
        srand48(time(NULL));
        int data;
        do {
-               int *pi;
                uint32_t lower = lrand48();
                uint32_t upper = lrand48();
 
@@ -59,10 +90,14 @@ int main() {
                printf("*%p = ", (void*)pi);
                fflush(stdout);
                data = *pi;
-               printf("%x\n", data);
+               if (pi != &dummy) {
+                       printf("%04x\n", data);
+               } else {
+                       printf("dummy\n");
+               }
 
                if (munmap((void*)(pvalue & ~0xFFFL), 4096)) {
                        perror("munmap");
                }
-       } while (data == 0);
+       } while (data == 0 || pi == &dummy);
 }