www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to debug D on Linux

reply Roguish <nospam nospam.net> writes:
How to debug D? My little trial app gives a segmentation fault. 
Probably a null pointer somewhere, which I could find simply by 
reading my code. But I'm puzzled that the program outputs very 
little helpful info when it crashes, even though I've compiled 
with all the debug options I could find in the docs:

    -g -gs -gf -debug -d-debug

Still all I get at runtime is

    Segmentation fault (core dumped)

Surely it should be possible to get at least a stack trace?
Jan 13 2021
parent reply Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 13:22:01 UTC, Roguish wrote:
 How to debug D?  be possible to get at least a stack trace?
I've discovered that GDB works with the binary generated by the D compiler, so that's great. Anything else I need to know when debugging on Linux, without an IDE?
Jan 13 2021
parent reply Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 13:30:48 UTC, Roguish wrote:
 Anything else I need to know when debugging on Linux, without 
 an IDE?
One specific question I have is: what's the difference between -g and -debug and -d-debug? Also, what does it mean to "always emit a stackframe" (compiler option -gs) ?
Jan 13 2021
next sibling parent drug <drug2004 bk.ru> writes:
On 1/13/21 4:47 PM, Roguish wrote:
 On Wednesday, 13 January 2021 at 13:30:48 UTC, Roguish wrote:
 Anything else I need to know when debugging on Linux, without an IDE?
One specific question I have is: what's the difference between -g and -debug and -d-debug? Also, what does it mean to "always emit a stackframe" (compiler option -gs) ?
https://stackoverflow.com/questions/17392200/debugging-dmd-generate-program-through-gdb
Jan 13 2021
prev sibling next sibling parent reply drug <drug2004 bk.ru> writes:
On 1/13/21 4:47 PM, Roguish wrote:
 
 Also, what does it mean to "always emit a stackframe" (compiler option 
 -gs) ?
Short answer - sometimes the compiler does not emit a stackframe (due to optimization for example). In general if you are able to debug your binary by gdb then you don't need to worry this flag. I skip long answer, sorry :-) But you can google about stack frame.
Jan 13 2021
parent Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 14:13:07 UTC, drug wrote:
 Short answer - sometimes the compiler does not emit a 
 stackframe (due to optimization for example).
OK, so -gs prevents a certain optimization that would make debugging harder in certain situations. Thanks for clearing that up.
Jan 13 2021
prev sibling next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 13 January 2021 at 13:47:55 UTC, Roguish wrote:
 One specific question I have is: what's the difference between 
 -g and -debug and -d-debug?
-debug enables the `debug` keyword inside the D code itself. This lets you bypass other rules temporarily. For example void foo() pure { writeln("called foo"); } Normally, that wouldn't compile, since writeln is not pure. But if you do void foo() pure { debug writeln("called foo"); } It is allowed. Without the `-debug` switch, that line is just ignored, it is not compiled. With the `-debug` switch, that line is allowed - and it bypasses the pure restriction. It does NOT do anything related to running D in debuggers like gdb, it just enables code guarded by that debug keyword.
 -g
-g is what compiles in the information gdb uses. This info is used to print function names in stack traces, make breakpoints by file and line number, etc. You can use -g and -debug together or independently or whatever depending on what exactly you want to do. Now, some general tips on using D with gdb: * Segfaults should be run inside the debugger to get the stack trace. If your program did "Segmentation fault (core dumped)", you can fire up gdb after the fact on it. Check that directory for a .core file and then run `gdb program that.core` to inspect it. * Running a program in gdb may sometimes say "program received SIGUSR1" and pause. The commands handle SIGUSR1 noprint handle SIGUSR2 noprint will skip this. SIGUSR1/2 are used by the GC when doing collections so you probably don't care about it. You can put those commands i your ~/.gdbinit to run every time. * Running `gdb --args ./yourprogram --DRT-trapExceptions=0` will break on any uncaught exception so you can inspect that stuff. Super useful if you get one of those.
Jan 13 2021
parent Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 14:13:11 UTC, Adam D. Ruppe 
wrote:
 -debug enables the `debug` keyword inside the D code itself. 
 This lets you bypass other rules temporarily. For example

 ...

 It does NOT do anything related to running D in debuggers like 
 gdb, it just enables code guarded by that debug keyword.
Thanks, that's very clear.
 * Segfaults should be run inside the debugger to get the stack 
 trace. If your program did "Segmentation fault (core dumped)", 
 you can fire up gdb after the fact on it. Check that directory 
 for a .core file and then run `gdb program that.core` to 
 inspect it.
It seems on my system no .core file gets generated, even though the program outputs "Segmentation fault (core dumped)". At least it's not present in the directory from where I compile and run the program, nor is it in /var/lib/systemd/coredump where, according to systemd-coredump's documentation, it should go by default. Anyway, I'm guessing this is a config problem with my Linux, rather than anything to do with D's compiler or runtime.
 * Running a program in gdb may sometimes say "program received 
 SIGUSR1" and pause.

 The commands

 handle SIGUSR1 noprint
 handle SIGUSR2 noprint

 will skip this. SIGUSR1/2 are used by the GC when doing 
 collections so you probably don't care about it. You can put 
 those commands i your ~/.gdbinit to run every time.

 * Running `gdb --args ./yourprogram --DRT-trapExceptions=0` 
 will break on any uncaught exception so you can inspect that 
 stuff. Super useful if you get one of those.
