authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-01 18:31:06-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-09-03 13:00:54-04:00
log980bf80036a896ff01e7395c3887858ebae3e7f7
treeae95303599411dcc30422098104be9eec2c72fc9
parentbac57b3d15b84b1e4d5365acde3a78d98f439de3

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`

9 files changed, 312 insertions(+), 201 deletions(-)

README.md+13-6
......@@ -781,12 +781,20 @@ If you will be debugging the Zig compiler itself, or if you will be debugging
781781any project compiled with Zig's LLVM backend (not recommended with the LLDB
782782fork, prefer vanilla LLDB with a version that matches the version of LLVM that
783783Zig is using), you can get a better debugging experience by using
784[`lldb_pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/tools/lldb_pretty_printers.py).
784[`lldb/pretty_printers.py`](https://codeberg.org/ziglang/zig/src/branch/master/lib/lldb/pretty_printers.py)
785which is included in Zig's installed lib dir.
785786
786787Put this line in `~/.lldbinit`:
787788
788789```
789command script import /path/to/zig/tools/lldb_pretty_printers.py
790command script import /path/to/zig/lib/lldb/pretty_printers.py
791```
792
793If you will be debugging a Zig compiler built using Zig's self-hosted backends,
794you will also want this line:
795
796```
797type category enable zig.compiler
790798```
791799
792800If you will be using Zig's LLVM backend (again, not recommended with the LLDB
......@@ -797,10 +805,9 @@ type category enable zig.lang
797805type category enable zig.std
798806```
799807
800If you will be debugging a Zig compiler built using Zig's LLVM backend (again,
801not recommended with the LLDB fork), you will also want this line:
808If you will be debugging a Zig compiler built using Zig's LLVM backend without
809using the LLDB fork, you will also want this line:
802810
803811```
804type category enable zig.stage2
812type category enable zig
805813```
806
ci/x86_64-linux-debug-llvm.sh+1-1
......@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \
5353
5454stage3-debug/bin/zig build test docs \
5555 --maxrss ${ZSF_MAX_RSS:-0} \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \
5757 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
5858 -fqemu \
5959 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
ci/x86_64-linux-debug.sh+1-1
......@@ -53,7 +53,7 @@ stage3-debug/bin/zig build \
5353
5454stage3-debug/bin/zig build test docs \
5555 --maxrss ${ZSF_MAX_RSS:-0} \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-7c1090fd46/bin/lldb \
56 -Dlldb=$HOME/deps/lldb-zig/Debug-aad646607a/bin/lldb \
5757 -fqemu \
5858 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
5959 -fwasmtime \
ci/x86_64-linux-release.sh+1-1
......@@ -61,7 +61,7 @@ stage3-release/bin/zig build \
6161
6262stage3-release/bin/zig build test docs \
6363 --maxrss ${ZSF_MAX_RSS:-0} \
64 -Dlldb=$HOME/deps/lldb-zig/Release-7c1090fd46/bin/lldb \
64 -Dlldb=$HOME/deps/lldb-zig/Release-aad646607a/bin/lldb \
6565 -Dlibc-test-path=$HOME/deps/libc-test-b95fe84 \
6666 -fqemu \
6767 --libc-runtimes $HOME/deps/glibc-2.43-musl-1.2.5 \
src/link/Coff.zig+2-1
......@@ -7736,12 +7736,13 @@ pub fn printNode(
77367736 {
77377737 const mf_node = &coff.mf.nodes.items[@backingInt(ni)];
77387738 const off, const size = mf_node.location().resolve(&coff.mf);
7739 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}\n", .{
7739 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{
77407740 @backingInt(ni),
77417741 off,
77427742 size,
77437743 mf_node.flags.alignment.toByteUnits(),
77447744 mf_node.flags.position,
7745 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
77457746 if (mf_node.flags.moved) " moved" else "",
77467747 if (mf_node.flags.resized) " resized" else "",
77477748 if (mf_node.flags.has_content) " has_content" else "",
src/link/Elf2.zig+150-94
......@@ -7241,7 +7241,16 @@ fn prelinkInner(elf: *Elf) Error!void {
72417241 const debug_ni = debug_shndx.get(elf).ni;
72427242 const frame_format = debug_shndx.debugFrameFormat(elf);
72437243 const unit_padding_ni = elf.addNodeAssumeCapacity(
7244 try debug_ni.addFloatingChild(gpa, &elf.mf, .{
7244 try debug_ni.addHeaderChildAfter(gpa, &elf.mf, last_header_oni: {
7245 var last_header_oni = debug_ni.last(&elf.mf);
7246 while (last_header_oni.unwrap()) |last_header_ni|
7247 switch (last_header_ni.position(&elf.mf)) {
7248 .header => break,
7249 .footer => last_header_oni = last_header_ni.prev(&elf.mf),
7250 .floating => unreachable,
7251 };
7252 break :last_header_oni last_header_oni;
7253 }, .{
72457254 .alignment = if (frame_format) |_| switch (elf.identClass()) {
72467255 .NONE, _ => unreachable,
72477256 .@"32" => .@"4",
......@@ -9311,7 +9320,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
93119320 defer sub_prog_node.end();
93129321 if (clean_moved) try elf.flushMoved(ni);
93139322 if (clean_resized) try elf.flushResized(ni);
9314 if (clean_next_moved) try elf.flushNextMoved(ni);
9323 if (clean_moved or clean_resized or clean_next_moved) try elf.flushPadding(ni);
93159324 break :task;
93169325 }
93179326 }
......@@ -10248,12 +10257,12 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo
1024810257 }
1024910258}
1025010259
10251fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
10260fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void {
1025210261 const trace = tracy.trace(@src());
1025310262 defer trace.end();
1025410263
1025510264 switch (elf.getNode(ni)) {
10256 .deleted,
10265 .deleted => unreachable,
1025710266 .archive,
1025810267 .archive_input_member,
1025910268 .archive_elf_member_header,
......@@ -10272,7 +10281,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
1027210281 .debug_shared,
1027310282 .eh_frame_footer,
1027410283 .unit_debug_info_footer,
10275 => unreachable,
10284 => {},
1027610285
1027710286 .archive_header => {
1027810287 const archive = &elf.archive.?;
......@@ -10314,94 +10323,139 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!
1031410323 => |_, tag| {
1031510324 const offset, const size = ni.location(&elf.mf).resolve(&elf.mf);
1031610325 const parent_ni = ni.parent(&elf.mf).unwrap().?;
10317 const slice = if (ni.next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |next_ni| slice: {
10318 const parent_slice = parent_ni.slicePadding(&elf.mf);
10319 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
10320 break :slice parent_slice[@intCast(offset)..@intCast(next_offset)];
10321 } else slice: switch (tag) {
10322 else => unreachable,
10323 .unit_padding, .unit_debug_rnglists => {
10324 const parent_slice = parent_ni.slicePadding(&elf.mf);
10325 const frame_shndx = elf.getNodeShndx(parent_ni);
10326 const frame_format = frame_shndx.debugFrameFormat(elf) orelse
10327 break :slice parent_slice[@intCast(offset)..];
10328 const footer_size = elf.debugFrameFooterSize(frame_format);
10329 @memset(parent_slice[@intCast(offset + size)..][0..footer_size], 0);
10330 frame_shndx.setSize(elf, offset + size + footer_size);
10331 break :slice parent_slice[@intCast(offset)..][0..@intCast(size)];
10332 },
10333 .unit_frame_cie, .func_frame_fde => {
10334 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10335 const frame_ni = parent_ni.parent(&elf.mf).unwrap().?;
10336 const frame_slice = frame_ni.slicePadding(&elf.mf);
10337 const frame_shndx = elf.getNode(frame_ni).section_manual_size;
10338 const frame_format = frame_shndx.debugFrameFormat(elf).?;
10339 if (parent_ni.next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |parent_next_ni| {
10340 const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10341 const slice =
10342 frame_slice[@intCast(parent_offset + offset)..@intCast(parent_next_offset)];
10343 var fw: Io.Writer = .fixed(slice[@intCast(size)..]);
10344 elf.dwarf.genDebugFrameCie(&fw, null, frame_format) catch |err| switch (err) {
10345 error.WriteFailed => break :slice slice,
10346 };
10347 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10348 break :slice slice[0..@intCast(size)];
10349 }
10350 const footer_size = elf.debugFrameFooterSize(frame_format);
10351 @memset(frame_slice[@intCast(parent_offset + offset + size)..][0..footer_size], 0);
10352 frame_shndx.setSize(elf, parent_offset + offset + size + footer_size);
10353 break :slice frame_slice[@intCast(parent_offset + offset)..][0..@intCast(size)];
10354 },
10355 .unit_debug_info_header,
10356 .unit_debug_line_header,
10357 .const_debug_info,
10358 .global_debug_info,
10359 .func_debug_info,
10360 .func_debug_line,
10361 .decl_debug_info,
10362 => {
10363 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10364 const debug_ni = parent_ni.parent(&elf.mf).unwrap().?;
10365 const debug_slice = debug_ni.slicePadding(&elf.mf);
10366 var fw: Io.Writer = .fixed(debug_slice[@intCast(parent_offset)..if (parent_ni
10367 .next(&elf.mf).ifPos(&elf.mf, .floating).unwrap()) |parent_next_ni|
10368 debug_end: {
10369 const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10370 break :debug_end @intCast(parent_next_offset);
10371 } else debug_slice.len]);
10372 fw.end = @intCast(offset + size);
10373 switch (tag) {
10374 else => unreachable,
10375 .unit_debug_info_header,
10376 .const_debug_info,
10377 .global_debug_info,
10378 .func_debug_info,
10379 .decl_debug_info,
10380 => for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch unreachable,
10381 .unit_debug_line_header, .func_debug_line => {},
10382 }
10383 const unit_padding_offset = fw.end;
10384 const unit_padding = fw.unusedCapacitySlice();
10385 elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) {
10386 error.WriteFailed => {
10387 fw.end = unit_padding_offset;
10388 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10389 switch (tag) {
10390 else => unreachable,
10391 .unit_debug_info_header, .const_debug_info, .global_debug_info, .func_debug_info, .decl_debug_info => {
10392 comptime assert(Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1);
10393 @memset(fw.unusedCapacitySlice(), @backingInt(Dwarf.AbbrevCode.null));
10326 const slice = slice: {
10327 if (ni.next(&elf.mf).unwrap()) |next_ni| switch (next_ni.position(&elf.mf)) {
10328 .header => unreachable,
10329 .footer => {},
10330 .floating => {
10331 const parent_slice = parent_ni.slicePadding(&elf.mf);
10332 const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf);
10333 break :slice parent_slice[@intCast(offset)..@intCast(next_offset)];
10334 },
10335 };
10336 switch (tag) {
10337 else => unreachable,
10338 .unit_padding, .unit_debug_rnglists => {
10339 const parent_slice = parent_ni.slicePadding(&elf.mf);
10340 const frame_shndx = elf.getNodeShndx(parent_ni);
10341 const frame_format = frame_shndx.debugFrameFormat(elf) orelse
10342 break :slice parent_slice[@intCast(offset)..];
10343 const footer_size = elf.debugFrameFooterSize(frame_format);
10344 @memset(parent_slice[@intCast(offset + size)..][0..footer_size], 0);
10345 frame_shndx.setSize(elf, offset + size + footer_size);
10346 break :slice parent_slice[@intCast(offset)..][0..@intCast(size)];
10347 },
10348 .unit_frame_cie, .func_frame_fde => {
10349 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10350 const frame_ni = parent_ni.parent(&elf.mf).unwrap().?;
10351 const frame_slice = frame_ni.slicePadding(&elf.mf);
10352 const frame_shndx = elf.getNode(frame_ni).section_manual_size;
10353 const frame_format = frame_shndx.debugFrameFormat(elf).?;
10354 if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| {
10355 switch (parent_next_ni.position(&elf.mf)) {
10356 .header => unreachable,
10357 .footer => {},
10358 .floating => {
10359 const parent_next_offset, _ =
10360 parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10361 const slice = frame_slice[@intCast(
10362 parent_offset + offset,
10363 )..@intCast(parent_next_offset)];
10364 var fw: Io.Writer = .fixed(slice[@intCast(size)..]);
10365 elf.dwarf.genDebugFrameCie(
10366 &fw,
10367 null,
10368 frame_format,
10369 ) catch |err| switch (err) {
10370 error.WriteFailed => break :slice slice,
10371 };
10372 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10373 break :slice slice[0..@intCast(size)];
1039410374 },
10395 .unit_debug_line_header, .func_debug_line => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch
10396 unreachable,
1039710375 }
10398 return;
10399 },
10400 };
10401 elf.dwarf.updateUnitLength(fw.buffer, unit_padding_offset);
10402 elf.dwarf.updateUnitLength(unit_padding, unit_padding.len);
10403 return;
10404 },
10376 }
10377 const footer_size = elf.debugFrameFooterSize(frame_format);
10378 @memset(
10379 frame_slice[@intCast(parent_offset + offset + size)..][0..footer_size],
10380 0,
10381 );
10382 frame_shndx.setSize(elf, parent_offset + offset + size + footer_size);
10383 break :slice frame_slice[@intCast(parent_offset + offset)..][0..@intCast(size)];
10384 },
10385 .unit_debug_info_header,
10386 .unit_debug_line_header,
10387 .const_debug_info,
10388 .global_debug_info,
10389 .func_debug_info,
10390 .func_debug_line,
10391 .decl_debug_info,
10392 => {
10393 const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf);
10394 const debug_ni = parent_ni.parent(&elf.mf).unwrap().?;
10395 const debug_slice = debug_ni.slicePadding(&elf.mf);
10396 var fw: Io.Writer = .fixed(buffer: {
10397 if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| {
10398 switch (parent_next_ni.position(&elf.mf)) {
10399 .header => unreachable,
10400 .footer => {},
10401 .floating => {
10402 const parent_next_offset, _ =
10403 parent_next_ni.location(&elf.mf).resolve(&elf.mf);
10404 break :buffer debug_slice[@intCast(
10405 parent_offset,
10406 )..@intCast(parent_next_offset)];
10407 },
10408 }
10409 }
10410 break :buffer debug_slice[@intCast(parent_offset)..];
10411 });
10412 fw.end = @intCast(offset + size);
10413 switch (tag) {
10414 else => unreachable,
10415 .unit_debug_info_header,
10416 .const_debug_info,
10417 .global_debug_info,
10418 .func_debug_info,
10419 .decl_debug_info,
10420 => for (0..2) |_| fw.writeUleb128(@backingInt(Dwarf.AbbrevCode.null)) catch
10421 unreachable,
10422 .unit_debug_line_header, .func_debug_line => {},
10423 }
10424 const unit_padding_offset = fw.end;
10425 const unit_padding = fw.unusedCapacitySlice();
10426 elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) {
10427 error.WriteFailed => {
10428 fw.end = unit_padding_offset;
10429 elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len);
10430 switch (tag) {
10431 else => unreachable,
10432 .unit_debug_info_header,
10433 .const_debug_info,
10434 .global_debug_info,
10435 .func_debug_info,
10436 .decl_debug_info,
10437 => {
10438 comptime assert(
10439 Dwarf.uleb128Size(@backingInt(Dwarf.AbbrevCode.null)) == 1,
10440 );
10441 @memset(
10442 fw.unusedCapacitySlice(),
10443 @backingInt(Dwarf.AbbrevCode.null),
10444 );
10445 },
10446 .unit_debug_line_header,
10447 .func_debug_line,
10448 => Dwarf.genDebugLinePadding(&fw, fw.unusedCapacityLen()) catch
10449 unreachable,
10450 }
10451 return;
10452 },
10453 };
10454 elf.dwarf.updateUnitLength(fw.buffer, unit_padding_offset);
10455 elf.dwarf.updateUnitLength(unit_padding, unit_padding.len);
10456 return;
10457 },
10458 }
1040510459 };
1040610460 var fw: Io.Writer = .fixed(slice[@intCast(size)..]);
1040710461 switch (tag) {
......@@ -11007,15 +11061,17 @@ pub fn printNode(
1100711061 {
1100811062 const mf_node = &elf.mf.nodes.items[@backingInt(ni)];
1100911063 const off, const size = mf_node.location().resolve(&elf.mf);
11010 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}\n", .{
11064 try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x} {t}{s}{s}{s}{s}{s}{s}\n", .{
1101111065 @backingInt(ni),
1101211066 off,
1101311067 size,
1101411068 mf_node.flags.alignment.toByteUnits(),
1101511069 mf_node.flags.position,
11016 if (mf_node.flags.moved) " moved" else "",
11017 if (mf_node.flags.next_moved) " next_moved" else "",
11070 if (mf_node.flags.bubbles_moved) " bubbles_moved" else "",
11071 if (mf_node.flags.resized) " moved" else "",
1101811072 if (mf_node.flags.resized) " resized" else "",
11073 if (mf_node.flags.enable_next_moved) " enable_next_moved" else "",
11074 if (mf_node.flags.next_moved) " next_moved" else "",
1101911075 if (mf_node.flags.has_content) " has_content" else "",
1102011076 });
1102111077 }
src/link/MappedFile.zig+2-8
......@@ -355,10 +355,6 @@ pub const Node = extern struct {
355355 assert(oi != .none);
356356 return oi;
357357 }
358
359 pub fn ifPos(oi: Optional, mf: *const MappedFile, pos: Node.Position) Optional {
360 return if ((oi.unwrap() orelse return .none).position(mf) == pos) oi else .none;
361 }
362358 };
363359
364360 fn get(ni: Node.Index, mf: *const MappedFile) *Node {
......@@ -518,12 +514,10 @@ pub const Node = extern struct {
518514 return node_moved.*;
519515 }
520516 pub fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void {
521 if (ni.hasMoved(mf)) return;
522517 const node = ni.get(mf);
518 if (node.prev.unwrap()) |prev_ni| prev_ni.nextMovedAssumeCapacity(mf);
519 if (ni.hasMoved(mf)) return;
523520 node.flags.moved = true;
524 if (node.prev.unwrap()) |prev_ni| {
525 prev_ni.nextMovedAssumeCapacity(mf);
526 }
527521 if (node.flags.resized or node.flags.next_moved) return;
528522 mf.updates.appendAssumeCapacity(ni);
529523 mf.update_prog_node.increaseEstimatedTotalItems(1);
test/src/Debugger.zig+101-71
......@@ -1,6 +1,7 @@
11b: *std.Build,
22options: Options,
33root_step: *std.Build.Step,
4test_matrix: []const TestTarget,
45
56pub const Options = struct {
67 test_filters: []const []const u8,
......@@ -12,19 +13,20 @@ pub const Options = struct {
1213 skip_libc: bool,
1314};
1415
15pub const Target = struct {
16 resolved: std.Build.ResolvedTarget,
16pub const TestTarget = struct {
17 target: std.Target.Query,
1718 optimize_mode: std.builtin.Optimize = .debug,
1819 link_libc: ?bool = null,
1920 single_threaded: ?bool = null,
2021 pic: ?bool = null,
21 test_name_suffix: []const u8,
22 linker: LinkerImpl,
2223};
2324
24pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
25pub const LinkerImpl = enum { default, old, new };
26
27pub fn addTests(db: *Debugger) void {
2528 db.addLldbTest(
2629 "basic",
27 target,
2830 &.{
2931 .{
3032 .path = "basic.zig",
......@@ -179,10 +181,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
179181 \\(lldb) breakpoint delete --force 1
180182 \\1 breakpoints deleted; 0 breakpoint locations disabled.
181183 },
184 .{},
182185 );
183186 db.addLldbTest(
184187 "identifiers",
185 target,
186188 &.{
187189 .{
188190 .path = "identifiers.zig",
......@@ -214,10 +216,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
214216 \\(lldb) breakpoint delete --force 1
215217 \\1 breakpoints deleted; 0 breakpoint locations disabled.
216218 },
219 .{},
217220 );
218221 db.addLldbTest(
219222 "types",
220 target,
221223 &.{
222224 .{
223225 .path = "types.zig",
......@@ -282,10 +284,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
282284 \\(lldb) breakpoint delete --force 1
283285 \\1 breakpoints deleted; 0 breakpoint locations disabled.
284286 },
287 .{},
285288 );
286289 db.addLldbTest(
287290 "pointers",
288 target,
289291 &.{
290292 .{
291293 .path = "pointers.zig",
......@@ -419,10 +421,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
419421 \\(lldb) breakpoint delete --force 1
420422 \\1 breakpoints deleted; 0 breakpoint locations disabled.
421423 },
424 .{},
422425 );
423426 db.addLldbTest(
424427 "strings",
425 target,
426428 &.{
427429 .{
428430 .path = "strings.zig",
......@@ -495,10 +497,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
495497 \\(lldb) breakpoint delete --force 1
496498 \\1 breakpoints deleted; 0 breakpoint locations disabled.
497499 },
500 .{},
498501 );
499502 db.addLldbTest(
500503 "enums",
501 target,
502504 &.{
503505 .{
504506 .path = "enums.zig",
......@@ -557,10 +559,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
557559 \\(lldb) breakpoint delete --force 1
558560 \\1 breakpoints deleted; 0 breakpoint locations disabled.
559561 },
562 .{ .skip_new_linker = true }, // passes, but prints errors
560563 );
561564 db.addLldbTest(
562565 "errors",
563 target,
564566 &.{
565567 .{
566568 .path = "errors.zig",
......@@ -627,10 +629,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
627629 \\(lldb) breakpoint delete --force 1
628630 \\1 breakpoints deleted; 0 breakpoint locations disabled.
629631 },
632 .{ .skip_new_linker = true },
630633 );
631634 db.addLldbTest(
632635 "optionals",
633 target,
634636 &.{
635637 .{
636638 .path = "optionals.zig",
......@@ -681,10 +683,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
681683 \\(lldb) breakpoint delete --force 2
682684 \\1 breakpoints deleted; 0 breakpoint locations disabled.
683685 },
686 .{},
684687 );
685688 db.addLldbTest(
686689 "unions",
687 target,
688690 &.{
689691 .{
690692 .path = "unions.zig",
......@@ -766,10 +768,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
766768 \\(lldb) breakpoint delete --force 1
767769 \\1 breakpoints deleted; 0 breakpoint locations disabled.
768770 },
771 .{ .skip_new_linker = true }, // passes, but prints errors
769772 );
770773 db.addLldbTest(
771774 "storage",
772 target,
773775 &.{
774776 .{
775777 .path = "storage.zig",
......@@ -866,10 +868,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
866868 \\(lldb) breakpoint delete --force 1
867869 \\1 breakpoints deleted; 0 breakpoint locations disabled.
868870 },
871 .{ .skip_new_linker = true },
869872 );
870873 db.addLldbTest(
871874 "if_blocks",
872 target,
873875 &.{
874876 .{
875877 .path = "if_blocks.zig",
......@@ -908,10 +910,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
908910 \\(lldb) breakpoint delete --force 1
909911 \\1 breakpoints deleted; 0 breakpoint locations disabled.
910912 },
913 .{},
911914 );
912915 db.addLldbTest(
913916 "switch_blocks",
914 target,
915917 &.{
916918 .{
917919 .path = "switch_blocks.zig",
......@@ -953,10 +955,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
953955 \\(lldb) breakpoint delete --force 1
954956 \\1 breakpoints deleted; 0 breakpoint locations disabled.
955957 },
958 .{},
956959 );
957960 db.addLldbTest(
958961 "step_single_stmt_loops",
959 target,
960962 &.{
961963 .{
962964 .path = "step_single_stmt_loops.zig",
......@@ -1371,10 +1373,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
13711373 \\(lldb) frame variable --show-all-children x
13721374 \\(u32) x = 12
13731375 },
1376 .{},
13741377 );
13751378 db.addLldbTest(
13761379 "inline_call",
1377 target,
13781380 &.{
13791381 .{
13801382 .path = "root0.zig",
......@@ -1944,10 +1946,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
19441946 \\ frame #1: inline_call`m1pfi(m1pai=89) at mod1.zig:23:15
19451947 \\ frame #2: inline_call`root0.main at root0.zig:41:15
19461948 },
1949 .{ .skip_new_linker = true },
19471950 );
19481951 db.addLldbTest(
19491952 "link_object",
1950 target,
19511953 &.{
19521954 .{
19531955 .path = "main.zig",
......@@ -1983,10 +1985,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
19831985 \\(lldb) breakpoint delete --force 2
19841986 \\1 breakpoints deleted; 0 breakpoint locations disabled.
19851987 },
1988 .{},
19861989 );
19871990 db.addLldbTest(
19881991 "hash_map",
1989 target,
19901992 &.{
19911993 .{
19921994 .path = "main.zig",
......@@ -2052,10 +2054,10 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
20522054 \\(lldb) breakpoint delete --force 1
20532055 \\1 breakpoints deleted; 0 breakpoint locations disabled.
20542056 },
2057 .{ .skip_new_linker = true },
20552058 );
20562059 db.addLldbTest(
20572060 "multi_array_list",
2058 target,
20592061 &.{
20602062 .{
20612063 .path = "main.zig",
......@@ -2306,22 +2308,26 @@ pub fn addTestsForTarget(db: *Debugger, target: *const Target) void {
23062308 \\(lldb) breakpoint delete --force 1
23072309 \\1 breakpoints deleted; 0 breakpoint locations disabled.
23082310 },
2311 .{ .skip_new_linker = true },
23092312 );
23102313}
23112314
23122315const File = struct { import: ?[]const u8 = null, path: []const u8, source: []const u8 };
23132316
2317const TestOptions = struct {
2318 skip_new_linker: bool = false,
2319};
2320
23142321fn addGdbTest(
23152322 db: *Debugger,
23162323 name: []const u8,
2317 target: *const Target,
23182324 files: []const File,
23192325 commands: []const u8,
23202326 expected_output: []const []const u8,
2327 options: TestOptions,
23212328) void {
23222329 db.addTest(
23232330 name,
2324 target,
23252331 files,
23262332 &.{},
23272333 &.{
......@@ -2331,24 +2337,22 @@ fn addGdbTest(
23312337 },
23322338 "set remotetimeout 0",
23332339 commands,
2334 &.{
2335 "--args",
2336 },
2340 &.{"--args"},
23372341 expected_output,
2342 options,
23382343 );
23392344}
23402345
23412346fn addLldbTest(
23422347 db: *Debugger,
23432348 name: []const u8,
2344 target: *const Target,
23452349 files: []const File,
23462350 commands: []const u8,
23472351 expected_output: []const []const u8,
2352 options: TestOptions,
23482353) void {
23492354 db.addTest(
23502355 name,
2351 target,
23522356 files,
23532357 &.{.{ "LANG", "C.UTF-8" }}, // affects output formatting
23542358 &.{
......@@ -2358,10 +2362,9 @@ fn addLldbTest(
23582362 },
23592363 "settings set plugin.process.gdb-remote.packet-timeout 0",
23602364 commands,
2361 &.{
2362 "--",
2363 },
2365 &.{"--"},
23642366 expected_output,
2367 options,
23652368 );
23662369}
23672370
......@@ -2373,7 +2376,6 @@ const success = 99;
23732376fn addTest(
23742377 db: *Debugger,
23752378 name: []const u8,
2376 target: *const Target,
23772379 files: []const File,
23782380 env: []const struct { []const u8, []const u8 },
23792381 db_argv1: []const []const u8,
......@@ -2381,57 +2383,85 @@ fn addTest(
23812383 commands: []const u8,
23822384 db_argv2: []const []const u8,
23832385 expected_output: []const []const u8,
2386 options: TestOptions,
23842387) void {
23852388 if (db.options.test_filters.len > 0) {
23862389 for (db.options.test_filters) |test_filter| {
23872390 if (std.mem.find(u8, name, test_filter) != null) break;
23882391 } else return;
23892392 }
2390 if (db.options.test_target_filters.len > 0) {
2391 const triple_txt = target.resolved.query.zigTriple(db.b.allocator) catch @panic("OOM");
2392 for (db.options.test_target_filters) |filter| {
2393 if (std.mem.find(u8, triple_txt, filter) != null) break;
2394 } else return;
2395 }
2396 const files_wf = db.b.addWriteFiles();
23972393
2398 const mod = db.b.createModule(.{
2399 .target = target.resolved,
2400 .root_source_file = files_wf.add(files[0].path, files[0].source),
2401 .optimize = target.optimize_mode,
2402 .link_libc = target.link_libc,
2403 .single_threaded = target.single_threaded,
2404 .pic = target.pic,
2405 .strip = false,
2406 });
2394 const wf = db.b.addWriteFiles();
2395 const root_source_file = wf.add(files[0].path, files[0].source);
2396 var imports: std.array_hash_map.String(*std.Build.Module) = .empty;
24072397 for (files[1..]) |file| {
2408 const path = files_wf.add(file.path, file.source);
2409 if (file.import) |import| mod.addImport(import, db.b.createModule(.{
2398 const path = wf.add(file.path, file.source);
2399 if (file.import) |import| imports.putNoClobber(db.b.allocator, import, db.b.createModule(.{
24102400 .root_source_file = path,
2411 }));
2401 })) catch @panic("OOM");
24122402 }
2413
2414 const exe = db.b.addExecutable(.{
2415 .name = name,
2416 .root_module = mod,
2417 .use_llvm = false,
2418 .use_lld = false,
2419 });
2420
2421 const commands_wf = db.b.addWriteFiles();
2422 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target.test_name_suffix }));
2423 for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]);
2424 run.addArgs(db_argv1);
2425 run.addFileArg(commands_wf.add(
2403 const commands_file = wf.add(
24262404 db.b.fmt("{s}.cmd", .{name}),
24272405 db.b.fmt("{s}\n\n{s}\n\nquit {d}\n", .{ db_commands, commands, success }),
2428 ));
2429 run.addArgs(db_argv2);
2430 run.addArtifactArg(exe);
2431 for (expected_output) |expected| run.addCheck(.{ .expect_stdout_match = db.b.fmt("{s}\n", .{expected}) });
2432 run.addCheck(.{ .expect_term = .{ .exited = success } });
2433 run.setStdIn(.{ .bytes = "" });
2434 db.root_step.dependOn(&run.step);
2406 );
2407
2408 for (db.test_matrix) |test_target| {
2409 if (options.skip_new_linker and test_target.linker == .new) continue;
2410
2411 const resolved_target = db.b.resolveTargetQuery(test_target.target);
2412
2413 const target_str = db.b.fmt("{s}{s}{s}", .{
2414 resolved_target.query.zigTriple(db.b.allocator) catch @panic("OOM"),
2415 switch (test_target.linker) {
2416 .default, .old => "",
2417 .new => "-new-linker",
2418 },
2419 if (test_target.pic == true) "-pic" else "",
2420 });
2421
2422 if (db.options.test_target_filters.len > 0) {
2423 for (db.options.test_target_filters) |filter| {
2424 if (std.mem.find(u8, target_str, filter) != null) break;
2425 } else continue;
2426 }
2427
2428 const mod = db.b.createModule(.{
2429 .target = resolved_target,
2430 .root_source_file = root_source_file,
2431 .optimize = test_target.optimize_mode,
2432 .link_libc = test_target.link_libc,
2433 .single_threaded = test_target.single_threaded,
2434 .pic = test_target.pic,
2435 .strip = false,
2436 });
2437 for (imports.keys(), imports.values()) |import_name, import_mod|
2438 mod.addImport(import_name, import_mod);
2439
2440 const exe = db.b.addExecutable(.{
2441 .name = name,
2442 .root_module = mod,
2443 .use_llvm = false,
2444 .use_lld = false,
2445 });
2446 exe.use_new_linker = switch (test_target.linker) {
2447 .default => null,
2448 .old => false,
2449 .new => true,
2450 };
2451
2452 const run = std.Build.Step.Run.create(db.b, db.b.fmt("run {s} {s}", .{ name, target_str }));
2453 for (env) |env_var| run.setEnvironmentVariable(env_var[0], env_var[1]);
2454 run.addArgs(db_argv1);
2455 run.addFileArg(commands_file);
2456 run.addArgs(db_argv2);
2457 run.addArtifactArg(exe);
2458 for (expected_output) |expected| run.addCheck(.{
2459 .expect_stdout_match = db.b.fmt("{s}\n", .{expected}),
2460 });
2461 run.addCheck(.{ .expect_term = .{ .exited = success } });
2462 run.setStdIn(.{ .bytes = "" });
2463 db.root_step.dependOn(&run.step);
2464 }
24352465}
24362466
24372467const Debugger = @This();
test/tests.zig+41-18
......@@ -2303,6 +2303,45 @@ const incremental_targets = &[_]IncrementalTarget{
23032303 },
23042304};
23052305
2306const debugger_matrix: []const DebuggerContext.TestTarget = &.{
2307 .{
2308 .target = .{
2309 .cpu_arch = .x86_64,
2310 .os_tag = .linux,
2311 .abi = .none,
2312 },
2313 .pic = false,
2314 .linker = .old,
2315 },
2316 .{
2317 .target = .{
2318 .cpu_arch = .x86_64,
2319 .os_tag = .linux,
2320 .abi = .none,
2321 },
2322 .pic = true,
2323 .linker = .old,
2324 },
2325 .{
2326 .target = .{
2327 .cpu_arch = .x86_64,
2328 .os_tag = .linux,
2329 .abi = .none,
2330 },
2331 .pic = false,
2332 .linker = .new,
2333 },
2334 .{
2335 .target = .{
2336 .cpu_arch = .x86_64,
2337 .os_tag = .linux,
2338 .abi = .none,
2339 },
2340 .pic = true,
2341 .linker = .new,
2342 },
2343};
2344
23062345fn compatible32bitArch(host: *const std.Target) ?std.Target.Cpu.Arch {
23072346 return switch (host.os.tag) {
23082347 .freebsd => switch (host.cpu.arch) {
......@@ -3323,25 +3362,9 @@ pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step
33233362 .b = b,
33243363 .options = options,
33253364 .root_step = step,
3365 .test_matrix = debugger_matrix,
33263366 };
3327 context.addTestsForTarget(&.{
3328 .resolved = b.resolveTargetQuery(.{
3329 .cpu_arch = .x86_64,
3330 .os_tag = .linux,
3331 .abi = .none,
3332 }),
3333 .pic = false,
3334 .test_name_suffix = "x86_64-linux",
3335 });
3336 context.addTestsForTarget(&.{
3337 .resolved = b.resolveTargetQuery(.{
3338 .cpu_arch = .x86_64,
3339 .os_tag = .linux,
3340 .abi = .none,
3341 }),
3342 .pic = true,
3343 .test_name_suffix = "x86_64-linux-pic",
3344 });
3367 context.addTests();
33453368 return step;
33463369}
33473370