Skip to content

Commit

Permalink
introduce std.debug.captureStackTrace
Browse files Browse the repository at this point in the history
and fix the implementation of writeStackTrace
it was printing the first frame in the wrong place
  • Loading branch information
andrewrk committed Feb 23, 2019
1 parent 6fd8d45 commit 00d8f4a
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 16 deletions.
74 changes: 62 additions & 12 deletions std/debug/index.zig
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
};
}

/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
/// and then try to find the first address. If addresses.len is more than 32, we
/// capture that many stack frames exactly, and then look for the first address,
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
/// equals the passed in addresses pointer.
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
switch (builtin.os) {
builtin.Os.windows => {
const addrs = stack_trace.instruction_addresses;
const u32_addrs_len = @intCast(u32, addrs.len);
const first_addr = first_address orelse {
stack_trace.index = windows.RtlCaptureStackBackTrace(
0,
u32_addrs_len,
@ptrCast(**c_void, addrs.ptr),
null,
);
return;
};
var addr_buf_stack: [32]usize = undefined;
const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
const first_index = for (addr_buf[0..n]) |addr, i| {
if (addr == first_addr) {
break i;
}
} else {
stack_trace.index = 0;
return;
};
const slice = addr_buf[first_index..n];
// We use a for loop here because slice and addrs may alias.
for (slice) |addr, i| {
addrs[i] = addr;
}
stack_trace.index = slice.len;
},
else => {
var it = StackIterator.init(first_address);
for (stack_trace.instruction_addresses) |*addr, i| {
addr.* = it.next() orelse {
stack_trace.index = i;
return;
};
}
stack_trace.index = stack_trace.instruction_addresses.len;
},
}
}

/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
const stderr = getStderrStream() catch return;
const debug_info = getSelfDebugInfo() catch |err| {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
Expand Down Expand Up @@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
const stderr = getStderrStream() catch os.abort();
stderr.print(format ++ "\n", args) catch os.abort();
if (trace) |t| {
dumpStackTrace(t);
dumpStackTrace(t.*);
}
dumpCurrentStackTrace(first_trace_addr);

Expand All @@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";
const DIM = "\x1b[2m";
const RESET = "\x1b[0m";

pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void {
var frame_index: usize = undefined;
var frames_left: usize = undefined;
if (stack_trace.index < stack_trace.instruction_addresses.len) {
frame_index = 0;
frames_left = stack_trace.index;
} else {
frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;
frames_left = stack_trace.instruction_addresses.len;
}
pub fn writeStackTrace(
stack_trace: builtin.StackTrace,
out_stream: var,
allocator: *mem.Allocator,
debug_info: *DebugInfo,
tty_color: bool,
) !void {
var frame_index: usize = 0;
var frames_left: usize = stack_trace.index;

while (frames_left != 0) : ({
frames_left -= 1;
Expand Down
11 changes: 7 additions & 4 deletions std/special/bootstrap.zig
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ nakedcc fn _start() noreturn {
switch (builtin.arch) {
builtin.Arch.x86_64 => {
argc_ptr = asm ("lea (%%rsp), %[argc]"
: [argc] "=r" (-> [*]usize)
);
: [argc] "=r" (-> [*]usize)
);
},
builtin.Arch.i386 => {
argc_ptr = asm ("lea (%%esp), %[argc]"
Expand Down Expand Up @@ -123,7 +123,7 @@ inline fn callMain() u8 {
std.debug.warn("error: {}\n", @errorName(err));
if (builtin.os != builtin.Os.zen) {
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace);
std.debug.dumpStackTrace(trace.*);
}
}
return 1;
Expand All @@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
var phdr_addr = at_phdr;
var n = at_phnum;
var base: usize = 0;
while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) {
while (n != 0) : ({
n -= 1;
phdr_addr += at_phent;
}) {
const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);
// TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
switch (phdr.p_type) {
Expand Down

0 comments on commit 00d8f4a

Please sign in to comment.