Yes! Excellent tips these. Thank you.
Jan 13 2021
prev sibling next sibling parent reply evilrat <evilrat666 gmail.com> writes:
if you are looking for back trace someone recently posted a hint 
for linux where there is no back trace by default is to import 
core.sys.linux.backtrace or something that has back trace info 
and using it in exception handler for runtime to print the stack 
trace.
https://dlang.org/phobos/core_runtime.html#.defaultTraceHandler


On Wednesday, 13 January 2021 at 13:47:55 UTC, Roguish wrote:
 One specific question I have is: what's the difference between 
 -g and -debug and -d-debug?
no idea what is -d-debug, but -g will emit debug info for debugger, and -debug will turn on certain features such as contracts and asserts even in release builds.
Jan 13 2021
parent Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 14:13:17 UTC, evilrat wrote:
 if you are looking for back trace someone recently posted a 
 hint for linux where there is no back trace by default is to 
 import core.sys.linux.backtrace or something that has back 
 trace info and using it in exception handler for runtime to 
 print the stack trace.
 https://dlang.org/phobos/core_runtime.html#.defaultTraceHandler
Good tip, thanks.
Jan 13 2021
prev sibling next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On Wednesday, 13 January 2021 at 13:47:55 UTC, Roguish wrote:
 On Wednesday, 13 January 2021 at 13:30:48 UTC, Roguish wrote:
 Anything else I need to know when debugging on Linux, without 
 an IDE?
One specific question I have is: what's the difference between -g and -debug and -d-debug?
From LDC (ldc specific): --d-debug[=<level/idents>] - Compile in debug code >= <level> or identified by <idents> --d-version=<level/idents> - Compile in version code >= <level> or identified by <idents> From dmd: -debug compile in debug code -debug=<level> compile in debug code <= level -debug=<ident> compile in debug code identified by ident -version=<level> compile in version code >= level -version=<ident> compile in version code identified by ident Same thing.
Jan 13 2021
parent reply Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 14:17:51 UTC, Rikki Cattermole 
wrote:
 Same thing.
Clear, thanks. I'm just discovering today that DMD and LDC are two different compilers. I got a different impression from the following webpage, which claims that ldmd2 is a wrapper invoking ldc2. https://stackoverflow.com/questions/35515138/ldc2-vs-ldmd2-whats-the-difference Perhaps this is just a peculiarity of how D is distributed on Debian? I simply installed the 'ldc' package from Debian's official repos, and that contains both a binary called ldc2 and one called ldmd2.
Jan 13 2021
parent Daniel Kozak <kozzi11 gmail.com> writes:
On Wed, Jan 13, 2021 at 4:10 PM Roguish via Digitalmars-d-learn <
digitalmars-d-learn puremagic.com> wrote:

 On Wednesday, 13 January 2021 at 14:17:51 UTC, Rikki Cattermole
 wrote:
 Same thing.
Clear, thanks. I'm just discovering today that DMD and LDC are two different compilers. I got a different impression from the following webpage, which claims that ldmd2 is a wrapper invoking ldc2. https://stackoverflow.com/questions/35515138/ldc2-vs-ldmd2-whats-the-difference Perhaps this is just a peculiarity of how D is distributed on Debian? I simply installed the 'ldc' package from Debian's official repos, and that contains both a binary called ldc2 and one called ldmd2.
There are 3 main compilers which share same frontend, DMD (using own backend), LDC2(llvm backend) a GDC(gcc backend) ldmd and gdmd are some wrappers to make similar interface for compiling with any of these compilers. So generally dmd, gdmd and ldmd2(on some distribution ldmd without 2) should have accept same args So calling <dmd or gdmd or ldmd2> -arg1 -arg2 -arg3 should do the same but with different compilers behind the scene.
Jan 13 2021
prev sibling parent reply user1234 <user1234 12.de> writes:
On Wednesday, 13 January 2021 at 13:47:55 UTC, Roguish wrote:
 On Wednesday, 13 January 2021 at 13:30:48 UTC, Roguish wrote:
 Anything else I need to know when debugging on Linux, without 
 an IDE?
One specific question I have is: what's the difference between -g and -debug and -d-debug? Also, what does it mean to "always emit a stackframe" (compiler option -gs) ?
-g : generate dwarf info, the debug info, the most important -debug : compiles the debug statements, e.g debug logging. not so important, this is a conditional compilation feature. -gs : always emit a prelude/prologue. but dmd pretty much always do that even when not required (sigh). You really mostly only requires -g. Then you have to learn gdb. A few basis to get started, a session for a segfault is often like $ gdb ./myapp $ run and when it crashes, note the source position, additionally $ bt $ p somevar $ p some.more.complex.expression may already give interesting infos. If not, during a second session you will rather put breakpoints to see what happens before the access violation and step from that breakpoint to the code that accesses unowned memory. $ gdb ./myapp $ break <somefile>.d <linenum> $ run and then step by step, each time it pauses you inspect the interesting stuff. Note that I may be wrong on the syntax of the commands as I always use an IDE GUI.
Jan 13 2021
parent Roguish <nospam nospam.net> writes:
On Wednesday, 13 January 2021 at 14:27:48 UTC, user1234 wrote:
 You really mostly only requires -g. Then you have to learn gdb.
 A few basis to get started
I've used GDB before, but I've forgotten nearly all of it. Your recap of the basics is appreciated. :-)
Jan 13 2021