Skip to content

Instantly share code, notes, and snippets.

@andrewrk
Created March 2, 2019 23:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrewrk/79a2f843c87886fe463131d2e9b3aef7 to your computer and use it in GitHub Desktop.
Save andrewrk/79a2f843c87886fe463131d2e9b3aef7 to your computer and use it in GitHub Desktop.
naive segfault handler with dumping a stack trace
# 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
[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
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