| ... | ... | @@ -130,13 +130,7 @@ pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void { |
| 130 | 130 | }; |
| 131 | 131 | const tty_config = detectTTYConfig(); |
| 132 | 132 | printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return; |
| 133 | | const first_return_address = @intToPtr(*const usize, bp + @sizeOf(usize)).*; |
| 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 | | }; |
| 133 | var it = StackIterator.init(null, bp); |
| 140 | 134 | while (it.next()) |return_address| { |
| 141 | 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 | 173 | } |
| 180 | 174 | stack_trace.index = slice.len; |
| 181 | 175 | } else { |
| 182 | | var it = StackIterator.init(first_address); |
| 176 | var it = StackIterator.init(first_address, null); |
| 183 | 177 | for (stack_trace.instruction_addresses) |*addr, i| { |
| 184 | 178 | addr.* = it.next() orelse { |
| 185 | 179 | stack_trace.index = i; |
| ... | ... | @@ -291,13 +285,15 @@ pub fn writeStackTrace( |
| 291 | 285 | } |
| 292 | 286 | |
| 293 | 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 | 291 | fp: usize, |
| 296 | 292 | |
| 297 | | pub fn init(first_addr: ?usize) StackIterator { |
| 293 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| 298 | 294 | return StackIterator{ |
| 299 | | .first_addr = first_addr, |
| 300 | | .fp = @frameAddress(), |
| 295 | .first_address = first_address, |
| 296 | .fp = fp orelse @frameAddress(), |
| 301 | 297 | }; |
| 302 | 298 | } |
| 303 | 299 | |
| ... | ... | @@ -305,29 +301,45 @@ pub const StackIterator = struct { |
| 305 | 301 | // the previous fp is stored, while on some other architectures such as |
| 306 | 302 | // RISC-V it points to the "top" of the frame, just above where the previous |
| 307 | 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 | 305 | 2 * @sizeOf(usize) |
| 310 | 306 | else |
| 311 | 307 | 0; |
| 312 | 308 | |
| 313 | 309 | fn next(self: *StackIterator) ?usize { |
| 314 | | if (self.fp <= fp_adjust_factor) return null; |
| 315 | | self.fp = @intToPtr(*const usize, self.fp - fp_adjust_factor).*; |
| 316 | | if (self.fp <= fp_adjust_factor) return null; |
| 317 | | |
| 318 | | if (self.first_addr) |addr| { |
| 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 | | } |
| 310 | var address = self.next_internal() orelse return null; |
| 311 | |
| 312 | if (self.first_address) |first_address| { |
| 313 | while (address != first_address) { |
| 314 | address = self.next_internal() orelse return null; |
| 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)).*; |
| 329 | | if (return_address == 0) return null; |
| 330 | | return return_address; |
| 319 | return address; |
| 320 | } |
| 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 | 352 | if (builtin.os == .windows) { |
| 341 | 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 | 356 | while (it.next()) |return_address| { |
| 345 | 357 | try printSourceAtAddress(debug_info, out_stream, return_address - 1, tty_config); |
| 346 | 358 | } |