Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
b706949
debug: refactor stack frame capturing
jacobly0 Aug 27, 2025
b750e7c
change one million things
mlugg Sep 1, 2025
ed6ed62
more stuff
mlugg Sep 2, 2025
fb88dab
more still
mlugg Sep 2, 2025
89d8621
yet more
mlugg Sep 2, 2025
3f6a907
sky pirates! which are even better!
mlugg Sep 2, 2025
55ae674
names
mlugg Sep 2, 2025
25e02be
less hacky :D
mlugg Sep 2, 2025
55a7aff
me when i did a thing
mlugg Sep 2, 2025
84b6586
the world if ElfModule didn't suck:
mlugg Sep 2, 2025
8fdcdb8
the world if Dwarf.ElfModule was like REALLY good:
mlugg Sep 2, 2025
e4dbfc1
dont dupe state you silly billy
mlugg Sep 2, 2025
b762cd3
remove TODOs which are done or which i'm not actually gonna do lol
mlugg Sep 2, 2025
1397b95
std.debug.Dwarf: eliminate host pointer size dependency
mlugg Sep 2, 2025
ba3f389
split SelfInfo into a file per impl
mlugg Sep 2, 2025
665f13b
SelfInfo deinit magic
mlugg Sep 2, 2025
4b47a37
stash? more like no
mlugg Sep 2, 2025
5e6a191
fix aarch64-macos DWARF unwinding
mlugg Sep 3, 2025
dd9cb1b
doc comments
mlugg Sep 3, 2025
c895aa7
std.debug.SelfInfo: concrete error sets
mlugg Sep 3, 2025
405075f
SelfInfo: load eh_frame/debug_frame from ELF file if eh_frame_hdr omi…
mlugg Sep 3, 2025
ba5d9d5
remove redundant test
mlugg Sep 4, 2025
67fa566
std.posix: mark getcontext as unsupported by default
mlugg Sep 5, 2025
d4f7107
tweaks
mlugg Sep 5, 2025
5709369
std.debug: improve the APIs and stuff
mlugg Sep 5, 2025
c2ada49
replace usages of old std.debug APIs
mlugg Sep 5, 2025
9859440
add freestanding support IN THEORY
mlugg Sep 5, 2025
253fdfc
SelfInfo: be honest about how general unwinding is
mlugg Sep 8, 2025
f1215ad
SelfInfo.DarwinModule: rename field
mlugg Sep 8, 2025
202aeac
std: fixes
mlugg Sep 8, 2025
0c7b2a7
fix compiler ftbfs from std.macho and std.dwarf changes
mlugg Sep 8, 2025
3a561da
std: doc comments and tweaks
mlugg Sep 8, 2025
d9661e9
compiler: better crash handler
mlugg Sep 8, 2025
f40fbdb
link.Elf: restore eh_frame_hdr search table building
mlugg Sep 8, 2025
ac4d633
std: fix debug.Info and debug.Coverage
mlugg Sep 8, 2025
1392a7a
std.debug: unwinding on Windows
mlugg Sep 8, 2025
229f0a0
std.debug: handle ThreadContext slightly better
mlugg Sep 8, 2025
2743fdb
std.debug: try removing a probably-redundant condition
mlugg Sep 8, 2025
e6adddf
small reasonable change
mlugg Sep 9, 2025
f798048
std.debug: don't include dumpCurrentStackTrace frame
mlugg Sep 9, 2025
c1a30bd
std: replace debug.Dwarf.ElfModule with debug.ElfFile
mlugg Sep 9, 2025
bfbbda7
compiler: fix new panic handler in release builds
mlugg Sep 10, 2025
1123741
Dwarf: use 'gpa' terminology
mlugg Sep 10, 2025
4e45362
link.Elf: fix static PIE
mlugg Sep 10, 2025
02a0ade
std.debug: never attempt FP unwind under fomit-frame-pointer
mlugg Sep 11, 2025
7601b39
fix bad merge
mlugg Sep 11, 2025
9901b93
std: fix 32-bit build and some unsafe casts
mlugg Sep 11, 2025
a12ce28
std: fix os.linux.x86.syscall6
mlugg Sep 11, 2025
cedd9de
std.debug.Dwarf: fix names of inlined functions
mlugg Sep 11, 2025
1a8a8c6
tests: split up and enhance stack trace tests
mlugg Sep 9, 2025
e6eccc3
SelfInfo: remove x86-windows unwinding path
mlugg Sep 12, 2025
cf13b40
test-stack-traces: don't try to strip unwind tables on x86-windows
mlugg Sep 12, 2025
344ab62
std.debug: don't attempt SelfInfo unwinding when unsupported
mlugg Sep 12, 2025
5f00738
test-stack-traces: fix on x86-windows
mlugg Sep 12, 2025
51d08f4
fix compile errors and minor bugs
mlugg Sep 13, 2025
4cb84f8
test-standalone: update for std.debug changes
mlugg Sep 13, 2025
d289667
std.debug.Pdb: fix leak
mlugg Sep 13, 2025
f5c8d80
windows_bat_args: fix path handling
mlugg Sep 13, 2025
2fefe0e
tests: fix 32-bit compatible arch selection
mlugg Sep 13, 2025
e9c0d43
test-error-traces: skip some more optimized traces
mlugg Sep 13, 2025
604fb30
std.start: also don't print error trace targeting `.other`
mlugg Sep 13, 2025
b578cca
link.Dwarf: i just fixed error union values, s'nothin' else to it
jacobly0 Sep 15, 2025
a18fd41
std: rework/remove ucontext_t
mlugg Sep 17, 2025
dd8d596
std.debug: miscellaneous fixes
mlugg Sep 17, 2025
abb2b1e
std.debug: update support checks
mlugg Sep 17, 2025
3a9c680
std: allow disabling stack tracing
mlugg Sep 17, 2025
0c24b8e
update to new std.debug changes
mlugg Sep 17, 2025
23d6381
std.debug: fix typo
mlugg Sep 18, 2025
9434bab
std: work around crash parsing LLVM PDB
mlugg Sep 18, 2025
2ab650b
std.debug: go back to storing return addresses instead of call addresses
mlugg Sep 18, 2025
dae703d
std.posix.abort: only trigger breakpoint on Windows if being debugged
mlugg Sep 18, 2025
084e928
std: don't get CPU context when using CBE targeting MSVC
mlugg Sep 18, 2025
9c1821d
ElfModule: fix assertion failure
mlugg Sep 19, 2025
099a950
std.debug.SelfInfo: thread safety
mlugg Sep 19, 2025
c41bf99
std.debug: don't assume return address register is defined if not spe…
mlugg Sep 20, 2025
b0f2227
std.debug: cap total stack trace frames
mlugg Sep 20, 2025
f7e0ff8
std: clarify cpu_context register order rationale
mlugg Sep 20, 2025
950a9d2
typo
mlugg Sep 22, 2025
dbda011
std.debug.SelfInfo: mark ARM unwinding as unsupported
mlugg Sep 22, 2025
3f84b6c
cbe: workaround GCC miscompilation
mlugg Sep 23, 2025
156cd8f
std.debug: significantly speed up capturing stack traces
mlugg Sep 26, 2025
8950831
Dwarf.Unwind: handle macOS deviation from standard
mlugg Sep 26, 2025
a90eb50
typo
mlugg Sep 27, 2025
12ceb89
Dwarf.Unwind: fix typo
mlugg Sep 29, 2025
1120546
std.debug.SelfInfo: remove shared logic
mlugg Sep 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,8 @@ pub fn build(b: *std.Build) !void {
.skip_release = skip_release,
}));
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, skip_non_native));
test_step.dependOn(tests.addErrorTraceTests(b, test_filters, optimization_modes, skip_non_native));
test_step.dependOn(tests.addCliTests(b));
if (tests.addDebuggerTests(b, .{
.test_filters = test_filters,
Expand Down
8 changes: 4 additions & 4 deletions lib/compiler/test_runner.zig
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ fn mainServer() !void {
else => {
fail = true;
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace);
}
},
};
Expand Down Expand Up @@ -182,7 +182,7 @@ fn mainServer() !void {
error.SkipZigTest => return,
else => {
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace);
}
std.debug.print("failed with error.{t}\n", .{err});
std.process.exit(1);
Expand Down Expand Up @@ -261,7 +261,7 @@ fn mainTerminal() void {
std.debug.print("FAIL ({t})\n", .{err});
}
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace);
}
test_node.end();
},
Expand Down Expand Up @@ -398,7 +398,7 @@ pub fn fuzz(
error.SkipZigTest => return,
else => {
std.debug.lockStdErr();
if (@errorReturnTrace()) |trace| std.debug.dumpStackTrace(trace.*);
if (@errorReturnTrace()) |trace| std.debug.dumpStackTrace(trace);
std.debug.print("failed with error.{t}\n", .{err});
std.process.exit(1);
},
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2195,7 +2195,7 @@ fn dependencyInner(
sub_builder.runBuild(bz) catch @panic("unhandled error");

if (sub_builder.validateUserInputDidItFail()) {
std.debug.dumpCurrentStackTrace(@returnAddress());
std.debug.dumpCurrentStackTrace(.{ .first_address = @returnAddress() });
}
}

Expand Down
38 changes: 5 additions & 33 deletions lib/std/Build/Step.zig
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ test_results: TestResults,

/// The return address associated with creation of this step that can be useful
/// to print along with debugging messages.
debug_stack_trace: []usize,
debug_stack_trace: std.builtin.StackTrace,

pub const TestResults = struct {
fail_count: u32 = 0,
Expand Down Expand Up @@ -220,16 +220,9 @@ pub fn init(options: StepOptions) Step {
.state = .precheck_unstarted,
.max_rss = options.max_rss,
.debug_stack_trace = blk: {
if (!std.debug.sys_can_stack_trace) break :blk &.{};
const addresses = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
@memset(addresses, 0);
const addr_buf = arena.alloc(usize, options.owner.debug_stack_frames_count) catch @panic("OOM");
const first_ret_addr = options.first_ret_addr orelse @returnAddress();
var stack_trace = std.builtin.StackTrace{
.instruction_addresses = addresses,
.index = 0,
};
std.debug.captureStackTrace(first_ret_addr, &stack_trace);
break :blk addresses;
break :blk std.debug.captureCurrentStackTrace(.{ .first_address = first_ret_addr }, addr_buf);
},
.result_error_msgs = .{},
.result_error_bundle = std.zig.ErrorBundle.empty,
Expand Down Expand Up @@ -282,18 +275,6 @@ pub fn dependOn(step: *Step, other: *Step) void {
step.dependencies.append(other) catch @panic("OOM");
}

pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace {
var len: usize = 0;
while (len < s.debug_stack_trace.len and s.debug_stack_trace[len] != 0) {
len += 1;
}

return if (len == 0) null else .{
.instruction_addresses = s.debug_stack_trace,
.index = len,
};
}

fn makeNoOp(step: *Step, options: MakeOptions) anyerror!void {
_ = options;

Expand All @@ -315,18 +296,9 @@ pub fn cast(step: *Step, comptime T: type) ?*T {

/// For debugging purposes, prints identifying information about this Step.
pub fn dump(step: *Step, w: *std.Io.Writer, tty_config: std.Io.tty.Config) void {
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
@errorName(err),
}) catch {};
return;
};
if (step.getStackTrace()) |stack_trace| {
if (step.debug_stack_trace.instruction_addresses.len > 0) {
w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
std.debug.writeStackTrace(stack_trace, w, debug_info, tty_config) catch |err| {
w.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch {};
return;
};
std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {};
} else {
const field = "debug_stack_frames_count";
comptime assert(@hasField(Build, field));
Expand Down
38 changes: 16 additions & 22 deletions lib/std/Build/Step/CheckObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1097,44 +1097,38 @@ const MachODumper = struct {

for (ctx.symtab.items) |sym| {
const sym_name = ctx.getString(sym.n_strx);
if (sym.stab()) {
const tt = switch (sym.n_type) {
macho.N_SO => "SO",
macho.N_OSO => "OSO",
macho.N_BNSYM => "BNSYM",
macho.N_ENSYM => "ENSYM",
macho.N_FUN => "FUN",
macho.N_GSYM => "GSYM",
macho.N_STSYM => "STSYM",
else => "UNKNOWN STAB",
if (sym.n_type.bits.is_stab != 0) {
const tt = switch (sym.n_type.stab) {
_ => "UNKNOWN STAB",
else => @tagName(sym.n_type.stab),
};
try writer.print("{x}", .{sym.n_value});
if (sym.n_sect > 0) {
const sect = ctx.sections.items[sym.n_sect - 1];
try writer.print(" ({s},{s})", .{ sect.segName(), sect.sectName() });
}
try writer.print(" {s} (stab) {s}\n", .{ tt, sym_name });
} else if (sym.sect()) {
} else if (sym.n_type.bits.type == .sect) {
const sect = ctx.sections.items[sym.n_sect - 1];
try writer.print("{x} ({s},{s})", .{
sym.n_value,
sect.segName(),
sect.sectName(),
});
if (sym.n_desc & macho.REFERENCED_DYNAMICALLY != 0) try writer.writeAll(" [referenced dynamically]");
if (sym.weakDef()) try writer.writeAll(" weak");
if (sym.weakRef()) try writer.writeAll(" weakref");
if (sym.ext()) {
if (sym.pext()) try writer.writeAll(" private");
if (sym.n_desc.referenced_dynamically) try writer.writeAll(" [referenced dynamically]");
if (sym.n_desc.weak_def_or_ref_to_weak) try writer.writeAll(" weak");
if (sym.n_desc.weak_ref) try writer.writeAll(" weakref");
if (sym.n_type.bits.ext) {
if (sym.n_type.bits.pext) try writer.writeAll(" private");
try writer.writeAll(" external");
} else if (sym.pext()) try writer.writeAll(" (was private external)");
} else if (sym.n_type.bits.pext) try writer.writeAll(" (was private external)");
try writer.print(" {s}\n", .{sym_name});
} else if (sym.tentative()) {
const alignment = (sym.n_desc >> 8) & 0x0F;
const alignment = (@as(u16, @bitCast(sym.n_desc)) >> 8) & 0x0F;
try writer.print(" 0x{x:0>16} (common) (alignment 2^{d})", .{ sym.n_value, alignment });
if (sym.ext()) try writer.writeAll(" external");
if (sym.n_type.bits.ext) try writer.writeAll(" external");
try writer.print(" {s}\n", .{sym_name});
} else if (sym.undf()) {
} else if (sym.n_type.bits.type == .undf) {
const ordinal = @divFloor(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER);
const import_name = blk: {
if (ordinal <= 0) {
Expand All @@ -1153,8 +1147,8 @@ const MachODumper = struct {
break :blk basename[0..ext];
};
try writer.writeAll("(undefined)");
if (sym.weakRef()) try writer.writeAll(" weakref");
if (sym.ext()) try writer.writeAll(" external");
if (sym.n_desc.weak_ref) try writer.writeAll(" weakref");
if (sym.n_type.bits.ext) try writer.writeAll(" external");
try writer.print(" {s} (from {s})\n", .{
sym_name,
import_name,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Thread.zig
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ fn callFn(comptime f: anytype, args: anytype) switch (Impl) {
@call(.auto, f, args) catch |err| {
std.debug.print("error: {s}\n", .{@errorName(err)});
if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
std.debug.dumpStackTrace(trace);
}
};

Expand Down
13 changes: 5 additions & 8 deletions lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,17 @@ pub const StackTrace = struct {
index: usize,
instruction_addresses: []usize,

pub fn format(self: StackTrace, writer: *std.Io.Writer) std.Io.Writer.Error!void {
pub fn format(st: *const StackTrace, writer: *std.Io.Writer) std.Io.Writer.Error!void {
// TODO: re-evaluate whether to use format() methods at all.
// Until then, avoid an error when using GeneralPurposeAllocator with WebAssembly
// where it tries to call detectTTYConfig here.
if (builtin.os.tag == .freestanding) return;

const debug_info = std.debug.getSelfDebugInfo() catch |err| {
return writer.print("\nUnable to print stack trace: Unable to open debug info: {s}\n", .{@errorName(err)});
};
const tty_config = std.Io.tty.detectConfig(std.fs.File.stderr());
// TODO: why on earth are we using stderr's ttyconfig?
// If we want colored output, we should just make a formatter out of `writeStackTrace`.
const tty_config = std.Io.tty.detectConfig(.stderr());
try writer.writeAll("\n");
std.debug.writeStackTrace(self, writer, debug_info, tty_config) catch |err| {
try writer.print("Unable to print stack trace: {s}\n", .{@errorName(err)});
};
try std.debug.writeStackTrace(st, writer, tty_config);
}
};

Expand Down
Loading