From 3b3649b86f74d08013b669a6a4eac573f8d7fa23 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 9 Mar 2018 22:21:13 -0500 Subject: [PATCH] refactor stack trace code to remove global state --- std/debug/index.zig | 48 ++++++++++++++++++------------------------- std/special/panic.zig | 7 ++----- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/std/debug/index.zig b/std/debug/index.zig index b20b8f6e5e..a573dc5549 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -9,7 +9,6 @@ const macho = std.macho; const ArrayList = std.ArrayList; const builtin = @import("builtin"); -pub var stack_trace_start_address: ?usize = null; pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; /// Tries to write to stderr, unbuffered, and ignores any error returned. @@ -46,13 +45,13 @@ pub fn getSelfDebugInfo() !&ElfStackTrace { } /// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned. -pub fn dumpCurrentStackTrace() void { +pub fn dumpCurrentStackTrace(start_addr: ?usize) 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; return; }; - writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty()) catch |err| { + writeCurrentStackTrace(stderr, global_allocator, debug_info, stderr_file.isTty(), start_addr) catch |err| { stderr.print("Unable to dump stack trace: {}\n", @errorName(err)) catch return; return; }; @@ -97,10 +96,18 @@ pub fn assertOrPanic(ok: bool) void { } } -var panicking: u8 = 0; // TODO make this a bool -/// This is the default panic implementation. pub fn panic(comptime format: []const u8, args: ...) noreturn { @setCold(true); + const first_trace_addr = @ptrToInt(@returnAddress()); + panicExtra(null, first_trace_addr, format, args); +} + +var panicking: u8 = 0; // TODO make this a bool + +pub fn panicExtra(trace: ?&const builtin.StackTrace, first_trace_addr: ?usize, + comptime format: []const u8, args: ...) noreturn +{ + @setCold(true); if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) { // Panicked during a panic. @@ -110,25 +117,12 @@ pub fn panic(comptime format: []const u8, args: ...) noreturn { // which first called panic can finish printing a stack trace. os.abort(); } - const stderr = getStderrStream() catch os.abort(); stderr.print(format ++ "\n", args) catch os.abort(); - dumpCurrentStackTrace(); - - os.abort(); -} - -pub fn panicWithTrace(trace: &const builtin.StackTrace, comptime format: []const u8, args: ...) noreturn { - @setCold(true); - - if (@atomicRmw(u8, &panicking, builtin.AtomicRmwOp.Xchg, 1, builtin.AtomicOrder.SeqCst) == 1) { - // See TODO in above function - os.abort(); + if (trace) |t| { + dumpStackTrace(t); } - const stderr = getStderrStream() catch os.abort(); - stderr.print(format ++ "\n", args) catch os.abort(); - dumpStackTrace(trace); - dumpCurrentStackTrace(); + dumpCurrentStackTrace(first_trace_addr); os.abort(); } @@ -161,18 +155,17 @@ pub fn writeStackTrace(stack_trace: &const builtin.StackTrace, out_stream: var, } pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, - debug_info: &ElfStackTrace, tty_color: bool) !void + debug_info: &ElfStackTrace, tty_color: bool, start_addr: ?usize) !void { const AddressState = union(enum) { NotLookingForStartAddress, LookingForStartAddress: usize, - FoundStartAddress, }; // TODO: I want to express like this: - //var addr_state = if (stack_trace_start_address) |addr| AddressState { .LookingForStartAddress = addr } + //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr } // else AddressState.NotLookingForStartAddress; var addr_state: AddressState = undefined; - if (stack_trace_start_address) |addr| { + if (start_addr) |addr| { addr_state = AddressState { .LookingForStartAddress = addr }; } else { addr_state = AddressState.NotLookingForStartAddress; @@ -183,15 +176,14 @@ pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize)); switch (addr_state) { - AddressState.NotLookingForStartAddress => continue, + AddressState.NotLookingForStartAddress => {}, AddressState.LookingForStartAddress => |addr| { if (return_address == addr) { - addr_state = AddressState.FoundStartAddress; + addr_state = AddressState.NotLookingForStartAddress; } else { continue; } }, - AddressState.FoundStartAddress => {}, } try printSourceAtAddress(debug_info, out_stream, return_address); } diff --git a/std/special/panic.zig b/std/special/panic.zig index 4459382f9b..8f933ddd97 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -14,11 +14,8 @@ pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn while (true) {} }, else => { - std.debug.stack_trace_start_address = @ptrToInt(@returnAddress()); - if (error_return_trace) |trace| { - std.debug.panicWithTrace(trace, "{}", msg); - } - std.debug.panic("{}", msg); + const first_trace_addr = @ptrToInt(@returnAddress()); + std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); }, } }