zig icon indicating copy to clipboard operation
zig copied to clipboard

std.debug: DWARFv5 debug info sometimes causes a failed stack trace

Open topolarity opened this issue 1 year ago • 4 comments

Zig Version

0.10.0-dev.2993+0248073b9

Steps to Reproduce

// build.zig
const Builder = @import("std").build.Builder;
pub fn build(b: *Builder) void {
    const exe = b.addExecutable("test", "test.zig");
    exe.addCSourceFile("test.c", &[_][]const u8{
        "-std=c99",
        "-gdwarf-5", // Bad stack trace
        //"-gdwarf-4", // works
    });
    exe.install();

    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}
// test.zig
extern fn baz(x: c_int) c_int;

pub fn main() void {
    _ = baz(15);
}
// test.c
int foo(int x) {
	*(int*)0 = 10; // Intentionally trigger SEGFAULT
	return x + 2;
}
int bar(int x) {
	return foo(x + 16);
}
int baz(int x) {
	return 2 * bar(x);
}

Expected Behavior

$ ../zig/build/zig build run
Illegal instruction at address 0x205211
/home/topolarity/repos/test/test.c:2:11: 0x205211 in foo (/home/topolarity/repos/test/test.c)
        *(int*)0 = 10; // Intentionally trigger SEGFAULT
          ^
/home/topolarity/repos/test/test.c:7:9: 0x20526c in bar (/home/topolarity/repos/test/test.c)
        return foo(x + 16);
        ^
/home/topolarity/repos/test/test.c:11:13: 0x205292 in baz (/home/topolarity/repos/test/test.c)
        return 2 * bar(x);
            ^
/home/topolarity/repos/test/test.zig:4:12: 0x227a0d in main (test)
    _ = baz(15);
           ^
/home/topolarity/repos/zig/lib/std/start.zig:570:22: 0x207033 in std.start.posixCallMainAndExit (test)
            root.main();
                     ^
/home/topolarity/repos/zig/lib/std/start.zig:338:5: 0x206df2 in std.start._start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
The following command terminated unexpectedly:
cd /home/topolarity/repos/test && /home/topolarity/repos/test/zig-out/bin/test
error: the following build command failed with exit code 1:
/home/topolarity/repos/test/zig-cache/o/c6e3ef0111461e363fabeadc1273799f/build /home/topolarity/repos/zig/build/zig /home/topolarity/repos/test/home/topolarity/repos/test/zig-cache /home/topolarity/.cache/zig run

Actual Behavior

$ ../zig/build/zig build run
Illegal instruction at address 0x205211
???:?:?: 0x205211 in ??? (???)
???:?:?: 0x20526c in ??? (???)
???:?:?: 0x205292 in ??? (???)
???:?:?: 0x227a0d in ??? (???)
???:?:?: 0x207033 in ??? (???)
???:?:?: 0x206df2 in ??? (???)
The following command terminated unexpectedly:
cd /home/topolarity/repos/test && /home/topolarity/repos/test/zig-out/bin/test
error: the following build command failed with exit code 1:
/home/topolarity/repos/test/zig-cache/o/2117e822669df035365d51266c2c619d/build /home/topolarity/repos/zig/build/zig /home/topolarity/repos/test/home/topolarity/repos/test/zig-cache /home/topolarity/.cache/zig run

topolarity avatar Jul 14 '22 17:07 topolarity

Note that DWARFv5 is the default in clang now on many systems, so it's actually quite easy to hit this with just -g

topolarity avatar Jul 14 '22 17:07 topolarity

In this case we hit https://github.com/ziglang/zig/blob/master/lib/std/dwarf.zig#L539 with a form_id of 0x25. It seems DW_FORM_strx1 and possibly others form types aren't implemented. https://www.dwarfstd.org/doc/DWARF5.pdf#chap%3ADWFORMstrxone DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, and DW_FORM_strx4 seem to be used to index into a debug_str_offsets section, which we have to add here: https://github.com/ziglang/zig/blob/master/lib/std/debug.zig#L922

wooster0 avatar Jul 14 '22 20:07 wooster0

I'm running into this same issue. If no-one else is working on it I can see about implementing support for DW_FORM_strx* based strings.

kdchambers avatar Jul 27 '22 23:07 kdchambers

I believe it's almost all of the new attribute forms for v5 that still need to be added (they are listed in the spec)

The issue is up for grabs, if you'd like to take a whack!

topolarity avatar Jul 27 '22 23:07 topolarity

Although #12270 was a step in the right direction, this still reproduces on my machine (Zig 0.10.0-dev.3702+583175dc1).

To summarize the missing DWARFv5 support:

  1. Several new forms: strx, addrx, addrx1, addrx2, addrx3, addrx4, data16, implicit_const, line_strp, loclistx, rnglistx, ref_sup4, ref_sup8, strp_sup
  2. V5 layout/header for the .debug_info section

topolarity avatar Aug 23 '22 16:08 topolarity

Ah thanks for reopening, I'm not sure why I closed it without checking the test case in the OP.

andrewrk avatar Aug 23 '22 18:08 andrewrk

The comment at the top of the .zig file helped reveal #12610, so thank you for that. As for DWARFv5, here's 0.9.1 vs the commit I just pushed:

0.9.1

$ ~/Downloads/zig-linux-x86_64-0.9.1/zig build-exe test.zig test.c &
& ./test
Illegal instruction at address 0x204d8c
/home/andy/dev/zig/build-release/test.c:3:14: 0x204d8c in baz (test.c)
    *(int*)0 = 10; // Intentionally trigger SEGFAULT
             ^
/home/andy/dev/zig/build-release/test.zig:4:12: 0x22cced in main (test)
    _ = baz(15);
           ^
/home/andy/Downloads/zig-linux-x86_64-0.9.1/lib/std/start.zig:551:22: 0x2263fc in std.start.callMain (test)
            root.main();
                     ^
/home/andy/Downloads/zig-linux-x86_64-0.9.1/lib/std/start.zig:495:12: 0x20701e in std.start.callMainWithArgs (test)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/home/andy/Downloads/zig-linux-x86_64-0.9.1/lib/std/start.zig:409:17: 0x2060b6 in std.start.posixCallMainAndExit (test)
    std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
                ^
/home/andy/Downloads/zig-linux-x86_64-0.9.1/lib/std/start.zig:322:5: 0x205ec2 in std.start._start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
Aborted (core dumped)

master

$ stage2/bin/zig build-exe test.zig test.c && ./test
Illegal instruction at address 0x20ccd1
/home/andy/dev/zig/build-release/test.c:3:14: 0x20ccd1 in foo (test.c)
    *(int*)0 = 10; // Intentionally trigger SEGFAULT
             ^
/home/andy/dev/zig/build-release/test.c:7:12: 0x20cd2c in bar (test.c)
    return foo(x + 16);
           ^
/home/andy/dev/zig/build-release/test.c:10:16: 0x20cd52 in baz (test.c)
    return 2 * bar(x);
               ^
./test.zig:4:12: 0x20dd4d in main (test)
    _ = baz(15);
           ^
/home/andy/dev/zig/lib/std/start.zig:564:22: 0x20d62d in posixCallMainAndExit (test)
            root.main();
                     ^
/home/andy/dev/zig/lib/std/start.zig:336:5: 0x20d032 in _start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
Aborted (core dumped)

So you can see that master branch outperforms 0.9.1 because some of the C stack frames that were missing with 0.9.1 are present with master branch.

andrewrk avatar Aug 24 '22 04:08 andrewrk