From 980bf80036a896ff01e7395c3887858ebae3e7f7 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Tue, 1 Sep 2026 18:31:06 -0400 Subject: [PATCH] Dwarf2: add testing and enable passing tests - fix some bit-rotted documentation - fix some non-determinism that was causing these tests to be flaky - also update padding on moved/resized events - make `unit_padding` a header node - refactor out `ifPos` --- README.md | 19 ++- ci/x86_64-linux-debug-llvm.sh | 2 +- ci/x86_64-linux-debug.sh | 2 +- ci/x86_64-linux-release.sh | 2 +- src/link/Coff.zig | 3 +- src/link/Elf2.zig | 244 +++++++++++++++++++++------------- src/link/MappedFile.zig | 10 +- test/src/Debugger.zig | 172 ++++++++++++++---------- test/tests.zig | 59 +++++--- 9 files changed, 312 insertions(+), 201 deletions(-) diff --git a/README.md b/README.md index 2a8fce25915d6308a6ed1d457ffca689ab82e5b5..7bbd34b69a5e6b51b5ed16e37d39678b0475151c 100644 --- a/README.md +++ b/README.md @@ -781,12 +781,20 @@ If you will be debugging the Zig compiler itself, or if you will be debugging any project compiled with Zig's LLVM backend (not recommended with the LLDB fork, prefer vanilla LLDB with a version that matches the version of LLVM that Zig is using), you can get a better debugging experience by using -[`lldb_pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/tools/lldb_pretty_printers.py). +[`lldb/pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/lib/lldb/pretty_printers.py) +which is included in Zig's installed lib dir. Put this line in `~/.lldbinit`: ``` -command script import /path/to/zig/tools/lldb_pretty_printers.py +command script import /path/to/zig/lib/lldb/pretty_printers.py +``` + +If you will be debugging a Zig compiler built using Zig's self-hosted backends, +you will also want this line: + +``` +type category enable zig.compiler ``` If you will be using Zig's LLVM backend (again, not recommended with the LLDB @@ -797,10 +805,9 @@ type category enable zig.lang type category enable zig.std ``` -If you will be debugging a Zig compiler built using Zig's LLVM backend (again, -not recommended with the LLDB fork), you will also want this line: +If you will be debugging a Zig compiler built using Zig's LLVM backend without +using the LLDB fork, you will also want this line: ``` -type category enable zig.stage2 +type category enable zig ``` - diff --git a/ci/x86_64-linux-debug-llvm.sh b/ci/x86_64-linux-debug-llvm.sh index cc590bcdb69677eab65c21b18a3fb3fac2495c31..12beee8d9baebc901a55076e75fe9d1164f8c193 100755 --- a/ci/x86_64-linux-debug-llvm.sh +++ b/ci/x86_64-linux-debug-llvm.sh @@ -53,7 +53,7 @@ stage3-debug/bin/zig build \ stage3-debug/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ - -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \ + -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \ -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \ -fqemu \ --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \ diff --git a/ci/x86_64-linux-debug.sh b/ci/x86_64-linux-debug.sh index f46f84d21099a927542698e0a872ab6238679691..79787d9cad274c9e06fd70e4527718bf70b4a7d6 100755 --- a/ci/x86_64-linux-debug.sh +++ b/ci/x86_64-linux-debug.sh @@ -53,7 +53,7 @@ stage3-debug/bin/zig build \ stage3-debug/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ - -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \ + -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \ -fqemu \ --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \ -fwasmtime \ diff --git a/ci/x86_64-linux-release.sh b/ci/x86_64-linux-release.sh index a9671222f4099be694c9fa6d711c8ced1d6f13ad..d8ac56e1af086d1ee298e2352cda71e1504443e9 100755 --- a/ci/x86_64-linux-release.sh +++ b/ci/x86_64-linux-release.sh @@ -61,7 +61,7 @@ stage3-release/bin/zig build \ stage3-release/bin/zig build test docs \ --maxrss ${ZSF_MAX_RSS:-0} \ - -Dlldb=$HOME/deps/lldb-zig/Release-7c1090fd46/bin/lldb \ + -Dlldb=$HOME/deps/lldb-zig/Release-aad646607a/bin/lldb \ -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \ -fqemu \ --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \ diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 4bc312b3ccb674f697b6d74c1b026c321a51300c..1a553d8dc8a2f3ee69a6720ecb2439c974e317c1 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -7736,12 +7736,13 @@ pub fn printNode( { const mf_node = &coff.mf.nodes.items[@backingInt(ni)]; const off, const size = mf_node.location().resolve(&coff.mf); - try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}\n", .{ + try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{ @backingInt(ni), off, size, mf_node.flags.alignment.toByteUnits(), mf_node.flags.position, + if (mf_node.flags.bubbles_moved) " bubbles_moved" else "", if (mf_node.flags.moved) " moved" else "", if (mf_node.flags.resized) " resized" else "", if (mf_node.flags.has_content) " has_content" else "", diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index ba352c95f1f0471d83ae0243806f088c04a7ec65..c624c3ca822a8188fc2013e8da6eed8e4ec2b574 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -7241,7 +7241,16 @@ fn prelinkInner(elf: *Elf) Error!void { const debug_ni = debug_shndx.get(elf).ni; const frame_format = debug_shndx.debugFrameFormat(elf); const unit_padding_ni = elf.addNodeAssumeCapacity( - try debug_ni.addFloatingChild(gpa, &elf.mf, .{ + try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: { + var last_header_oni = debug_ni.last(&elf.mf); + while (last_header_oni.unwrap()) |last_header_ni| + switch (last_header_ni.position(&elf.mf)) { + .header => break, + .footer => last_header_oni = last_header_ni.prev(&elf.mf), + .floating => unreachable, + }; + break :last_header_oni last_header_oni; + }, .{ .alignment = if (frame_format) |_| switch (elf.identClass()) { .NONE, _ => unreachable, .@"32" => .@"4", @@ -9311,7 +9320,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { defer sub_prog_node.end(); if (clean_moved) try elf.flushMoved(ni); if (clean_resized) try elf.flushResized(ni); - if (clean_next_moved) try elf.flushNextMoved(ni); + if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni); break :task; } } @@ -10248,12 +10257,12 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo } } -fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { +fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { const trace = tracy.trace(@src()); defer trace.end(); switch (elf.getNode(ni)) { - .deleted, + .deleted => unreachable, .archive, .archive_input_member, .archive_elf_member_header, @@ -10272,7 +10281,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! .debug_shared, .eh_frame_footer, .unit_debug_info_footer, - => unreachable, + => {}, .archive_header => { const archive = &elf.archive.?; @@ -10314,94 +10323,139 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! => |_, tag| { const offset, const size = ni.location(&elf.mf).resolve(&elf.mf); const parent_ni = ni.parent(&elf.mf).unwrap().?; - const slice = if (ni.next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |next_ni| slice: { - const parent_slice = parent_ni.slicePadding(&elf.mf); - const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); - break :slice parent_slice[@intCast(offset)..@intCast(next_offset)]; - } else slice: switch (tag) { - else => unreachable, - .unit_padding, .unit_debug_rnglists => { - const parent_slice = parent_ni.slicePadding(&elf.mf); - const frame_shndx = elf.getNodeShndx(parent_ni); - const frame_format = frame_shndx.debugFrameFormat(elf) orelse - break :slice parent_slice[@intCast(offset)..]; - const footer_size = elf.debugFrameFooterSize(frame_format); - @memset(parent_slice[@intCast(offset + size)..][0..footer_size], 0); - frame_shndx.setSize(elf, offset + size + footer_size); - break :slice parent_slice[@intCast(offset)..][0..@intCast(size)]; - }, - .unit_frame_cie, .func_frame_fde => { - const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); - const frame_ni = parent_ni.parent(&elf.mf).unwrap().?; - const frame_slice = frame_ni.slicePadding(&elf.mf); - const frame_shndx = elf.getNode(frame_ni).section_manual_size; - const frame_format = frame_shndx.debugFrameFormat(elf).?; - if (parent_ni.next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |parent_next_ni| { - const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); - const slice = - frame_slice[@intCast(parent_offset + offset)..@intCast(parent_next_offset)]; - var fw: Io.Writer = .fixed(slice[@intCast(size)..]); - elf.dwarf.genDebugFrameCie(&fw, null, frame_format) catch |err| switch (err) { - error.WriteFailed => break :slice slice, - }; - elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); - break :slice slice[0..@intCast(size)]; - } - const footer_size = elf.debugFrameFooterSize(frame_format); - @memset(frame_slice[@intCast(parent_offset + offset + size)..][0..footer_size], 0); - frame_shndx.setSize(elf, parent_offset + offset + size + footer_size); - break :slice frame_slice[@intCast(parent_offset + offset)..][0..@intCast(size)]; - }, - .unit_debug_info_header, - .unit_debug_line_header, - .const_debug_info, - .global_debug_info, - .func_debug_info, - .func_debug_line, - .decl_debug_info, - => { - const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); - const debug_ni = parent_ni.parent(&elf.mf).unwrap().?; - const debug_slice = debug_ni.slicePadding(&elf.mf); - var fw: Io.Writer = .fixed(debug_slice[@intCast(parent_offset)..if (parent_ni - .next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |parent_next_ni| - debug_end: { - const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); - break :debug_end @intCast(parent_next_offset); - } else debug_slice.len]); - fw.end = @intCast(offset + size); - switch (tag) { - else => unreachable, - .unit_debug_info_header, - .const_debug_info, - .global_debug_info, - .func_debug_info, - .decl_debug_info, - => for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch unreachable, - .unit_debug_line_header, .func_debug_line => {}, - } - const unit_padding_offset = fw.end; - const unit_padding = fw.unusedCapacitySlice(); - elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) { - error.WriteFailed => { - fw.end = unit_padding_offset; - elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); - switch (tag) { - else => unreachable, - .unit_debug_info_header, .const_debug_info, .global_debug_info, .func_debug_info, .decl_debug_info => { - comptime assert(Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1); - @memset(fw.unusedCapacitySlice(), @backingInt(Dwarf.AbbrevCode.null)); + const slice = slice: { + if (ni.next(&elf.mf).unwrap()) |next_ni| switch (next_ni.position(&elf.mf)) { + .header => unreachable, + .footer => {}, + .floating => { + const parent_slice = parent_ni.slicePadding(&elf.mf); + const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); + break :slice parent_slice[@intCast(offset)..@intCast(next_offset)]; + }, + }; + switch (tag) { + else => unreachable, + .unit_padding, .unit_debug_rnglists => { + const parent_slice = parent_ni.slicePadding(&elf.mf); + const frame_shndx = elf.getNodeShndx(parent_ni); + const frame_format = frame_shndx.debugFrameFormat(elf) orelse + break :slice parent_slice[@intCast(offset)..]; + const footer_size = elf.debugFrameFooterSize(frame_format); + @memset(parent_slice[@intCast(offset + size)..][0..footer_size], 0); + frame_shndx.setSize(elf, offset + size + footer_size); + break :slice parent_slice[@intCast(offset)..][0..@intCast(size)]; + }, + .unit_frame_cie, .func_frame_fde => { + const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); + const frame_ni = parent_ni.parent(&elf.mf).unwrap().?; + const frame_slice = frame_ni.slicePadding(&elf.mf); + const frame_shndx = elf.getNode(frame_ni).section_manual_size; + const frame_format = frame_shndx.debugFrameFormat(elf).?; + if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| { + switch (parent_next_ni.position(&elf.mf)) { + .header => unreachable, + .footer => {}, + .floating => { + const parent_next_offset, _ = + parent_next_ni.location(&elf.mf).resolve(&elf.mf); + const slice = frame_slice[@intCast( + parent_offset + offset, + )..@intCast(parent_next_offset)]; + var fw: Io.Writer = .fixed(slice[@intCast(size)..]); + elf.dwarf.genDebugFrameCie( + &fw, + null, + frame_format, + ) catch |err| switch (err) { + error.WriteFailed => break :slice slice, + }; + elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); + break :slice slice[0..@intCast(size)]; }, - .unit_debug_line_header, .func_debug_line => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch - unreachable, } - return; - }, - }; - elf.dwarf.updateUnitLength(fw.buffer, unit_padding_offset); - elf.dwarf.updateUnitLength(unit_padding, unit_padding.len); - return; - }, + } + const footer_size = elf.debugFrameFooterSize(frame_format); + @memset( + frame_slice[@intCast(parent_offset + offset + size)..][0..footer_size], + 0, + ); + frame_shndx.setSize(elf, parent_offset + offset + size + footer_size); + break :slice frame_slice[@intCast(parent_offset + offset)..][0..@intCast(size)]; + }, + .unit_debug_info_header, + .unit_debug_line_header, + .const_debug_info, + .global_debug_info, + .func_debug_info, + .func_debug_line, + .decl_debug_info, + => { + const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); + const debug_ni = parent_ni.parent(&elf.mf).unwrap().?; + const debug_slice = debug_ni.slicePadding(&elf.mf); + var fw: Io.Writer = .fixed(buffer: { + if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| { + switch (parent_next_ni.position(&elf.mf)) { + .header => unreachable, + .footer => {}, + .floating => { + const parent_next_offset, _ = + parent_next_ni.location(&elf.mf).resolve(&elf.mf); + break :buffer debug_slice[@intCast( + parent_offset, + )..@intCast(parent_next_offset)]; + }, + } + } + break :buffer debug_slice[@intCast(parent_offset)..]; + }); + fw.end = @intCast(offset + size); + switch (tag) { + else => unreachable, + .unit_debug_info_header, + .const_debug_info, + .global_debug_info, + .func_debug_info, + .decl_debug_info, + => for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch + unreachable, + .unit_debug_line_header, .func_debug_line => {}, + } + const unit_padding_offset = fw.end; + const unit_padding = fw.unusedCapacitySlice(); + elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) { + error.WriteFailed => { + fw.end = unit_padding_offset; + elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); + switch (tag) { + else => unreachable, + .unit_debug_info_header, + .const_debug_info, + .global_debug_info, + .func_debug_info, + .decl_debug_info, + => { + comptime assert( + Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1, + ); + @memset( + fw.unusedCapacitySlice(), + @backingInt(Dwarf.AbbrevCode.null), + ); + }, + .unit_debug_line_header, + .func_debug_line, + => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch + unreachable, + } + return; + }, + }; + elf.dwarf.updateUnitLength(fw.buffer, unit_padding_offset); + elf.dwarf.updateUnitLength(unit_padding, unit_padding.len); + return; + }, + } }; var fw: Io.Writer = .fixed(slice[@intCast(size)..]); switch (tag) { @@ -11007,15 +11061,17 @@ pub fn printNode( { const mf_node = &elf.mf.nodes.items[@backingInt(ni)]; const off, const size = mf_node.location().resolve(&elf.mf); - try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{ + try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}{s}{s}\n", .{ @backingInt(ni), off, size, mf_node.flags.alignment.toByteUnits(), mf_node.flags.position, - if (mf_node.flags.moved) " moved" else "", - if (mf_node.flags.next_moved) " next_moved" else "", + if (mf_node.flags.bubbles_moved) " bubbles_moved" else "", + if (mf_node.flags.resized) " moved" else "", if (mf_node.flags.resized) " resized" else "", + if (mf_node.flags.enable_next_moved) " enable_next_moved" else "", + if (mf_node.flags.next_moved) " next_moved" else "", if (mf_node.flags.has_content) " has_content" else "", }); } diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig index f3c1d9302c4a759d9a76c9e2631f67bd390a248e..22b6f529accf3ba22eac77e9574677140260bfcd 100644 --- a/src/link/MappedFile.zig +++ b/src/link/MappedFile.zig @@ -355,10 +355,6 @@ pub const Node = extern struct { assert(oi != .none); return oi; } - - pub fn ifPos(oi: Optional, mf: *const MappedFile, pos: Node.Position) Optional { - return if ((oi.unwrap() orelse return .none).position(mf) == pos) oi else .none; - } }; fn get(ni: Node.Index, mf: *const MappedFile) *Node { @@ -518,12 +514,10 @@ pub const Node = extern struct { return node_moved.*; } pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { + const node = ni.get(mf); + if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf); if (ni.hasMoved(mf)) return; - const node = ni.get(mf); node.flags.moved = true; - if (node.prev.unwrap()) |prev_ni| { - prev_ni.nextMovedAssumeCapacity(mf); - } if (node.flags.resized or node.flags.next_moved) return; mf.updates.appendAssumeCapacity(ni); mf.update_prog_node.increaseEstimatedTotalItems(1); diff --git a/test/src/Debugger.zig b/test/src/Debugger.zig index 6a8082248547bdaf7f24d70fcebb236ee5035733..5e28c48a7e3772817f46e4cdae7af21d157945b1 100644 --- a/test/src/Debugger.zig +++ b/test/src/Debugger.zig @@ -1,6 +1,7 @@ b: *std.Build, options: Options, root_step: *std.Build.Step, +test_matrix: []const TestTarget, pub const Options = struct { test_filters: []const []const u8, @@ -12,19 +13,20 @@ pub const Options = struct { skip_libc: bool, }; -pub const Target = struct { - resolved: std.Build.ResolvedTarget, +pub const TestTarget = struct { + target: std.Target.Query, optimize_mode: std.builtin.Optimize = .debug, link_libc: ?bool = null, single_threaded: ?bool = null, pic: ?bool = null, - test_name_suffix: []const u8, + linker: LinkerImpl, }; -pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { +pub const LinkerImpl = enum { default, old, new }; + +pub fn addTests(db: *Debugger) void { db.addLldbTest( "basic", - target, &.{ .{ .path = "basic.zig", @@ -179,10 +181,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "identifiers", - target, &.{ .{ .path = "identifiers.zig", @@ -214,10 +216,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "types", - target, &.{ .{ .path = "types.zig", @@ -282,10 +284,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "pointers", - target, &.{ .{ .path = "pointers.zig", @@ -419,10 +421,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "strings", - target, &.{ .{ .path = "strings.zig", @@ -495,10 +497,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "enums", - target, &.{ .{ .path = "enums.zig", @@ -557,10 +559,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, // passes, but prints errors ); db.addLldbTest( "errors", - target, &.{ .{ .path = "errors.zig", @@ -627,10 +629,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, ); db.addLldbTest( "optionals", - target, &.{ .{ .path = "optionals.zig", @@ -681,10 +683,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 2 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "unions", - target, &.{ .{ .path = "unions.zig", @@ -766,10 +768,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, // passes, but prints errors ); db.addLldbTest( "storage", - target, &.{ .{ .path = "storage.zig", @@ -866,10 +868,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, ); db.addLldbTest( "if_blocks", - target, &.{ .{ .path = "if_blocks.zig", @@ -908,10 +910,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "switch_blocks", - target, &.{ .{ .path = "switch_blocks.zig", @@ -953,10 +955,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "step_single_stmt_loops", - target, &.{ .{ .path = "step_single_stmt_loops.zig", @@ -1371,10 +1373,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) frame variable --show-all-children x \\(u32) x = 12 }, + .{}, ); db.addLldbTest( "inline_call", - target, &.{ .{ .path = "root0.zig", @@ -1944,10 +1946,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\ frame #1: inline_call`m1pfi(m1pai=89) at mod1.zig:23:15 \\ frame #2: inline_call`root0.main at root0.zig:41:15 }, + .{ .skip_new_linker = true }, ); db.addLldbTest( "link_object", - target, &.{ .{ .path = "main.zig", @@ -1983,10 +1985,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 2 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{}, ); db.addLldbTest( "hash_map", - target, &.{ .{ .path = "main.zig", @@ -2052,10 +2054,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, ); db.addLldbTest( "multi_array_list", - target, &.{ .{ .path = "main.zig", @@ -2306,22 +2308,26 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void { \\(lldb) breakpoint delete --force 1 \\1 breakpoints deleted; 0 breakpoint locations disabled. }, + .{ .skip_new_linker = true }, ); } const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 }; +const TestOptions = struct { + skip_new_linker: bool = false, +}; + fn addGdbTest( db: *Debugger, name: []const u8, - target: *const Target, files: []const File, commands: []const u8, expected_output: []const []const u8, + options: TestOptions, ) void { db.addTest( name, - target, files, &.{}, &.{ @@ -2331,24 +2337,22 @@ fn addGdbTest( }, "set remotetimeout 0", commands, - &.{ - "--args", - }, + &.{"--args"}, expected_output, + options, ); } fn addLldbTest( db: *Debugger, name: []const u8, - target: *const Target, files: []const File, commands: []const u8, expected_output: []const []const u8, + options: TestOptions, ) void { db.addTest( name, - target, files, &.{.{ "LANG", "C.UTF-8" }}, // affects output formatting &.{ @@ -2358,10 +2362,9 @@ fn addLldbTest( }, "settings set plugin.process.gdb-remote.packet-timeout 0", commands, - &.{ - "--", - }, + &.{"--"}, expected_output, + options, ); } @@ -2373,7 +2376,6 @@ const success = 99; fn addTest( db: *Debugger, name: []const u8, - target: *const Target, files: []const File, env: []const struct { []const u8, []const u8 }, db_argv1: []const []const u8, @@ -2381,57 +2383,85 @@ fn addTest( commands: []const u8, db_argv2: []const []const u8, expected_output: []const []const u8, + options: TestOptions, ) void { if (db.options.test_filters.len > 0) { for (db.options.test_filters) |test_filter| { if (std.mem.find(u8, name, test_filter) != null) break; } else return; } - if (db.options.test_target_filters.len > 0) { - const triple_txt = target.resolved.query.zigTriple(db.b.allocator) catch @panic("OOM"); - for (db.options.test_target_filters) |filter| { - if (std.mem.find(u8, triple_txt, filter) != null) break; - } else return; - } - const files_wf = db.b.addWriteFiles(); - const mod = db.b.createModule(.{ - .target = target.resolved, - .root_source_file = files_wf.add(files[0].path, files[0].source), - .optimize = target.optimize_mode, - .link_libc = target.link_libc, - .single_threaded = target.single_threaded, - .pic = target.pic, - .strip = false, - }); + const wf = db.b.addWriteFiles(); + const root_source_file = wf.add(files[0].path, files[0].source); + var imports: std.array_hash_map.String(*std.Build.Module) = .empty; for (files[1..]) |file| { - const path = files_wf.add(file.path, file.source); - if (file.import) |import| mod.addImport(import, db.b.createModule(.{ + const path = wf.add(file.path, file.source); + if (file.import) |import| imports.putNoClobber(db.b.allocator, import, db.b.createModule(.{ .root_source_file = path, - })); + })) catch @panic("OOM"); } - - const exe = db.b.addExecutable(.{ - .name = name, - .root_module = mod, - .use_llvm = false, - .use_lld = false, - }); - - const commands_wf = db.b.addWriteFiles(); - const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix })); - for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]); - run.addArgs(db_argv1); - run.addFileArg(commands_wf.add( + const commands_file = wf.add( db.b.fmt("{s}.cmd", .{name}), db.b.fmt("{s}\n\n{s}\n\nquit {d}\n", .{ db_commands, commands, success }), - )); - run.addArgs(db_argv2); - run.addArtifactArg(exe); - for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) }); - run.addCheck(.{ .expect_term = .{ .exited = success } }); - run.setStdIn(.{ .bytes = "" }); - db.root_step.dependOn(&run.step); + ); + + for (db.test_matrix) |test_target| { + if (options.skip_new_linker and test_target.linker == .new) continue; + + const resolved_target = db.b.resolveTargetQuery(test_target.target); + + const target_str = db.b.fmt("{s}{s}{s}", .{ + resolved_target.query.zigTriple(db.b.allocator) catch @panic("OOM"), + switch (test_target.linker) { + .default, .old => "", + .new => "-new-linker", + }, + if (test_target.pic == true) "-pic" else "", + }); + + if (db.options.test_target_filters.len > 0) { + for (db.options.test_target_filters) |filter| { + if (std.mem.find(u8, target_str, filter) != null) break; + } else continue; + } + + const mod = db.b.createModule(.{ + .target = resolved_target, + .root_source_file = root_source_file, + .optimize = test_target.optimize_mode, + .link_libc = test_target.link_libc, + .single_threaded = test_target.single_threaded, + .pic = test_target.pic, + .strip = false, + }); + for (imports.keys(), imports.values()) |import_name, import_mod| + mod.addImport(import_name, import_mod); + + const exe = db.b.addExecutable(.{ + .name = name, + .root_module = mod, + .use_llvm = false, + .use_lld = false, + }); + exe.use_new_linker = switch (test_target.linker) { + .default => null, + .old => false, + .new => true, + }; + + const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target_str })); + for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]); + run.addArgs(db_argv1); + run.addFileArg(commands_file); + run.addArgs(db_argv2); + run.addArtifactArg(exe); + for (expected_output) |expected| run.addCheck(.{ + .expect_stdout_match = db.b.fmt("{s}\n", .{expected}), + }); + run.addCheck(.{ .expect_term = .{ .exited = success } }); + run.setStdIn(.{ .bytes = "" }); + db.root_step.dependOn(&run.step); + } } const Debugger = @This(); diff --git a/test/tests.zig b/test/tests.zig index 920f75582e6278365d095f0b5132b2a90dbec94c..7ecc7d93e22f5ba209ce8961c21c32a4f8112893 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2303,6 +2303,45 @@ const incremental_targets = &[_]IncrementalTarget{ }, }; +const debugger_matrix: []const DebuggerContext.TestTarget = &.{ + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .pic = false, + .linker = .old, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .pic = true, + .linker = .old, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .pic = false, + .linker = .new, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .pic = true, + .linker = .new, + }, +}; + fn compatible32bitArch(host: *const std.Target) ?std.Target.Cpu.Arch { return switch (host.os.tag) { .freebsd => switch (host.cpu.arch) { @@ -3323,25 +3362,9 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step .b = b, .options = options, .root_step = step, + .test_matrix = debugger_matrix, }; - context.addTestsForTarget(&.{ - .resolved = b.resolveTargetQuery(.{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }), - .pic = false, - .test_name_suffix = "x86_64-linux", - }); - context.addTestsForTarget(&.{ - .resolved = b.resolveTargetQuery(.{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }), - .pic = true, - .test_name_suffix = "x86_64-linux-pic", - }); + context.addTests(); return step; } -- 2.54.0