//
// 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>
// 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) {
}
// 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();
--- /dev/null
+// 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)