Skip to content

Incorrect DWARF Symbols for Inline Functions #17444

@jcalabro

Description

@jcalabro

Zig Version

0.12.0-dev.800+a9b37ac63

Steps to Reproduce and Observed Behavior

Apologies if this has been mentioned before, I tried searching the issue tracker but nothing that appeared to be relevant came up.

A minimal repro is the following on Linux, compiled with zig build-exe main.zig:

const print = @import("std").debug.print;

inline fn myFunc() void {
    print("C\n", .{});
}

pub fn main() !void {
    print("A\n", .{});
    print("B\n", .{});

    myFunc();
}

Which outputs the following DWARF .debug_line info (I've copied the relevant section via dwarfdump only):

...
0x0021da80  [   7, 0] NS uri: "/path/to/main.zig"
0x0021da84  [   8,10] NS PE
0x0021da89  [   9,10] NS
0x0021da8e  [   8,10] NS
0x0021da95  [   8,10] ET EB
...

And here's that same info in a format closer to what the DWARF file format is actually doing, via readelf --debug-dump=line main:

...
[0x00000889]  Special opcode 103: advance Address by 7 to 0x21da80 and Line by 0 to 7
[0x0000088a]  Set column to 10
[0x0000088c]  Set prologue_end to true
[0x0000088d]  Special opcode 62: advance Address by 4 to 0x21da84 and Line by 1 to 8
[0x0000088e]  Special opcode 76: advance Address by 5 to 0x21da89 and Line by 1 to 9
[0x0000088f]  Special opcode 74: advance Address by 5 to 0x21da8e and Line by -1 to 8
[0x00000890]  Set is_stmt to 0
[0x00000891]  Set epilogue_begin to true
...

This unfortunately leads to a choppy experience when using the debugger. I've captured an example in gdb, though it's the same in VS Code since neither has a correct source of truth from which to read:

Screencast.from.2023-10-08.23-27-15.webm

Though not-very-rigorous poking around, it appears that when you call an inline funciton, it always outputs its line numbers as the start of the current function, then offsets you by one for each line in the inline function. So a longer example that demonstrates this is:

const print = @import("std").debug.print;

inline fn myFunc() void {
    print("C\n", .{});
    print("D\n", .{});
    print("E\n", .{});
}

pub fn main() !void {
    print("A\n", .{});
    print("B\n", .{});

    myFunc();

    print("F\n", .{});
    print("G\n", .{});

    myFunc();
}

Which results in:

0x0021dd40  [   9, 0] NS uri: "/path/to/main.zig"
0x0021dd44  [  10,10] NS PE
0x0021dd49  [  11,10] NS
0x0021dd4e  [  10,10] NS
0x0021dd53  [  11,10] NS
0x0021dd58  [  12,10] NS
0x0021dd5d  [  15,10] NS
0x0021dd62  [  16,10] NS
0x0021dd67  [  10,10] NS
0x0021dd6c  [  11,10] NS
0x0021dd71  [  12,10] NS
0x0021dd78  [  12,10] ET EB

Expected Behavior

The compiler should output the correct line numbers for the inline function, i.e. perhaps something like this after digging in to what clang/gcc output:

...
0x0021da80  [   7, 0] NS uri: "/path/to/main.zig"
0x0021da84  [   8,10] NS PE
0x0021da89  [   9,10] NS
0x0021da8e  [  11,10] NS
0x0021da8e  [   3,10] NS
0x0021da8e  [   4,10] NS
0x0021da95  [   4,10] ET EB
...

Notice that the PC 0x0021da8e is repeated a few times. That's what achieves the look and feel of a function with a normal calling convention in the debugger.

Note that when you don't have inline fn myFunc and instead have normal zig calling convention with fn myFunc, the output symbols are correct. Two functions are defined, and all the PE/NS are correct. Here is that dwarfdump:

...
0x0021dab0  [   7, 0] NS uri: "/path/to/main.zig"
0x0021dab4  [   8,10] NS PE
0x0021dab9  [   9,10] NS
0x0021dabe  [  11,11] NS
0x0021dac5  [  11,11] ET EB                                                                                                                                                                         
...

0x0021dc50  [   3, 0] NS uri: "/path/to/main.zig"
0x0021dc54  [   4,10] NS PE
0x0021dc59  [   4,10] ET EB
...

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behaviorfrontendTokenization, parsing, AstGen, Sema, and Liveness.regressionIt worked in a previous version of Zig, but stopped working.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions