mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
Implement segfault handler for macOS x86_64
This commit is contained in:
parent
f423b5949b
commit
305a7def13
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 } };
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user