Commit fbde43524f

John Schmidt <john.schmidt.h@gmail.com>
2022-02-07 18:20:33
debug: implement segfault handler for macOS aarch64
Tested on a M1 MacBook Pro, macOS Monterey 12.2.
1 parent 8e10c80
Changed files (4)
lib/std/c/darwin/aarch64.zig
@@ -0,0 +1,18 @@
+// See C headers in
+// lib/libc/include/aarch64-macos.12-gnu/mach/arm/_structs.h
+
+pub const exception_state = extern struct {
+    far: u64, // Virtual Fault Address
+    esr: u32, // Exception syndrome
+    exception: u32, // Number of arm exception taken
+};
+
+pub const thread_state = extern struct {
+    regs: [29]u64, // General purpose registers
+    fp: u64, // Frame pointer x29
+    lr: u64, // Link register x30
+    sp: u64, // Stack pointer x31
+    pc: u64, // Program counter
+    cpsr: u32, // Current program status register
+    __pad: u32,
+};
lib/std/c/darwin/x86_64.zig
@@ -0,0 +1,30 @@
+pub const exception_state = extern struct {
+    trapno: u16,
+    cpu: u16,
+    err: u32,
+    faultvaddr: u64,
+};
+
+pub const thread_state = extern struct {
+    rax: u64,
+    rbx: u64,
+    rcx: u64,
+    rdx: u64,
+    rdi: u64,
+    rsi: u64,
+    rbp: u64,
+    rsp: u64,
+    r8: u64,
+    r9: u64,
+    r10: u64,
+    r11: u64,
+    r12: u64,
+    r13: u64,
+    r14: u64,
+    r15: u64,
+    rip: u64,
+    rflags: u64,
+    cs: u64,
+    fs: u64,
+    gs: u64,
+};
lib/std/c/darwin.zig
@@ -6,6 +6,26 @@ const native_arch = builtin.target.cpu.arch;
 const maxInt = std.math.maxInt;
 const iovec_const = std.os.iovec_const;
 
+const arch_bits = switch (native_arch) {
+    .aarch64 => @import("darwin/aarch64.zig"),
+    .x86_64 => @import("darwin/x86_64.zig"),
+    else => struct {},
+};
+
+pub const ucontext_t = extern struct {
+    onstack: c_int,
+    sigmask: sigset_t,
+    stack: stack_t,
+    link: ?*ucontext_t,
+    mcsize: u64,
+    mcontext: *mcontext_t,
+};
+
+pub const mcontext_t = extern struct {
+    es: arch_bits.exception_state,
+    ss: arch_bits.thread_state,
+};
+
 extern "c" fn __error() *c_int;
 pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32;
 pub extern "c" fn _NSGetExecutablePath(buf: [*:0]u8, bufsize: *u32) c_int;
@@ -478,51 +498,6 @@ pub const SIG = struct {
     pub const USR2 = 31;
 };
 
-pub const ucontext_t = extern struct {
-    onstack: c_int,
-    sigmask: sigset_t,
-    stack: stack_t,
-    link: ?*ucontext_t,
-    mcsize: u64,
-    mcontext: *mcontext_t,
-};
-
-pub const exception_state = extern struct {
-    trapno: u16,
-    cpu: u16,
-    err: u32,
-    faultvaddr: u64,
-};
-
-pub const thread_state = extern struct {
-    rax: u64,
-    rbx: u64,
-    rcx: u64,
-    rdx: u64,
-    rdi: u64,
-    rsi: u64,
-    rbp: u64,
-    rsp: u64,
-    r8: u64,
-    r9: u64,
-    r10: u64,
-    r11: u64,
-    r12: u64,
-    r13: u64,
-    r14: u64,
-    r15: u64,
-    rip: u64,
-    rflags: u64,
-    cs: u64,
-    fs: u64,
-    gs: u64,
-};
-
-pub const mcontext_t = extern struct {
-    es: exception_state,
-    ss: thread_state,
-};
-
 pub const siginfo_t = extern struct {
     signo: c_int,
     errno: c_int,
lib/std/debug.zig
@@ -1601,9 +1601,13 @@ fn getDebugInfoAllocator() mem.Allocator {
 
 /// Whether or not the current target can print useful debug information when a segfault occurs.
 pub const have_segfault_handling_support = switch (native_os) {
-    .linux, .netbsd, .solaris => true,
-    .macos => native_arch == .x86_64,
-    .windows => true,
+    .linux,
+    .macos,
+    .netbsd,
+    .solaris,
+    .windows,
+    => true,
+
     .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"),
     else => false,
 };
@@ -1717,9 +1721,15 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
         },
         .aarch64 => {
             const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
-            const ip = @intCast(usize, ctx.mcontext.pc);
+            const ip = switch (native_os) {
+                .macos => @intCast(usize, ctx.mcontext.ss.pc),
+                else => @intCast(usize, ctx.mcontext.pc),
+            };
             // x29 is the ABI-designated frame pointer
-            const bp = @intCast(usize, ctx.mcontext.regs[29]);
+            const bp = switch (native_os) {
+                .macos => @intCast(usize, ctx.mcontext.ss.fp),
+                else => @intCast(usize, ctx.mcontext.regs[29]),
+            };
             dumpStackTraceFromBase(bp, ip);
         },
         else => {},