tests: enable stack trace tests for x86_64-selfhosted

Allows the stack trace tests to be additionally compiled and run with
`.use_llvm = false, .use_lld = false` depending on the host target. This
is currently enabled for x86_64 targets emitting ELF.

Self-hosted backends emit slightly different DWARF info to the LLVM
backend, so the checking logic (and the tests themselves) had to be
tweaked slightly to support both backends at once.
This commit is contained in:
mlugg 2025-01-23 04:48:01 +00:00
parent d916954bee
commit 7774287fdc
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
3 changed files with 70 additions and 42 deletions

View file

@ -21,17 +21,34 @@ const Config = struct {
}; };
pub fn addCase(self: *StackTrace, config: Config) void { pub fn addCase(self: *StackTrace, config: Config) void {
self.addCaseInner(config, true);
if (shouldTestNonLlvm(self.b.graph.host.result)) {
self.addCaseInner(config, false);
}
}
fn addCaseInner(self: *StackTrace, config: Config, use_llvm: bool) void {
if (config.Debug) |per_mode| if (config.Debug) |per_mode|
self.addExpect(config.name, config.source, .Debug, per_mode); self.addExpect(config.name, config.source, .Debug, use_llvm, per_mode);
if (config.ReleaseSmall) |per_mode| if (config.ReleaseSmall) |per_mode|
self.addExpect(config.name, config.source, .ReleaseSmall, per_mode); self.addExpect(config.name, config.source, .ReleaseSmall, use_llvm, per_mode);
if (config.ReleaseFast) |per_mode| if (config.ReleaseFast) |per_mode|
self.addExpect(config.name, config.source, .ReleaseFast, per_mode); self.addExpect(config.name, config.source, .ReleaseFast, use_llvm, per_mode);
if (config.ReleaseSafe) |per_mode| if (config.ReleaseSafe) |per_mode|
self.addExpect(config.name, config.source, .ReleaseSafe, per_mode); self.addExpect(config.name, config.source, .ReleaseSafe, use_llvm, per_mode);
}
fn shouldTestNonLlvm(target: std.Target) bool {
return switch (target.cpu.arch) {
.x86_64 => switch (target.ofmt) {
.elf => true,
else => false,
},
else => false,
};
} }
fn addExpect( fn addExpect(
@ -39,13 +56,14 @@ fn addExpect(
name: []const u8, name: []const u8,
source: []const u8, source: []const u8,
optimize_mode: OptimizeMode, optimize_mode: OptimizeMode,
use_llvm: bool,
mode_config: Config.PerMode, mode_config: Config.PerMode,
) void { ) void {
for (mode_config.exclude_os) |tag| if (tag == builtin.os.tag) return; for (mode_config.exclude_os) |tag| if (tag == builtin.os.tag) return;
const b = self.b; const b = self.b;
const annotated_case_name = b.fmt("check {s} ({s})", .{ const annotated_case_name = b.fmt("check {s} ({s} {s})", .{
name, @tagName(optimize_mode), name, @tagName(optimize_mode), if (use_llvm) "llvm" else "selfhosted",
}); });
for (self.test_filters) |test_filter| { for (self.test_filters) |test_filter| {
if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
@ -61,6 +79,7 @@ fn addExpect(
.target = b.graph.host, .target = b.graph.host,
.error_tracing = mode_config.error_tracing, .error_tracing = mode_config.error_tracing,
}), }),
.use_llvm = use_llvm,
}); });
const run = b.addRunArtifact(exe); const run = b.addRunArtifact(exe);

View file

