| ... | @@ -130,13 +130,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { | ... | @@ -130,13 +130,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { |
| 130 | }; | 130 | }; |
| 131 | const tty_config = detectTTYConfig(); | 131 | const tty_config = detectTTYConfig(); |
| 132 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; | 132 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; |
| 133 | const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; | 133 | var it = StackIterator.init(null, bp); |
| 134 | if (first_return_address == 0) return; // The whole call stack may be optimized out | | |
| 135 | printSourceAtAddress(debug_info, stderr, first_return_address - 1, tty_config) catch return; | | |
| 136 | var it = StackIterator{ | | |
| 137 | .first_addr = null, | | |
| 138 | .fp = bp, | | |
| 139 | }; | | |
| 140 | while (it.next()) |return_address| { | 134 | while (it.next()) |return_address| { |
| 141 | printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return; | 135 | printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return; |
| 142 | } | 136 | } |
| ... | @@ -179,7 +173,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace | ... | @@ -179,7 +173,7 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace |
| 179 | } | 173 | } |
| 180 | stack_trace.index = slice.len; | 174 | stack_trace.index = slice.len; |
| 181 | } else { | 175 | } else { |
| 182 | var it = StackIterator.init(first_address); | 176 | var it = StackIterator.init(first_address, null); |
| 183 | for (stack_trace.instruction_addresses) |*addr, i| { | 177 | for (stack_trace.instruction_addresses) |*addr, i| { |
| 184 | addr.* = it.next() orelse { | 178 | addr.* = it.next() orelse { |
| 185 | stack_trace.index = i; | 179 | stack_trace.index = i; |
| ... | @@ -291,13 +285,15 @@ pub fn writeStackTrace( | ... | @@ -291,13 +285,15 @@ pub fn writeStackTrace( |
| 291 | } | 285 | } |
| 292 | | 286 | |
| 293 | pub const StackIterator = struct { | 287 | pub const StackIterator = struct { |
| 294 | first_addr: ?usize, | 288 | // Skip every frame before this address is found |
| | 289 | first_address: ?usize, |
| | 290 | // Last known value of the frame pointer register |
| 295 | fp: usize, | 291 | fp: usize, |
| 296 | | 292 | |
| 297 | pub fn init(first_addr: ?usize) StackIterator { | 293 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| 298 | return StackIterator{ | 294 | return StackIterator{ |
| 299 | .first_addr = first_addr, | 295 | .first_address = first_address, |
| 300 | .fp = @frameAddress(), | 296 | .fp = fp orelse @frameAddress(), |
| 301 | }; | 297 | }; |
| 302 | } | 298 | } |
| 303 | | 299 | |
| ... | @@ -305,29 +301,45 @@ pub const StackIterator = struct { | ... | @@ -305,29 +301,45 @@ pub const StackIterator = struct { |
| 305 | // the previous fp is stored, while on some other architectures such as | 301 | // the previous fp is stored, while on some other architectures such as |
| 306 | // RISC-V it points to the "top" of the frame, just above where the previous | 302 | // RISC-V it points to the "top" of the frame, just above where the previous |
| 307 | // fp and the return address are stored. | 303 | // fp and the return address are stored. |
| 308 | const fp_adjust_factor = if (builtin.arch == .riscv32 or builtin.arch == .riscv64) | 304 | const fp_offset = if (builtin.arch.isRISCV()) |
| 309 | 2 * @sizeOf(usize) | 305 | 2 * @sizeOf(usize) |
| 310 | else | 306 | else |
| 311 | 0; | 307 | 0; |
| 312 | | 308 | |
| 313 | fn next(self: *StackIterator) ?usize { | 309 | fn next(self: *StackIterator) ?usize { |
| 314 | if (self.fp <= fp_adjust_factor) return null; | 310 | var address = self.next_internal() orelse return null; |
| 315 | self.fp = @intToPtr(*const usize, self.fp - fp_adjust_factor).*; | 311 | |
| 316 | if (self.fp <= fp_adjust_factor) return null; | 312 | if (self.first_address) |first_address| { |
| 317 | | 313 | while (address != first_address) { |
| 318 | if (self.first_addr) |addr| { | 314 | address = self.next_internal() orelse return null; |
| 319 | while (self.fp > fp_adjust_factor) : (self.fp = @intToPtr(*const usize, self.fp - fp_adjust_factor).*) { | | |
| 320 | const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*; | | |
| 321 | if (addr == return_address) { | | |
| 322 | self.first_addr = null; | | |
| 323 | return return_address; | | |
| 324 | } | | |
| 325 | } | 315 | } |
| | 316 | self.first_address = null; |
| 326 | } | 317 | } |
| 327 | | 318 | |
| 328 | const return_address = @intToPtr(*const usize, self.fp - fp_adjust_factor + @sizeOf(usize)).*; | 319 | return address; |
| 329 | if (return_address == 0) return null; | 320 | } |
| 330 | return return_address; | 321 | |
| | 322 | fn next_internal(self: *StackIterator) ?usize { |
| | 323 | const fp = math.sub(usize, self.fp, fp_offset) catch return null; |
| | 324 | |
| | 325 | // Sanity check |
| | 326 | if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) |
| | 327 | return null; |
| | 328 | |
| | 329 | const new_fp = @intToPtr(*const usize, fp).*; |
| | 330 | |
| | 331 | // Sanity check: the stack grows down thus all the parent frames must be |
| | 332 | // be at addresses that are greater (or equal) than the previous one. |
| | 333 | // A zero frame pointer often signals this is the last frame, that case |
| | 334 | // is gracefully handled by the next call to next_internal |
| | 335 | if (new_fp != 0 and new_fp < self.fp) |
| | 336 | return null; |
| | 337 | |
| | 338 | const new_pc = @intToPtr(*const usize, fp + @sizeOf(usize)).*; |
| | 339 | |
| | 340 | self.fp = new_fp; |
| | 341 | |
| | 342 | return new_pc; |
| 331 | } | 343 | } |
| 332 | }; | 344 | }; |
| 333 | | 345 | |
| ... | @@ -340,7 +352,7 @@ pub fn writeCurrentStackTrace( | ... | @@ -340,7 +352,7 @@ pub fn writeCurrentStackTrace( |
| 340 | if (builtin.os == .windows) { | 352 | if (builtin.os == .windows) { |
| 341 | return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr); | 353 | return writeCurrentStackTraceWindows(out_stream, debug_info, tty_config, start_addr); |
| 342 | } | 354 | } |
| 343 | var it = StackIterator.init(start_addr); | 355 | var it = StackIterator.init(start_addr, null); |
| 344 | while (it.next()) |return_address| { | 356 | while (it.next()) |return_address| { |
| 345 | try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); | 357 | try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); |
| 346 | } | 358 | } |