debug: implement segfault handler for macOS aarch64

Tested on a M1 MacBook Pro, macOS Monterey 12.2.
This commit is contained in:
John Schmidt 2022-02-07 18:20:33 +01:00 committed by Andrew Kelley
parent 2a415a033c
commit 05cf69209e
4 changed files with 83 additions and 50 deletions

View file

@ -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,

View file

@ -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,
};

View file

@ -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,
};

View file

@ -1610,9 +1610,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,
};
@ -1726,9 +1730,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 => {},