ldc-developers / ldc

The LLVM-based D Compiler.
http://wiki.dlang.org/LDC
Other
1.19k stars 258 forks source link

Wrong breakpoint locations for D main function #3689

Open quickfur opened 3 years ago

quickfur commented 3 years ago
import std;
void fun(void delegate() dg) {
    dg();
}
void main() {
    int x = 123;
    string y = "abc";
    writeln(y);
    fun({
        x++;
        y ~= "d";
    });
}

Compile with ldc2 -g prog.d. Inside gdb, set a breakpoint for prog.main:

(gdb) break prog.main
Breakpoint 1 at 0x295b8: file prog.d, line 10.
(gdb) run
Starting program: /tmp/prog 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
abc

Breakpoint 1, prog.main().__lambda1() () at prog.d:10
10          x++;
(gdb) bt
#0  prog.main().__lambda1() () at prog.d:10
#1  0x000055555557d48a in prog.fun(void() delegate) (dg=...) at prog.d:3
#2  0x000055555557d4df in D main () at prog.d:9

The breakpoint apparently was set inside the delegate, rather than the body of main proper. As the stacktrace and output abc show, main has already run past the writeln and has entered fun and subsequently called the delegate.

Expected behaviour: setting a breakpoint in prog.main ought to break inside the function body, not inside a delegate!

DMD appears to have the same bug, so could be a frontend issue: https://issues.dlang.org/show_bug.cgi?id=21770

kinke commented 3 years ago

I rather suspect a gdb problem wrt. special _Dmain mangling.

quickfur commented 3 years ago

But isn't it the compiler's job to emit the necessary debugging information so that gdb understands that main and prog.main point to the same thing?

kinke commented 3 years ago

I think the D main special case is pretty clear - it's mangled as _Dmain without any module parent, and its pretty name is D main. It's a total special case. I don't know whether gdb can safely be taught that some symbol ending with .main can be a D main; @ibuclaw probably knows best as he's worked on gdb's D support AFAIK.

ibuclaw commented 3 years ago

I think the D main special case is pretty clear - it's mangled as _Dmain without any module parent, and its pretty name is D main. It's a total special case. I don't know whether gdb can safely be taught that some symbol ending with .main can be a D main; @ibuclaw probably knows best as he's worked on gdb's D support AFAIK.

I suspect it'd have to be added to the lookup table along with D main when it (gdb) reads in and demangles all symbols (from the dwarf debug code).

Regardless, a better way of setting a breakpoint at D main is just to run start. No need do break and run individually.

quickfur commented 3 years ago

Regardless, a better way of setting a breakpoint at D main is just to run start. No need do break and run individually.

That's not really the complaint here. The complaint is that the user types break prog.main and gets a breakpoint inside one of the nested functions instead. At the very least one would expect some sort of error "sorry I don't know of such a symbol" rather than silently accepting it but with subtly different semantics.

ibuclaw commented 3 years ago

That's not really the complaint here. The complaint is that the user types break prog.main and gets a breakpoint inside one of the nested functions instead. At the very least one would expect some sort of error "sorry I don't know of such a symbol" rather than silently accepting it but with subtly different semantics.

~Checked on gdb 9.2 and 10.1 - (edit: and also checked 11.0-git just now as well) - and can't reproduce your issue with any D compiler.~

Update: Oh, the example code was missing a module declaration. Reproducible now.

JohanEngelen commented 3 years ago

The complaint is that the user types break prog.main and gets a breakpoint inside one of the nested functions instead. At the very least one would expect some sort of error "sorry I don't know of such a symbol" rather than silently accepting it but with subtly different semantics.

I disagree. The debugger is trying to help the user, by autocompleting the function name that you wrote down. You can easily see in the backtrace that the autocompletion did not complete to the function that you desired, so you know that you should be more specific/change the function name when setting the breakpoint. The autocomplete functionality is a user-friendliness feature and I reckon most people like it.

ibuclaw commented 3 years ago

The complaint is that the user types break prog.main and gets a breakpoint inside one of the nested functions instead. At the very least one would expect some sort of error "sorry I don't know of such a symbol" rather than silently accepting it but with subtly different semantics.

I disagree. The debugger is trying to help the user, by autocompleting the function name that you wrote down. You can easily see in the backtrace that the autocompletion did not complete to the function that you desired, so you know that you should be more specific/change the function name when setting the breakpoint. The autocomplete functionality is a user-friendliness feature and I reckon most people like it.

Auto-completion kicks in when you press the tab key. The other side of expanding matches is setting breakpoints in multiple locations for overloaded functions, which should not be happening here either.

If there is an issue to be raised, it should be against gdb (https://sourceware.org/bugzilla/buglist.cgi?product=gdb&component=d), not the compilers.

quickfur commented 3 years ago

All raised concerns, including my own, would be solved if the compiler emitted "prog.main" as an alias for _Dmain. :-) Is such a thing possible?