Created
March 2, 2019 23:39
-
-
Save andrewrk/79a2f843c87886fe463131d2e9b3aef7 to your computer and use it in GitHub Desktop.
naive segfault handler with dumping a stack trace
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# with dumpCurrentStackTrace commented out | |
execve("./test", ["./test"], 0x7ffc4946bd00 /* 131 vars */) = 0 | |
rt_sigaction(SIGSEGV, {sa_handler=0x2030b0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESETHAND, sa_restorer=0x223d10}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 | |
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x1} --- | |
rt_sigreturn({mask=[]}) = 0 | |
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x1} --- | |
+++ killed by SIGSEGV +++ | |
Segmentation fault |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[nix-shell:~/dev/zig/build]$ ./zig build-exe test.zig | |
[nix-shell:~/dev/zig/build]$ ./test | |
/home/andy/dev/zig/build/test.zig:70:5: 0x223d30 in ??? (test) | |
if (oact) |old| { | |
^ | |
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:112:22: 0x2235cb in ??? (test) | |
root.main(); | |
^ | |
/home/andy/dev/zig/build/lib/zig/std/special/bootstrap.zig:43:5: 0x2233d0 in ??? (test) | |
@noInlineCall(posixCallMainAndExit); | |
^ | |
Segmentation fault | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const std = @import("std"); | |
const assert = std.debug.assert; | |
pub fn main() void { | |
_ = sigaction(SIGSEGV, &segv_handler_action, null); | |
var x = @intToPtr(*i32, 0x1); | |
x.* = 42; | |
} | |
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | |
pub const Sigaction = struct { | |
handler: extern fn (i32) void, | |
mask: sigset_t, | |
flags: u32, | |
}; | |
const k_sigaction = extern struct { | |
handler: extern fn (i32) void, | |
flags: usize, | |
restorer: extern fn () void, | |
mask: [2]u32, | |
}; | |
pub const SIGSEGV = 11; | |
pub const SIGKILL = 9; | |
pub const SIGSTOP = 19; | |
pub const empty_sigset = []usize{0} ** sigset_t.len; | |
pub const SA_RESETHAND = 0x80000000; | |
pub const SA_RESTORER = 0x04000000; | |
const sigset_t = [128 / @sizeOf(usize)]usize; | |
const segv_handler_action = Sigaction{ | |
.handler = segv_handler, | |
.mask = empty_sigset, | |
.flags = SA_RESETHAND, | |
}; | |
extern fn segv_handler(sig: i32) void { | |
std.debug.dumpCurrentStackTrace(@returnAddress()); | |
} | |
pub const SYS_rt_sigaction = 13; | |
pub const SYS_rt_sigreturn = 15; | |
pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { | |
assert(sig >= 1); | |
assert(sig != SIGKILL); | |
assert(sig != SIGSTOP); | |
var ksa = k_sigaction{ | |
.handler = act.handler, | |
.flags = act.flags | SA_RESTORER, | |
.mask = undefined, | |
.restorer = @ptrCast(extern fn () void, restore_rt), | |
}; | |
var ksa_old: k_sigaction = undefined; | |
@memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8); | |
const result = syscall4( | |
SYS_rt_sigaction, | |
sig, | |
@ptrToInt(&ksa), | |
@ptrToInt(&ksa_old), | |
@sizeOf(@typeOf(ksa.mask)), | |
); | |
const err = getErrno(result); | |
if (err != 0) { | |
return result; | |
} | |
if (oact) |old| { | |
old.handler = ksa_old.handler; | |
old.flags = @truncate(u32, ksa_old.flags); | |
@memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask))); | |
} | |
return 0; | |
} | |
pub nakedcc fn restore_rt() void { | |
return asm volatile ("syscall" | |
: | |
: [number] "{rax}" (usize(SYS_rt_sigreturn)) | |
: "rcx", "r11" | |
); | |
} | |
pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { | |
return asm volatile ("syscall" | |
: [ret] "={rax}" (-> usize) | |
: [number] "{rax}" (number), | |
[arg1] "{rdi}" (arg1), | |
[arg2] "{rsi}" (arg2), | |
[arg3] "{rdx}" (arg3), | |
[arg4] "{r10}" (arg4) | |
: "rcx", "r11" | |
); | |
} | |
/// Get the errno from a syscall return value, or 0 for no error. | |
pub fn getErrno(r: usize) usize { | |
const signed_r = @bitCast(isize, r); | |
return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment