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