| ... | @@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | ... | @@ -90,9 +90,60 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void { |
| 90 | }; | 90 | }; |
| 91 | } | 91 | } |
| 92 | | 92 | |
| | 93 | /// Returns a slice with the same pointer as addresses, with a potentially smaller len. |
| | 94 | /// On Windows, when first_address is not null, we ask for at least 32 stack frames, |
| | 95 | /// and then try to find the first address. If addresses.len is more than 32, we |
| | 96 | /// capture that many stack frames exactly, and then look for the first address, |
| | 97 | /// chopping off the irrelevant frames and shifting so that the returned addresses pointer |
| | 98 | /// equals the passed in addresses pointer. |
| | 99 | pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { |
| | 100 | switch (builtin.os) { |
| | 101 | builtin.Os.windows => { |
| | 102 | const addrs = stack_trace.instruction_addresses; |
| | 103 | const u32_addrs_len = @intCast(u32, addrs.len); |
| | 104 | const first_addr = first_address orelse { |
| | 105 | stack_trace.index = windows.RtlCaptureStackBackTrace( |
| | 106 | 0, |
| | 107 | u32_addrs_len, |
| | 108 | @ptrCast(**c_void, addrs.ptr), |
| | 109 | null, |
| | 110 | ); |
| | 111 | return; |
| | 112 | }; |
| | 113 | var addr_buf_stack: [32]usize = undefined; |
| | 114 | const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs; |
| | 115 | const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null); |
| | 116 | const first_index = for (addr_buf[0..n]) |addr, i| { |
| | 117 | if (addr == first_addr) { |
| | 118 | break i; |
| | 119 | } |
| | 120 | } else { |
| | 121 | stack_trace.index = 0; |
| | 122 | return; |
| | 123 | }; |
| | 124 | const slice = addr_buf[first_index..n]; |
| | 125 | // We use a for loop here because slice and addrs may alias. |
| | 126 | for (slice) |addr, i| { |
| | 127 | addrs[i] = addr; |
| | 128 | } |
| | 129 | stack_trace.index = slice.len; |
| | 130 | }, |
| | 131 | else => { |
| | 132 | var it = StackIterator.init(first_address); |
| | 133 | for (stack_trace.instruction_addresses) |*addr, i| { |
| | 134 | addr.* = it.next() orelse { |
| | 135 | stack_trace.index = i; |
| | 136 | return; |
| | 137 | }; |
| | 138 | } |
| | 139 | stack_trace.index = stack_trace.instruction_addresses.len; |
| | 140 | }, |
| | 141 | } |
| | 142 | } |
| | 143 | |
| 93 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. | 144 | /// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned. |
| 94 | /// TODO multithreaded awareness | 145 | /// TODO multithreaded awareness |
| 95 | pub fn dumpStackTrace(stack_trace: *const builtin.StackTrace) void { | 146 | pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void { |
| 96 | const stderr = getStderrStream() catch return; | 147 | const stderr = getStderrStream() catch return; |
| 97 | const debug_info = getSelfDebugInfo() catch |err| { | 148 | const debug_info = getSelfDebugInfo() catch |err| { |
| 98 | stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return; | 149 | stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return; |
| ... | @@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c | ... | @@ -141,7 +192,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c |
| 141 | const stderr = getStderrStream() catch os.abort(); | 192 | const stderr = getStderrStream() catch os.abort(); |
| 142 | stderr.print(format ++ "\n", args) catch os.abort(); | 193 | stderr.print(format ++ "\n", args) catch os.abort(); |
| 143 | if (trace) |t| { | 194 | if (trace) |t| { |
| 144 | dumpStackTrace(t); | 195 | dumpStackTrace(t.*); |
| 145 | } | 196 | } |
| 146 | dumpCurrentStackTrace(first_trace_addr); | 197 | dumpCurrentStackTrace(first_trace_addr); |
| 147 | | 198 | |
| ... | @@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m"; | ... | @@ -155,16 +206,15 @@ const WHITE = "\x1b[37;1m"; |
| 155 | const DIM = "\x1b[2m"; | 206 | const DIM = "\x1b[2m"; |
| 156 | const RESET = "\x1b[0m"; | 207 | const RESET = "\x1b[0m"; |
| 157 | | 208 | |
| 158 | pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, allocator: *mem.Allocator, debug_info: *DebugInfo, tty_color: bool) !void { | 209 | pub fn writeStackTrace( |
| 159 | var frame_index: usize = undefined; | 210 | stack_trace: builtin.StackTrace, |
| 160 | var frames_left: usize = undefined; | 211 | out_stream: var, |
| 161 | if (stack_trace.index < stack_trace.instruction_addresses.len) { | 212 | allocator: *mem.Allocator, |
| 162 | frame_index = 0; | 213 | debug_info: *DebugInfo, |
| 163 | frames_left = stack_trace.index; | 214 | tty_color: bool, |
| 164 | } else { | 215 | ) !void { |
| 165 | frame_index = (stack_trace.index + 1) % stack_trace.instruction_addresses.len; | 216 | var frame_index: usize = 0; |
| 166 | frames_left = stack_trace.instruction_addresses.len; | 217 | var frames_left: usize = stack_trace.index; |
| 167 | } | | |
| 168 | | 218 | |
| 169 | while (frames_left != 0) : ({ | 219 | while (frames_left != 0) : ({ |
| 170 | frames_left -= 1; | 220 | frames_left -= 1; |