authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2022-01-17 17:46:48+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-02 21:18:45-07:00
logafd1f7ed47884ca39082287c267fbb9c5d1ebe68
tree52e47163a9a63cd7a4bc70dabc1c3ad7f241d9cd
parent2ac7aefe2ff0d2f1a4d58a2baa49a40dfb670732

Implement segfault handler for macOS x86_64


3 files changed, 57 insertions(+), 7 deletions(-)

lib/std/c/darwin.zig+45
...@@ -478,6 +478,51 @@ pub const SIG = struct {...@@ -478,6 +478,51 @@ pub const SIG = struct {
478 pub const USR2 = 31;478 pub const USR2 = 31;
479};479};
480480
481pub const ucontext_t = extern struct {
482 onstack: c_int,
483 sigmask: sigset_t,
484 stack: stack_t,
485 link: ?*ucontext_t,
486 mcsize: u64,
487 mcontext: *mcontext_t,
488};
489
490pub const exception_state = extern struct {
491 trapno: u16,
492 cpu: u16,
493 err: u32,
494 faultvaddr: u64,
495};
496
497pub const thread_state = extern struct {
498 rax: u64,
499 rbx: u64,
500 rcx: u64,
501 rdx: u64,
502 rdi: u64,
503 rsi: u64,
504 rbp: u64,
505 rsp: u64,
506 r8: u64,
507 r9: u64,
508 r10: u64,
509 r11: u64,
510 r12: u64,
511 r13: u64,
512 r14: u64,
513 r15: u64,
514 rip: u64,
515 rflags: u64,
516 cs: u64,
517 fs: u64,
518 gs: u64,
519};
520
521pub const mcontext_t = extern struct {
522 es: exception_state,
523 ss: thread_state,
524};
525
481pub const siginfo_t = extern struct {526pub const siginfo_t = extern struct {
482 signo: c_int,527 signo: c_int,
483 errno: c_int,528 errno: c_int,
lib/std/debug.zig+6-3
...@@ -1574,6 +1574,7 @@ fn getDebugInfoAllocator() mem.Allocator {...@@ -1574,6 +1574,7 @@ fn getDebugInfoAllocator() mem.Allocator {
1574/// Whether or not the current target can print useful debug information when a segfault occurs.1574/// Whether or not the current target can print useful debug information when a segfault occurs.
1575pub const have_segfault_handling_support = switch (native_os) {1575pub const have_segfault_handling_support = switch (native_os) {
1576 .linux, .netbsd, .solaris => true,1576 .linux, .netbsd, .solaris => true,
1577 .macos => native_arch == .x86_64,
1577 .windows => true,1578 .windows => true,
1578 .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"),1579 .freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"),
1579 else => false,1580 else => false,
...@@ -1601,7 +1602,7 @@ pub fn attachSegfaultHandler() void {...@@ -1601,7 +1602,7 @@ pub fn attachSegfaultHandler() void {
1601 return;1602 return;
1602 }1603 }
1603 var act = os.Sigaction{1604 var act = os.Sigaction{
1604 .handler = .{ .sigaction = handleSegfaultLinux },1605 .handler = .{ .sigaction = handleSegfaultPosix },
1605 .mask = os.empty_sigset,1606 .mask = os.empty_sigset,
1606 .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),1607 .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),
1607 };1608 };
...@@ -1629,7 +1630,7 @@ fn resetSegfaultHandler() void {...@@ -1629,7 +1630,7 @@ fn resetSegfaultHandler() void {
1629 os.sigaction(os.SIG.BUS, &act, null);1630 os.sigaction(os.SIG.BUS, &act, null);
1630}1631}
16311632
1632fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {1633fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
1633 // Reset to the default handler so that if a segfault happens in this handler it will crash1634 // Reset to the default handler so that if a segfault happens in this handler it will crash
1634 // the process. Also when this handler returns, the original instruction will be repeated1635 // the process. Also when this handler returns, the original instruction will be repeated
1635 // and the resulting segfault will crash the process rather than continually dump stack traces.1636 // 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...@@ -1637,7 +1638,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
16371638
1638 const addr = switch (native_os) {1639 const addr = switch (native_os) {
1639 .linux => @ptrToInt(info.fields.sigfault.addr),1640 .linux => @ptrToInt(info.fields.sigfault.addr),
1640 .freebsd => @ptrToInt(info.addr),1641 .freebsd, .macos => @ptrToInt(info.addr),
1641 .netbsd => @ptrToInt(info.info.reason.fault.addr),1642 .netbsd => @ptrToInt(info.info.reason.fault.addr),
1642 .openbsd => @ptrToInt(info.data.fault.addr),1643 .openbsd => @ptrToInt(info.data.fault.addr),
1643 .solaris => @ptrToInt(info.reason.fault.addr),1644 .solaris => @ptrToInt(info.reason.fault.addr),
...@@ -1668,12 +1669,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any...@@ -1668,12 +1669,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
1668 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]),1669 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]),
1669 .freebsd => @intCast(usize, ctx.mcontext.rip),1670 .freebsd => @intCast(usize, ctx.mcontext.rip),
1670 .openbsd => @intCast(usize, ctx.sc_rip),1671 .openbsd => @intCast(usize, ctx.sc_rip),
1672 .macos => @intCast(usize, ctx.mcontext.ss.rip),
1671 else => unreachable,1673 else => unreachable,
1672 };1674 };
1673 const bp = switch (native_os) {1675 const bp = switch (native_os) {
1674 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]),1676 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]),
1675 .openbsd => @intCast(usize, ctx.sc_rbp),1677 .openbsd => @intCast(usize, ctx.sc_rbp),
1676 .freebsd => @intCast(usize, ctx.mcontext.rbp),1678 .freebsd => @intCast(usize, ctx.mcontext.rbp),
1679 .macos => @intCast(usize, ctx.mcontext.ss.rbp),
1677 else => unreachable,1680 else => unreachable,
1678 };1681 };
1679 dumpStackTraceFromBase(bp, ip);1682 dumpStackTraceFromBase(bp, ip);
src/crash_report.zig+6-4
...@@ -169,7 +169,7 @@ pub fn attachSegfaultHandler() void {...@@ -169,7 +169,7 @@ pub fn attachSegfaultHandler() void {
169 return;169 return;
170 }170 }
171 var act = os.Sigaction{171 var act = os.Sigaction{
172 .handler = .{ .sigaction = handleSegfaultLinux },172 .handler = .{ .sigaction = handleSegfaultPosix },
173 .mask = os.empty_sigset,173 .mask = os.empty_sigset,
174 .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),174 .flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),
175 };175 };
...@@ -179,17 +179,17 @@ pub fn attachSegfaultHandler() void {...@@ -179,17 +179,17 @@ pub fn attachSegfaultHandler() void {
179 os.sigaction(os.SIG.BUS, &act, null);179 os.sigaction(os.SIG.BUS, &act, null);
180}180}
181181
182fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {182fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
183 // TODO: use alarm() here to prevent infinite loops183 // TODO: use alarm() here to prevent infinite loops
184 PanicSwitch.preDispatch();184 PanicSwitch.preDispatch();
185185
186 const addr = switch (builtin.os.tag) {186 const addr = switch (builtin.os.tag) {
187 .linux => @ptrToInt(info.fields.sigfault.addr),187 .linux => @ptrToInt(info.fields.sigfault.addr),
188 .freebsd => @ptrToInt(info.addr),188 .freebsd, .macos => @ptrToInt(info.addr),
189 .netbsd => @ptrToInt(info.info.reason.fault.addr),189 .netbsd => @ptrToInt(info.info.reason.fault.addr),
190 .openbsd => @ptrToInt(info.data.fault.addr),190 .openbsd => @ptrToInt(info.data.fault.addr),
191 .solaris => @ptrToInt(info.reason.fault.addr),191 .solaris => @ptrToInt(info.reason.fault.addr),
192 else => @compileError("TODO implement handleSegfaultLinux for new linux OS"),192 else => @compileError("TODO implement handleSegfaultPosix for new POSIX OS"),
193 };193 };
194194
195 var err_buffer: [128]u8 = undefined;195 var err_buffer: [128]u8 = undefined;
...@@ -213,12 +213,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any...@@ -213,12 +213,14 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
213 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]),213 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RIP]),
214 .freebsd => @intCast(usize, ctx.mcontext.rip),214 .freebsd => @intCast(usize, ctx.mcontext.rip),
215 .openbsd => @intCast(usize, ctx.sc_rip),215 .openbsd => @intCast(usize, ctx.sc_rip),
216 .macos => @intCast(usize, ctx.mcontext.ss.rip),
216 else => unreachable,217 else => unreachable,
217 };218 };
218 const bp = switch (builtin.os.tag) {219 const bp = switch (builtin.os.tag) {
219 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]),220 .linux, .netbsd, .solaris => @intCast(usize, ctx.mcontext.gregs[os.REG.RBP]),
220 .openbsd => @intCast(usize, ctx.sc_rbp),221 .openbsd => @intCast(usize, ctx.sc_rbp),
221 .freebsd => @intCast(usize, ctx.mcontext.rbp),222 .freebsd => @intCast(usize, ctx.mcontext.rbp),
223 .macos => @intCast(usize, ctx.mcontext.ss.rbp),
222 else => unreachable,224 else => unreachable,
223 };225 };
224 break :ctx StackContext{ .exception = .{ .bp = bp, .ip = ip } };226 break :ctx StackContext{ .exception = .{ .bp = bp, .ip = ip } };