Skip to content

Add debug info for inlined calls #11177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 16, 2022
Merged

Add debug info for inlined calls #11177

merged 4 commits into from
Mar 16, 2022

Conversation

Vexu
Copy link
Member

@Vexu Vexu commented Mar 15, 2022

Add dbg_inline_{begin,end} emitted around an inlined call so that inlined dbg_line instructions will emit debug info pointing to the correct source function.

pub fn main() void {
    var a: u32 = 0;
    a += 
    // dbg_inline_begin foo
        @import("b.zig").foo();
    // dbg_inline_end main
    if (a != 15) @breakpoint();
}
// b.zig
pub inline fn foo() u32 {
    var c: u32 = 3;
    return c * (c + 2);
}

I'm not sure if this works currently... I managed to break my system to a point where I can't build master branch stage2 with a clean cache without an assertion failure.

Closes #11158
Closes #11160

@andrewrk
Copy link
Member

andrewrk commented Mar 16, 2022

rename dbg_stmt to dbg_line

In DWARF, there is a flag is_stmt that goes into the line/column info that marks whether a location begins a statement. It looks like LLVM does not expose this, but I think the other backends probably care about it.

Should we make the AIR instruction dbg_line instead of dbg_stmt? Maybe. I'm not against it. But I do think that having dbg_stmt correspond to setting is_stmt=true in DWARF is a reasonable way to go. I get that the condition of an if is not really a statement according to Zig but maybe making it a statement according to debug info is the way that makes it work well? 🤷

@Vexu
Copy link
Member Author

Vexu commented Mar 16, 2022

Got this to work. Not sure what that syntax error is about? Also should symbols from the parent function be visible in the inlined function and vice-versa? Currently they aren't but it should be easy to change by removing the lexical scopes.

(gdb) b a.main
Breakpoint 1 at 0x201b54: file a.zig, line 15.
(gdb) r
Starting program: /home/vexu/Documents/zig/zig/a 

Breakpoint 1, a.main () at a.zig:15
15          var a: u32 = 0;
(gdb) s
16          a +=
(gdb) p a
$1 = 0
(gdb) p c
No symbol "c" in current context.
(gdb) s
18              @import("b.zig").foo();
(gdb) s
b.foo () at b.zig:2
2           var c: u32 = 3;
(gdb) p a
A syntax error in expression, near `'.
(gdb) p c
$2 = 0
(gdb) s
3           return c * (c + 2);
(gdb) 
a.main () at a.zig:20
20          if (a != 15) @breakpoint();
(gdb) p a
$3 = 15
(gdb) p c
No symbol "c" in current context.

@ifreund
Copy link
Member

ifreund commented Mar 16, 2022

Also should symbols from the parent function be visible in the inlined function and vice-versa? Currently they aren't but it should be easy to change by removing the lexical scopes.

I think making symbols from the parent visible would be confusing. Also there might be symbol conflicts right? In your example code it would be perfectly valid to rename c to a.

@andrewrk
Copy link
Member

andrewrk commented Mar 16, 2022

One data point would be looking at what stage1 does (e.g. what LLVM does) for an inlined function from another file with different things in scope. We can recreate this scenario:

test1.zig

const test2_foo = @import("test2.zig").foo;
pub fn main() void {
    var x: i32 = 42;
    test2_foo();
}

test2.zig

pub inline fn foo() void {
    var x: i32 = 1234;
    x += 1;
}

I'm not sure I have an opinion on this one (yet?). Happy to go with whatever feels best to you @Vexu.

@Vexu
Copy link
Member Author

Vexu commented Mar 16, 2022

It seems stage1 and 2 behave the same on this, I think I just got confused by the different behavior when the variable is not in scope:

// stage1
(gdb) p c
$2 = c
// stage2
(gdb) p c
No symbol "c" in current context.

Seems like we should also add dbg_block_{begin,end} to be able match stage1:

pub fn main() void {
    var a: u32 = 0;
    {
        var b: u32 = a;
        if (b != 0) unreachable;
    }
    if (a != 0) unreachable;
}
// stage1
29          if (a != 0) unreachable;
(gdb) p a
$1 = 0
(gdb) p b
No symbol "b" in current context.
// stage2 
29          if (a != 0) unreachable;
(gdb) p a
$1 = 0
(gdb) p b
$2 = 0

@Vexu Vexu merged commit 49c0bb1 into ziglang:master Mar 16, 2022
@Vexu Vexu deleted the dbg_func branch March 16, 2022 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

make else if conditions contain debug stmt info make function calls contain debug stmt line/column info
3 participants