authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-09 22:06:24-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-10 01:38:40-05:00
log60b2031831320186f3920d63cfa35bda40930450
tree1c09db35eab1d6bac66db99f02a891811da230c3
parent20011a7a1c1f08644cd82a3c3e1d57cba9980695

improvements to stack traces

* @panic generates an error return trace * printing an error return trace no longer interferes with normal stack traces. * instead of ignore_frame_count, we look at the return address when you call panic, and that's the first stack trace function makes stack traces much cleaner - the error return trace flows gracefully into the stack trace

3 files changed, 34 insertions(+), 14 deletions(-)

src/codegen.cpp+2-2
...@@ -3299,8 +3299,8 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -3299,8 +3299,8 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
3299static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,3299static LLVMValueRef ir_render_error_return_trace(CodeGen *g, IrExecutable *executable,
3300 IrInstructionErrorReturnTrace *instruction)3300 IrInstructionErrorReturnTrace *instruction)
3301{3301{
3302 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3303 if (g->cur_err_ret_trace_val == nullptr) {3302 if (g->cur_err_ret_trace_val == nullptr) {
3303 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(g);
3304 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);3304 return LLVMConstNull(ptr_to_stack_trace_type->type_ref);
3305 }3305 }
3306 return g->cur_err_ret_trace_val;3306 return g->cur_err_ret_trace_val;
...@@ -3925,7 +3925,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec...@@ -3925,7 +3925,7 @@ static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *exec
3925}3925}
39263926
3927static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {3927static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
3928 gen_panic(g, ir_llvm_value(g, instruction->msg), nullptr);3928 gen_panic(g, ir_llvm_value(g, instruction->msg), g->cur_err_ret_trace_val);
3929 return nullptr;3929 return nullptr;
3930}3930}
39313931
std/debug/index.zig+29-10
...@@ -9,6 +9,7 @@ const macho = std.macho;...@@ -9,6 +9,7 @@ const macho = std.macho;
9const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
10const builtin = @import("builtin");10const builtin = @import("builtin");
1111
12pub var stack_trace_start_address: ?usize = null;
12pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;13pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1314
14/// Tries to write to stderr, unbuffered, and ignores any error returned.15/// Tries to write to stderr, unbuffered, and ignores any error returned.
...@@ -51,8 +52,7 @@ pub fn dumpCurrentStackTrace() void {...@@ -51,8 +52,7 @@ pub fn dumpCurrentStackTrace() void {
51 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;52 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
52 return;53 return;
53 };54 };
54 defer debug_info.close();55 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
55 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), 1) catch |err| {
56 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;56 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
57 return;57 return;
58 };58 };
...@@ -65,7 +65,6 @@ pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) void {...@@ -65,7 +65,6 @@ pub fn dumpStackTrace(stack_trace: &const builtin.StackTrace) void {
65 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;65 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
66 return;66 return;
67 };67 };
68 defer debug_info.close();
69 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {68 writeStackTrace(stack_trace, stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {
70 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;69 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
71 return;70 return;
...@@ -162,18 +161,38 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,...@@ -162,18 +161,38 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
162}161}
163162
164pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,163pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
165 debug_info: &ElfStackTrace, tty_color: bool, ignore_frame_count: usize) !void164 debug_info: &ElfStackTrace, tty_color: bool) !void
166{165{
167 var ignored_count: usize = 0;166 const AddressState = union(enum) {
167 NotLookingForStartAddress,
168 LookingForStartAddress: usize,
169 FoundStartAddress,
170 };
171 // TODO: I want to express like this:
172 //var addr_state = if (stack_trace_start_address) |addr| AddressState { .LookingForStartAddress = addr }
173 // else AddressState.NotLookingForStartAddress;
174 var addr_state: AddressState = undefined;
175 if (stack_trace_start_address) |addr| {
176 addr_state = AddressState { .LookingForStartAddress = addr };
177 } else {
178 addr_state = AddressState.NotLookingForStartAddress;
179 }
168180
169 var fp = @ptrToInt(@frameAddress());181 var fp = @ptrToInt(@frameAddress());
170 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {182 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
171 if (ignored_count < ignore_frame_count) {
172 ignored_count += 1;
173 continue;
174 }
175
176 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));183 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
184
185 switch (addr_state) {
186 AddressState.NotLookingForStartAddress => continue,
187 AddressState.LookingForStartAddress => |addr| {
188 if (return_address == addr) {
189 addr_state = AddressState.FoundStartAddress;
190 } else {
191 continue;
192 }
193 },
194 AddressState.FoundStartAddress => {},
195 }
177 try printSourceAtAddress(debug_info, out_stream, return_address);196 try printSourceAtAddress(debug_info, out_stream, return_address);
178 }197 }
179}198}
std/special/panic.zig+3-2
...@@ -14,10 +14,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn...@@ -14,10 +14,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn
14 while (true) {}14 while (true) {}
15 },15 },
16 else => {16 else => {
17 std.debug.stack_trace_start_address = @ptrToInt(@returnAddress());
17 if (error_return_trace) |trace| {18 if (error_return_trace) |trace| {
18 @import("std").debug.panicWithTrace(trace, "{}", msg);19 std.debug.panicWithTrace(trace, "{}", msg);
19 }20 }
20 @import("std").debug.panic("{}", msg);21 std.debug.panic("{}", msg);
21 },22 },
22 }23 }
23}24}