diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 2a4541ea74..b10b582dc2 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -478,6 +478,51 @@ 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, diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 6c09b71451..517176c900 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1574,6 +1574,7 @@ 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, .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"), else => false, @@ -1601,7 +1602,7 @@ pub fn attachSegfaultHandler() void { return; } var act = os.Sigaction{ - .handler = .{ .sigaction = handleSegfaultLinux }, + .handler = .{ .sigaction = handleSegfaultPosix }, .mask = os.empty_sigset, .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), }; @@ -1629,7 +1630,7 @@ fn resetSegfaultHandler() void { os.sigaction(os.SIG.BUS, &act, null); } -fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { +fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { // Reset to the default handler so that if a segfault happens in this handler it will crash // the process. Also when this handler returns, the original instruction will be repeated // and the resulting segfault will crash the process rather than continually dump stack traces. @@ -1637,7 +1638,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any const addr = switch (native_os) { .linux => @ptrToInt(info.fields.sigfault.addr), - .freebsd => @ptrToInt(info.addr), + .freebsd, .macos => @ptrToInt(info.addr), .netbsd => @ptrToInt(info.info.reason.fault.addr), .openbsd => @ptrToInt(info.data.fault.addr), .solaris => @ptrToInt(info.reason.fault.addr), @@ -1668,12 +1669,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), .freebsd => @intCast(usize, ctx.mcontext.rip), .openbsd => @intCast(usize, ctx.sc_rip), + .macos => @intCast(usize, ctx.mcontext.ss.rip), else => unreachable, }; const bp = switch (native_os) { .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), .openbsd => @intCast(usize, ctx.sc_rbp), .freebsd => @intCast(usize, ctx.mcontext.rbp), + .macos => @intCast(usize, ctx.mcontext.ss.rbp), else => unreachable, }; dumpStackTraceFromBase(bp, ip); diff --git a/src/crash_report.zig b/src/crash_report.zig index 88b59e8952..724269556b 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -169,7 +169,7 @@ pub fn attachSegfaultHandler() void { return; } var act = os.Sigaction{ - .handler = .{ .sigaction = handleSegfaultLinux }, + .handler = .{ .sigaction = handleSegfaultPosix }, .mask = os.empty_sigset, .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND), }; @@ -179,17 +179,17 @@ pub fn attachSegfaultHandler() void { os.sigaction(os.SIG.BUS, &act, null); } -fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { +fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn { // TODO: use alarm() here to prevent infinite loops PanicSwitch.preDispatch(); const addr = switch (builtin.os.tag) { .linux => @ptrToInt(info.fields.sigfault.addr), - .freebsd => @ptrToInt(info.addr), + .freebsd, .macos => @ptrToInt(info.addr), .netbsd => @ptrToInt(info.info.reason.fault.addr), .openbsd => @ptrToInt(info.data.fault.addr), .solaris => @ptrToInt(info.reason.fault.addr), - else => @compileError("TODO implement handleSegfaultLinux for new linux OS"), + else => @compileError("TODO implement handleSegfaultPosix for new POSIX OS"), }; var err_buffer: [128]u8 = undefined; @@ -213,12 +213,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]), .freebsd => @intCast(usize, ctx.mcontext.rip), .openbsd => @intCast(usize, ctx.sc_rip), + .macos => @intCast(usize, ctx.mcontext.ss.rip), else => unreachable, }; const bp = switch (builtin.os.tag) { .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]), .openbsd => @intCast(usize, ctx.sc_rbp), .freebsd => @intCast(usize, ctx.mcontext.rbp), + .macos => @intCast(usize, ctx.mcontext.ss.rbp), else => unreachable, }; break :ctx StackContext{ .exception = .{ .bp = bp, .ip = ip } };