@ -58,14 +58,23 @@ pub fn main() !void {
try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]); try buf.appendSlice(line[pos + 1 .. marks[2] + delims[2].len]);
try buf.appendSlice(" [address]"); try buf.appendSlice(" [address]");
if (optimize_mode == .Debug) { if (optimize_mode == .Debug) {
// On certain platforms (windows) or possibly depending on how we choose to link main try buf.appendSlice(line[marks[3] .. marks[4] + delims[4].len]);
// the object file extension may be present so we simply strip any extension.
if (mem.indexOfScalar(u8, line[marks[4]..marks[5]], '.')) |idot| { const file_name = line[marks[4] + delims[4].len .. marks[5]];
try buf.appendSlice(line[marks[3] .. marks[4] + idot]); // The LLVM backend currently uses the object file name in the debug info here.
try buf.appendSlice(line[marks[5]..]); // This actually violates the DWARF specification (DWARF5 § 3.1.1, lines 24-27).
// The self-hosted backend uses the root Zig source file of the module (in compilance with the spec).
if (std.mem.eql(u8, file_name, "test") or
std.mem.eql(u8, file_name, "test.exe.obj") or
std.mem.endsWith(u8, file_name, ".zig"))
{
try buf.appendSlice("[main_file]");
} else { } else {
try buf.appendSlice(line[marks[3]..]); // Something unexpected; include it verbatim.
try buf.appendSlice(file_name);
} }
try buf.appendSlice(line[marks[5]..]);
} else { } else {
try buf.appendSlice(line[marks[3] .. marks[3] + delims[3].len]); try buf.appendSlice(line[marks[3] .. marks[3] + delims[3].len]);
try buf.appendSlice("[function]"); try buf.appendSlice("[function]");

View file

@ -13,7 +13,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TheSkyIsFalling \\error: TheSkyIsFalling
\\source.zig:2:5: [address] in main (test) \\source.zig:2:5: [address] in main ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\ \\
@ -61,10 +61,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TheSkyIsFalling \\error: TheSkyIsFalling
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:6:5: [address] in main (test) \\source.zig:6:5: [address] in main ([main_file])
\\ try foo(); \\ try foo();
\\ ^ \\ ^
\\ \\
@ -120,7 +120,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: UnrelatedError \\error: UnrelatedError
\\source.zig:13:5: [address] in main (test) \\source.zig:13:5: [address] in main ([main_file])
\\ return error.UnrelatedError; \\ return error.UnrelatedError;
\\ ^ \\ ^
\\ \\
@ -172,7 +172,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: UnrelatedError \\error: UnrelatedError
\\source.zig:10:5: [address] in main (test) \\source.zig:10:5: [address] in main ([main_file])
\\ return error.UnrelatedError; \\ return error.UnrelatedError;
\\ ^ \\ ^
\\ \\
@ -224,10 +224,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TheSkyIsFalling \\error: TheSkyIsFalling
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:10:5: [address] in main (test) \\source.zig:10:5: [address] in main ([main_file])
\\ try foo(); \\ try foo();
\\ ^ \\ ^
\\ \\
@ -284,7 +284,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: BadTime \\error: BadTime
\\source.zig:12:5: [address] in main (test) \\source.zig:12:5: [address] in main ([main_file])
\\ return error.BadTime; \\ return error.BadTime;
\\ ^ \\ ^
\\ \\
@ -332,10 +332,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: AndMyCarIsOutOfGas \\error: AndMyCarIsOutOfGas
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:6:5: [address] in main (test) \\source.zig:6:5: [address] in main ([main_file])
\\ return foo() catch error.AndMyCarIsOutOfGas; \\ return foo() catch error.AndMyCarIsOutOfGas;
\\ ^ \\ ^
\\ \\
@ -391,7 +391,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: SomethingUnrelatedWentWrong \\error: SomethingUnrelatedWentWrong
\\source.zig:11:5: [address] in main (test) \\source.zig:11:5: [address] in main ([main_file])
\\ return error.SomethingUnrelatedWentWrong; \\ return error.SomethingUnrelatedWentWrong;
\\ ^ \\ ^
\\ \\
@ -456,13 +456,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: StillUnresolved \\error: StillUnresolved
\\source.zig:1:18: [address] in foo (test) \\source.zig:1:18: [address] in foo ([main_file])
\\fn foo() !void { return error.TheSkyIsFalling; } \\fn foo() !void { return error.TheSkyIsFalling; }
\\ ^ \\ ^
\\source.zig:2:18: [address] in bar (test) \\source.zig:2:18: [address] in bar ([main_file])
\\fn bar() !void { return error.InternalError; } \\fn bar() !void { return error.InternalError; }
\\ ^ \\ ^
\\source.zig:23:5: [address] in main (test) \\source.zig:23:5: [address] in main ([main_file])
\\ return error.StillUnresolved; \\ return error.StillUnresolved;
\\ ^ \\ ^
\\ \\
@ -527,13 +527,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TestExpectedError \\error: TestExpectedError
\\source.zig:9:18: [address] in foo (test) \\source.zig:9:18: [address] in foo ([main_file])
\\fn foo() !void { return error.Foo; } \\fn foo() !void { return error.Foo; }
\\ ^ \\ ^
\\source.zig:5:5: [address] in expectError (test) \\source.zig:5:5: [address] in expectError ([main_file])
\\ return error.TestExpectedError; \\ return error.TestExpectedError;
\\ ^ \\ ^
\\source.zig:17:5: [address] in main (test) \\source.zig:17:5: [address] in main ([main_file])
\\ try expectError(error.Bar, foo()); \\ try expectError(error.Bar, foo());
\\ ^ \\ ^
\\ \\
@ -592,13 +592,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: AndMyCarIsOutOfGas \\error: AndMyCarIsOutOfGas
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:6:5: [address] in bar (test) \\source.zig:6:5: [address] in bar ([main_file])
\\ return error.AndMyCarIsOutOfGas; \\ return error.AndMyCarIsOutOfGas;
\\ ^ \\ ^
\\source.zig:11:9: [address] in main (test) \\source.zig:11:9: [address] in main ([main_file])
\\ try bar(); \\ try bar();
\\ ^ \\ ^
\\ \\
@ -657,13 +657,13 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: AndMyCarIsOutOfGas \\error: AndMyCarIsOutOfGas
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:6:5: [address] in bar (test) \\source.zig:6:5: [address] in bar ([main_file])
\\ return error.AndMyCarIsOutOfGas; \\ return error.AndMyCarIsOutOfGas;
\\ ^ \\ ^
\\source.zig:11:9: [address] in main (test) \\source.zig:11:9: [address] in main ([main_file])
\\ try bar(); \\ try bar();
\\ ^ \\ ^
\\ \\
@ -724,16 +724,16 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TheSkyIsFalling \\error: TheSkyIsFalling
\\source.zig:10:5: [address] in make_error (test) \\source.zig:10:5: [address] in make_error ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\source.zig:6:5: [address] in bar (test) \\source.zig:6:5: [address] in bar ([main_file])
\\ return make_error(); \\ return make_error();
\\ ^ \\ ^
\\source.zig:2:5: [address] in foo (test) \\source.zig:2:5: [address] in foo ([main_file])
\\ try bar(); \\ try bar();
\\ ^ \\ ^
\\source.zig:14:5: [address] in main (test) \\source.zig:14:5: [address] in main ([main_file])
\\ try foo(); \\ try foo();
\\ ^ \\ ^
\\ \\
@ -797,10 +797,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.windows, // TODO intermittent failures .windows, // TODO intermittent failures
}, },
.expect = .expect =
\\source.zig:7:8: [address] in foo (test) \\source.zig:7:8: [address] in foo ([main_file])
\\ bar(); \\ bar();
\\ ^ \\ ^
\\source.zig:10:8: [address] in main (test) \\source.zig:10:8: [address] in main ([main_file])
\\ foo(); \\ foo();
\\ ^ \\ ^
\\ \\
@ -829,7 +829,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
.Debug = .{ .Debug = .{
.expect = .expect =
\\error: TheSkyIsFalling \\error: TheSkyIsFalling
\\source.zig:3:5: [address] in main (test) \\source.zig:3:5: [address] in main ([main_file])
\\ return error.TheSkyIsFalling; \\ return error.TheSkyIsFalling;
\\ ^ \\ ^
\\ \\