| ... | @@ -626,7 +626,11 @@ pub const StackUnwindOptions = struct { | ... | @@ -626,7 +626,11 @@ pub const StackUnwindOptions = struct { |
| 626 | /// | 626 | /// |
| 627 | /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. | 627 | /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. |
| 628 | pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { | 628 | pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) StackTrace { |
| 629 | const empty_trace: StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; | 629 | const empty_trace: StackTrace = .{ |
| | 630 | .index = 0, |
| | 631 | .instruction_addresses = &.{}, |
| | 632 | .includes_inlined_frames = false, |
| | 633 | }; |
| 630 | if (!std.options.allow_stack_tracing) return empty_trace; | 634 | if (!std.options.allow_stack_tracing) return empty_trace; |
| 631 | var it: StackIterator = .init(options.context); | 635 | var it: StackIterator = .init(options.context); |
| 632 | defer it.deinit(); | 636 | defer it.deinit(); |
| ... | @@ -661,6 +665,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: | ... | @@ -661,6 +665,7 @@ pub noinline fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: |
| 661 | return .{ | 665 | return .{ |
| 662 | .index = index, | 666 | .index = index, |
| 663 | .instruction_addresses = addr_buf[0..index], | 667 | .instruction_addresses = addr_buf[0..index], |
| | 668 | .includes_inlined_frames = false, |
| 664 | }; | 669 | }; |
| 665 | } | 670 | } |
| 666 | /// Write the current stack trace to `writer`, annotated with source locations. | 671 | /// Write the current stack trace to `writer`, annotated with source locations. |
| ... | @@ -745,7 +750,10 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin | ... | @@ -745,7 +750,10 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, t: Io.Termin |
| 745 | } | 750 | } |
| 746 | // `ret_addr` is the return address, which is *after* the function call. | 751 | // `ret_addr` is the return address, which is *after* the function call. |
| 747 | // Subtract 1 to get an address *in* the function call for a better source location. | 752 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 748 | try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); | 753 | try printSourceAtAddress(io, di, t, .{ |
| | 754 | .address = ret_addr -| StackIterator.ra_call_offset, |
| | 755 | .print_inlines = true, |
| | 756 | }); |
| 749 | printed_any_frame = true; | 757 | printed_any_frame = true; |
| 750 | }, | 758 | }, |
| 751 | }; | 759 | }; |
| ... | @@ -805,7 +813,10 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void | ... | @@ -805,7 +813,10 @@ pub fn writeStackTrace(st: *const StackTrace, t: Io.Terminal) Writer.Error!void |
| 805 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { | 813 | for (st.instruction_addresses[0..captured_frames]) |ret_addr| { |
| 806 | // `ret_addr` is the return address, which is *after* the function call. | 814 | // `ret_addr` is the return address, which is *after* the function call. |
| 807 | // Subtract 1 to get an address *in* the function call for a better source location. | 815 | // Subtract 1 to get an address *in* the function call for a better source location. |
| 808 | try printSourceAtAddress(io, di, t, ret_addr -| StackIterator.ra_call_offset); | 816 | try printSourceAtAddress(io, di, t, .{ |
| | 817 | .address = ret_addr -| StackIterator.ra_call_offset, |
| | 818 | .print_inlines = !st.includes_inlined_frames, |
| | 819 | }); |
| 809 | } | 820 | } |
| 810 | if (n_frames > captured_frames) { | 821 | if (n_frames > captured_frames) { |
| 811 | t.setColor(.bold) catch {}; | 822 | t.setColor(.bold) catch {}; |
| ... | @@ -1111,8 +1122,18 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { | ... | @@ -1111,8 +1122,18 @@ pub inline fn stripInstructionPtrAuthCode(ptr: usize) usize { |
| 1111 | return ptr; | 1122 | return ptr; |
| 1112 | } | 1123 | } |
| 1113 | | 1124 | |
| 1114 | fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: usize) Writer.Error!void { | 1125 | const PrintSourceAddressOptions = struct { |
| 1115 | var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, address); | 1126 | address: usize, |
| | 1127 | print_inlines: bool, |
| | 1128 | }; |
| | 1129 | |
| | 1130 | fn printSourceAtAddress( |
| | 1131 | io: Io, |
| | 1132 | debug_info: *SelfInfo, |
| | 1133 | t: Io.Terminal, |
| | 1134 | options: PrintSourceAddressOptions, |
| | 1135 | ) Writer.Error!void { |
| | 1136 | var symbols: SelfInfo.SymbolIterator = debug_info.getSymbols(io, options.address); |
| 1116 | defer symbols.deinit(io); | 1137 | defer symbols.deinit(io); |
| 1117 | while (symbols.next()) |curr| { | 1138 | while (symbols.next()) |curr| { |
| 1118 | const symbol: Symbol = curr catch |err| switch (err) { | 1139 | const symbol: Symbol = curr catch |err| switch (err) { |
| ... | @@ -1138,10 +1159,11 @@ fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: | ... | @@ -1138,10 +1159,11 @@ fn printSourceAtAddress(io: Io, debug_info: *SelfInfo, t: Io.Terminal, address: |
| 1138 | io, | 1159 | io, |
| 1139 | t, | 1160 | t, |
| 1140 | symbol.source_location, | 1161 | symbol.source_location, |
| 1141 | address, | 1162 | options.address, |
| 1142 | symbol.name orelse "???", | 1163 | symbol.name orelse "???", |
| 1143 | symbol.compile_unit_name orelse debug_info.getModuleName(io, address) catch "???", | 1164 | symbol.compile_unit_name orelse debug_info.getModuleName(io, options.address) catch "???", |
| 1144 | ); | 1165 | ); |
| | 1166 | if (!options.print_inlines) break; |
| 1145 | } | 1167 | } |
| 1146 | } | 1168 | } |
| 1147 | fn printLineInfo( | 1169 | fn printLineInfo( |
| ... | @@ -1608,7 +1630,10 @@ test "manage resources correctly" { | ... | @@ -1608,7 +1630,10 @@ test "manage resources correctly" { |
| 1608 | var di: SelfInfo = .init; | 1630 | var di: SelfInfo = .init; |
| 1609 | defer di.deinit(io); | 1631 | defer di.deinit(io); |
| 1610 | const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; | 1632 | const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color }; |
| 1611 | try printSourceAtAddress(io, &di, t, S.showMyTrace()); | 1633 | try printSourceAtAddress(io, &di, t, .{ |
| | 1634 | .address = S.showMyTrace(), |
| | 1635 | .inlines = true, |
| | 1636 | }); |
| 1612 | } | 1637 | } |
| 1613 | | 1638 | |
| 1614 | /// This API helps you track where a value originated and where it was mutated, | 1639 | /// This API helps you track where a value originated and where it was mutated, |
| ... | @@ -1679,6 +1704,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize | ... | @@ -1679,6 +1704,7 @@ pub fn ConfigurableTrace(comptime size: usize, comptime stack_frame_count: usize |
| 1679 | const stack_trace: StackTrace = .{ | 1704 | const stack_trace: StackTrace = .{ |
| 1680 | .index = frames.len, | 1705 | .index = frames.len, |
| 1681 | .instruction_addresses = frames, | 1706 | .instruction_addresses = frames, |
| | 1707 | .includes_inlined_frames = false, |
| 1682 | }; | 1708 | }; |
| 1683 | writeStackTrace(&stack_trace, stderr) catch return; | 1709 | writeStackTrace(&stack_trace, stderr) catch return; |
| 1684 | } | 1710 | } |