authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-09 22:21:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-10 01:38:40-05:00
log3b3649b86f74d08013b669a6a4eac573f8d7fa23
tree751c3abd5d2f5be50b3305b6489ee36297b69db6
parent60b2031831320186f3920d63cfa35bda40930450

refactor stack trace code to remove global state


2 files changed, 22 insertions(+), 33 deletions(-)

std/debug/index.zig+20-28
...@@ -9,7 +9,6 @@ const macho = std.macho;...@@ -9,7 +9,6 @@ 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;
13pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;12pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
1413
15/// Tries to write to stderr, unbuffered, and ignores any error returned.14/// Tries to write to stderr, unbuffered, and ignores any error returned.
...@@ -46,13 +45,13 @@ pub fn getSelfDebugInfo() !&ElfStackTrace {...@@ -46,13 +45,13 @@ pub fn getSelfDebugInfo() !&ElfStackTrace {
46}45}
4746
48/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.47/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
49pub fn dumpCurrentStackTrace() void {48pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
50 const stderr = getStderrStream() catch return;49 const stderr = getStderrStream() catch return;
51 const debug_info = getSelfDebugInfo() catch |err| {50 const debug_info = getSelfDebugInfo() catch |err| {
52 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;51 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
53 return;52 return;
54 };53 };
55 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| {54 writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), start_addr) catch |err| {
56 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;55 stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return;
57 return;56 return;
58 };57 };
...@@ -97,10 +96,18 @@ pub fn assertOrPanic(ok: bool) void {...@@ -97,10 +96,18 @@ pub fn assertOrPanic(ok: bool) void {
97 }96 }
98}97}
9998
100var panicking: u8 = 0; // TODO make this a bool
101/// This is the default panic implementation.
102pub fn panic(comptime format: []const u8, args: ...) noreturn {99pub fn panic(comptime format: []const u8, args: ...) noreturn {
103 @setCold(true);100 @setCold(true);
101 const first_trace_addr = @ptrToInt(@returnAddress());
102 panicExtra(null, first_trace_addr, format, args);
103}
104
105var panicking: u8 = 0; // TODO make this a bool
106
107pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize,
108 comptime format: []const u8, args: ...) noreturn
109{
110 @setCold(true);
104111
105 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {112 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
106 // Panicked during a panic.113 // Panicked during a panic.
...@@ -110,25 +117,12 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {...@@ -110,25 +117,12 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn {
110 // which first called panic can finish printing a stack trace.117 // which first called panic can finish printing a stack trace.
111 os.abort();118 os.abort();
112 }119 }
113
114 const stderr = getStderrStream() catch os.abort();120 const stderr = getStderrStream() catch os.abort();
115 stderr.print(format ++ "\n", args) catch os.abort();121 stderr.print(format ++ "\n", args) catch os.abort();
116 dumpCurrentStackTrace();122 if (trace) |t| {
117123 dumpStackTrace(t);
118 os.abort();
119}
120
121pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) noreturn {
122 @setCold(true);
123
124 if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) {
125 // See TODO in above function
126 os.abort();
127 }124 }
128 const stderr = getStderrStream() catch os.abort();125 dumpCurrentStackTrace(first_trace_addr);
129 stderr.print(format ++ "\n", args) catch os.abort();
130 dumpStackTrace(trace);
131 dumpCurrentStackTrace();
132126
133 os.abort();127 os.abort();
134}128}
...@@ -161,18 +155,17 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,...@@ -161,18 +155,17 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var,
161}155}
162156
163pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,157pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
164 debug_info: &ElfStackTrace, tty_color: bool) !void158 debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void
165{159{
166 const AddressState = union(enum) {160 const AddressState = union(enum) {
167 NotLookingForStartAddress,161 NotLookingForStartAddress,
168 LookingForStartAddress: usize,162 LookingForStartAddress: usize,
169 FoundStartAddress,
170 };163 };
171 // TODO: I want to express like this:164 // TODO: I want to express like this:
172 //var addr_state = if (stack_trace_start_address) |addr| AddressState { .LookingForStartAddress = addr }165 //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr }
173 // else AddressState.NotLookingForStartAddress;166 // else AddressState.NotLookingForStartAddress;
174 var addr_state: AddressState = undefined;167 var addr_state: AddressState = undefined;
175 if (stack_trace_start_address) |addr| {168 if (start_addr) |addr| {
176 addr_state = AddressState { .LookingForStartAddress = addr };169 addr_state = AddressState { .LookingForStartAddress = addr };
177 } else {170 } else {
178 addr_state = AddressState.NotLookingForStartAddress;171 addr_state = AddressState.NotLookingForStartAddress;
...@@ -183,15 +176,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,...@@ -183,15 +176,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator,
183 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));176 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
184177
185 switch (addr_state) {178 switch (addr_state) {
186 AddressState.NotLookingForStartAddress => continue,179 AddressState.NotLookingForStartAddress => {},
187 AddressState.LookingForStartAddress => |addr| {180 AddressState.LookingForStartAddress => |addr| {
188 if (return_address == addr) {181 if (return_address == addr) {
189 addr_state = AddressState.FoundStartAddress;182 addr_state = AddressState.NotLookingForStartAddress;
190 } else {183 } else {
191 continue;184 continue;
192 }185 }
193 },186 },
194 AddressState.FoundStartAddress => {},
195 }187 }
196 try printSourceAtAddress(debug_info, out_stream, return_address);188 try printSourceAtAddress(debug_info, out_stream, return_address);
197 }189 }
std/special/panic.zig+2-5
...@@ -14,11 +14,8 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn...@@ -14,11 +14,8 @@ 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 const first_trace_addr = @ptrToInt(@returnAddress());
18 if (error_return_trace) |trace| {18 std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
19 std.debug.panicWithTrace(trace, "{}", msg);
20 }
21 std.debug.panic("{}", msg);
22 },19 },
23 }20 }
24}21}