authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-23 13:19:06-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-23 13:19:06-05:00
log00d8f4a1bb634ec5b0569e6ff6c2679ade2bd6b0
treec06f376d383800d703be682e7ad5ee258e56788b
parent6fd8d455bcc6765e7411fa00d23dca1eb270aac9
signaturelock-open Commit is signed but in an unrecognized format.

introduce std.debug.captureStackTrace

and fix the implementation of writeStackTrace it was printing the first frame in the wrong place

2 files changed, 69 insertions(+), 16 deletions(-)

std/debug/index.zig+62-12
...@@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
90 };90 };
91}91}
9292
93/// Returns a slice with the same pointer as addresses, with a potentially smaller len.
94/// On Windows, when first_address is not null, we ask for at least 32 stack frames,
95/// and then try to find the first address. If addresses.len is more than 32, we
96/// capture that many stack frames exactly, and then look for the first address,
97/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
98/// equals the passed in addresses pointer.
99pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
100 switch (builtin.os) {
101 builtin.Os.windows => {
102 const addrs = stack_trace.instruction_addresses;
103 const u32_addrs_len = @intCast(u32, addrs.len);
104 const first_addr = first_address orelse {
105 stack_trace.index = windows.RtlCaptureStackBackTrace(
106 0,
107 u32_addrs_len,
108 @ptrCast(**c_void, addrs.ptr),
109 null,
110 );
111 return;
112 };
113 var addr_buf_stack: [32]usize = undefined;
114 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
115 const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
116 const first_index = for (addr_buf[0..n]) |addr, i| {
117 if (addr == first_addr) {
118 break i;
119 }
120 } else {
121 stack_trace.index = 0;
122 return;
123 };
124 const slice = addr_buf[first_index..n];
125 // We use a for loop here because slice and addrs may alias.
126 for (slice) |addr, i| {
127 addrs[i] = addr;
128 }
129 stack_trace.index = slice.len;
130 },
131 else => {
132 var it = StackIterator.init(first_address);
133 for (stack_trace.instruction_addresses) |*addr, i| {
134 addr.* = it.next() orelse {
135 stack_trace.index = i;
136 return;
137 };
138 }
139 stack_trace.index = stack_trace.instruction_addresses.len;
140 },
141 }
142}
143
93/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.144/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
94/// TODO multithreaded awareness145/// TODO multithreaded awareness
95pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void {146pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
96 const stderr = getStderrStream() catch return;147 const stderr = getStderrStream() catch return;
97 const debug_info = getSelfDebugInfo() catch |err| {148 const debug_info = getSelfDebugInfo() catch |err| {
98 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;149 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
...@@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c...@@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
141 const stderr = getStderrStream() catch os.abort();192 const stderr = getStderrStream() catch os.abort();
142 stderr.print(format ++ "\n", args) catch os.abort();193 stderr.print(format ++ "\n", args) catch os.abort();
143 if (trace) |t| {194 if (trace) |t| {
144 dumpStackTrace(t);195 dumpStackTrace(t.*);
145 }196 }
146 dumpCurrentStackTrace(first_trace_addr);197 dumpCurrentStackTrace(first_trace_addr);
147198
...@@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";...@@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m";
155const DIM = "\x1b[2m";206const DIM = "\x1b[2m";
156const RESET = "\x1b[0m";207const RESET = "\x1b[0m";
157208
158pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void {209pub fn writeStackTrace(
159 var frame_index: usize = undefined;210 stack_trace: builtin.StackTrace,
160 var frames_left: usize = undefined;211 out_stream: var,
161 if (stack_trace.index < stack_trace.instruction_addresses.len) {212 allocator: *mem.Allocator,
162 frame_index = 0;213 debug_info: *DebugInfo,
163 frames_left = stack_trace.index;214 tty_color: bool,
164 } else {215) !void {
165 frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len;216 var frame_index: usize = 0;
166 frames_left = stack_trace.instruction_addresses.len;217 var frames_left: usize = stack_trace.index;
167 }
168218
169 while (frames_left != 0) : ({219 while (frames_left != 0) : ({
170 frames_left -= 1;220 frames_left -= 1;
std/special/bootstrap.zig+7-4
...@@ -23,8 +23,8 @@ nakedcc fn _start() noreturn {...@@ -23,8 +23,8 @@ nakedcc fn _start() noreturn {
23 switch (builtin.arch) {23 switch (builtin.arch) {
24 builtin.Arch.x86_64 => {24 builtin.Arch.x86_64 => {
25 argc_ptr = asm ("lea (%%rsp), %[argc]"25 argc_ptr = asm ("lea (%%rsp), %[argc]"
26 : [argc] "=r" (-> [*]usize)26 : [argc] "=r" (-> [*]usize)
27 );27 );
28 },28 },
29 builtin.Arch.i386 => {29 builtin.Arch.i386 => {
30 argc_ptr = asm ("lea (%%esp), %[argc]"30 argc_ptr = asm ("lea (%%esp), %[argc]"
...@@ -123,7 +123,7 @@ inline fn callMain() u8 {...@@ -123,7 +123,7 @@ inline fn callMain() u8 {
123 std.debug.warn("error: {}\n", @errorName(err));123 std.debug.warn("error: {}\n", @errorName(err));
124 if (builtin.os != builtin.Os.zen) {124 if (builtin.os != builtin.Os.zen) {
125 if (@errorReturnTrace()) |trace| {125 if (@errorReturnTrace()) |trace| {
126 std.debug.dumpStackTrace(trace);126 std.debug.dumpStackTrace(trace.*);
127 }127 }
128 }128 }
129 return 1;129 return 1;
...@@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:...@@ -142,7 +142,10 @@ fn linuxInitializeThreadLocalStorage(at_phdr: usize, at_phnum: usize, at_phent:
142 var phdr_addr = at_phdr;142 var phdr_addr = at_phdr;
143 var n = at_phnum;143 var n = at_phnum;
144 var base: usize = 0;144 var base: usize = 0;
145 while (n != 0) : ({n -= 1; phdr_addr += at_phent;}) {145 while (n != 0) : ({
146 n -= 1;
147 phdr_addr += at_phent;
148 }) {
146 const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);149 const phdr = @intToPtr(*std.elf.Phdr, phdr_addr);
147 // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917150 // TODO look for PT_DYNAMIC when we have https://github.com/ziglang/zig/issues/1917
148 switch (phdr.p_type) {151 switch (phdr.p_type) {