]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/cgo: EXC_BAD_ACCESS handler for arm64
authorDavid Crawshaw <crawshaw@golang.org>
Sat, 11 Apr 2015 23:14:02 +0000 (19:14 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Mon, 13 Apr 2015 12:08:37 +0000 (12:08 +0000)
Change-Id: Ia9ff9c0d381fad43fc5d3e5972dd6e66503733a5
Reviewed-on: https://go-review.googlesource.com/8815
Reviewed-by: Minux Ma <minux@golang.org>
src/runtime/cgo/gcc_signal_darwin_armx.c
src/runtime/cgo/signal_darwin_arm64.s [new file with mode: 0644]

index cb32898e439e1b1428c7f4428e71908ce9bbb4d4..9d572acce3dd4b7432840005194e579f00e30b18 100644 (file)
@@ -20,9 +20,9 @@
 //
 //     go test -tags lldb -installsuffix lldb
 
-// +build darwin,arm,!lldb
-
-// TODO(crawshaw): darwin,arm64,!lldb
+// +build !lldb
+// +build darwin
+// +build arm arm64
 
 #include <limits.h>
 #include <pthread.h>
@@ -77,9 +77,31 @@ catch_exception_raise(
 
        // Bounce call to sigpanic through asm that makes it look like
        // we call sigpanic directly from the faulting code.
+#ifdef __arm64__
+       thread_state.ts_64.__x[1] = thread_state.ts_64.__lr;
+       thread_state.ts_64.__x[2] = thread_state.ts_64.__pc;
+       thread_state.ts_64.__pc = x_cgo_panicmem;
+#else
        thread_state.ts_32.__r[1] = thread_state.ts_32.__lr;
        thread_state.ts_32.__r[2] = thread_state.ts_32.__pc;
        thread_state.ts_32.__pc = x_cgo_panicmem;
+#endif
+
+       if (0) {
+               // Useful debugging logic when panicmem is broken.
+               //
+               // Sends the first SIGSEGV and lets lldb catch the
+               // second one, avoiding a loop that locks up iOS
+               // devices requiring a hard reboot.
+               fprintf(stderr, "runtime/cgo: caught exc_bad_access\n");
+               fprintf(stderr, "__lr = %llx\n", thread_state.ts_64.__lr);
+               fprintf(stderr, "__pc = %llx\n", thread_state.ts_64.__pc);
+               static int pass1 = 0;
+               if (pass1) {
+                       return KERN_FAILURE;
+               }
+               pass1 = 1;
+       }
 
        ret = thread_set_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, state_count);
        if (ret) {
@@ -174,9 +196,10 @@ darwin_arm_init_mach_exception_handler()
        }
 
        // Start a thread to handle exceptions.
+       uintptr_t port_set = (uintptr_t)mach_exception_handler_port_set;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-       ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)mach_exception_handler_port_set);
+       ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)port_set);
        if (ret) {
                fprintf(stderr, "runtime/cgo: pthread_create failed: %d\n", ret);
                abort();
diff --git a/src/runtime/cgo/signal_darwin_arm64.s b/src/runtime/cgo/signal_darwin_arm64.s
new file mode 100644 (file)
index 0000000..83062d4
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// panicmem is the entrypoint for SIGSEGV as intercepted via a
+// mach thread port as EXC_BAD_ACCESS. As the segfault may have happened
+// in C code, we first need to load_g then call panicmem.
+//
+//     R1 - LR at moment of fault
+//     R2 - PC at moment of fault
+TEXT ·panicmem(SB),NOSPLIT,$-8
+       // If in external C code, we need to load the g register.
+       BL  runtime·load_g(SB)
+       CMP $0, g
+       BNE ongothread
+
+       // On a foreign thread.
+       // TODO(crawshaw): call badsignal
+       MOVW $139, R1
+       MOVW R1, (RSP)
+       B    runtime·exit(SB)
+
+ongothread:
+       // Trigger a SIGSEGV panic.
+       //
+       // The goal is to arrange the stack so it looks like the runtime
+       // function sigpanic was called from the PC that faulted. It has
+       // to be sigpanic, as the stack unwinding code in traceback.go
+       // looks explicitly for it.
+       //
+       // To do this we call into runtime·setsigsegv, which sets the
+       // appropriate state inside the g object. We give it the faulting
+       // PC on the stack, then put it in the LR before calling sigpanic.
+       STP.W (R1, R2), -16(RSP)
+       BL runtime·setsigsegv(SB)
+       LDP.P 16(RSP), (R1, R2)
+
+       MOVD R1, 8(RSP)
+       MOVD R2, R30 // link register
+       B runtime·sigpanic(SB)