| ... | @@ -9,7 +9,6 @@ const macho = std.macho; | ... | @@ -9,7 +9,6 @@ const macho = std.macho; |
| 9 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 10 | const builtin = @import("builtin"); | 10 | const builtin = @import("builtin"); |
| 11 | | 11 | |
| 12 | pub var stack_trace_start_address: ?usize = null; | | |
| 13 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; | 12 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; |
| 14 | | 13 | |
| 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 | } |
| 47 | | 46 | |
| 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. |
| 49 | pub fn dumpCurrentStackTrace() void { | 48 | pub 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 | } |
| 99 | | 98 | |
| 100 | var panicking: u8 = 0; // TODO make this a bool | | |
| 101 | /// This is the default panic implementation. | | |
| 102 | pub fn panic(comptime format: []const u8, args: ...) noreturn { | 99 | pub 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 | |
| | 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 | 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| { |
| 117 | | 123 | dumpStackTrace(t); |
| 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(); | | |
| 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(); | | |
| 132 | | 126 | |
| 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 | } |
| 162 | | 156 | |
| 163 | pub fn writeCurrentStackTrace(out_stream: var, allocator: &mem.Allocator, | 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 | 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)); |
| 184 | | 177 | |
| 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 | } |