www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Stack tracing on Linux ?

reply Georg Wrede <georg.wrede iki.fi> writes:
With gdb I can either debug a core dump or an actual running process. 
For example, with

import std.stdio;

int main()
{
     readWrite();
     return 8;
}

void readWrite()
{
     auto line = readln();   // here it waits, and that's when I debug
                             // in another window
     write("Rivi oli: ", line);
}

I get the following stack trace (it looks the same whether I debug a 
core dump or a running instance)






     delimiter=10, fp=0x62e420) at iogetdelim.c:79





This is not perfect, 5..7 are functions written in D, but main is 
missing. Then, trying to examine a core dump from something that gets a 
segfault, I wrote the following, expecting that I'd get a grandiose 
stack trace


$ cat npe.d
import std.stdio;

int main()
{
     return foo(3);
}

int foo(int a)
{
     return 1 + bar(a - 3);
}

int bar(int b)
{
     return 1 + car(b - 3);
}

int car(int c)
{
     return 1 + dar(c - 3);
}

int dar(int d)
{
     return 1 + * cast(int*) d; // null pointer exception
}



Turns out I got zilch!




I have DMD on Fedora 10, and used
dmd -g -debug -v read2.d
to compile. Incidentally, using
dmd -gc -debug -v read2.d
does seem to give the same stack trace.
Apr 02 2009
next sibling parent reply "Simon Gomizelj" <simongmzlj gmail.com> writes:
On Thu, 02 Apr 2009 04:56:46 -0400, Georg Wrede <georg.wrede iki.fi> wrote:

 With gdb I can either debug a core dump or an actual running process.  
 For example, with

 import std.stdio;

 int main()
 {
      readWrite();
      return 8;
 }

 void readWrite()
 {
      auto line = readln();   // here it waits, and that's when I debug
                              // in another window
      write("Rivi oli: ", line);
 }

 I get the following stack trace (it looks the same whether I debug a  
 core dump or a running instance)






      delimiter=10, fp=0x62e420) at iogetdelim.c:79





 This is not perfect, 5..7 are functions written in D, but main is  
 missing. Then, trying to examine a core dump from something that gets a  
 segfault, I wrote the following, expecting that I'd get a grandiose  
 stack trace


 $ cat npe.d
 import std.stdio;

 int main()
 {
      return foo(3);
 }

 int foo(int a)
 {
      return 1 + bar(a - 3);
 }

 int bar(int b)
 {
      return 1 + car(b - 3);
 }

 int car(int c)
 {
      return 1 + dar(c - 3);
 }

 int dar(int d)
 {
      return 1 + * cast(int*) d; // null pointer exception
 }



 Turns out I got zilch!




 I have DMD on Fedora 10, and used
 dmd -g -debug -v read2.d
 to compile. Incidentally, using
 dmd -gc -debug -v read2.d
 does seem to give the same stack trace.
While I can't explain why gdb and dmd don't seem to work nicely together, you'd have much better luck using ldc. Compiling with ldc, this is the backtrace I got when debugging read2.d on my maching (and is what you're probably looking for): (gdb) run Starting program: /data/Code/D/error [Thread debugging using libthread_db enabled] [New Thread 0xb7d656c0 (LWP 14104)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7d656c0 (LWP 14104)] 0x080495fe in _D5error3darFiZi (d=-6) at error.d:23 23 return 1 + * cast(int*) d; // null pointer exception (gdb) backtrace -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Apr 03 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Simon Gomizelj wrote:
 On Thu, 02 Apr 2009 04:56:46 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
 
 With gdb I can either debug a core dump or an actual running process. 
 For example, with

 import std.stdio;

 int main()
 {
      readWrite();
      return 8;
 }

 void readWrite()
 {
      auto line = readln();   // here it waits, and that's when I debug
                              // in another window
      write("Rivi oli: ", line);
 }

 I get the following stack trace (it looks the same whether I debug a 
 core dump or a running instance)






      delimiter=10, fp=0x62e420) at iogetdelim.c:79





 This is not perfect, 5..7 are functions written in D, but main is 
 missing. Then, trying to examine a core dump from something that gets 
 a segfault, I wrote the following, expecting that I'd get a grandiose 
 stack trace


 $ cat npe.d
 import std.stdio;

 int main()
 {
      return foo(3);
 }

 int foo(int a)
 {
      return 1 + bar(a - 3);
 }

 int bar(int b)
 {
      return 1 + car(b - 3);
 }

 int car(int c)
 {
      return 1 + dar(c - 3);
 }

 int dar(int d)
 {
      return 1 + * cast(int*) d; // null pointer exception
 }



 Turns out I got zilch!




 I have DMD on Fedora 10, and used
 dmd -g -debug -v read2.d
 to compile. Incidentally, using
 dmd -gc -debug -v read2.d
 does seem to give the same stack trace.
While I can't explain why gdb and dmd don't seem to work nicely together, you'd have much better luck using ldc. Compiling with ldc, this is the backtrace I got when debugging read2.d on my maching (and is what you're probably looking for): (gdb) run Starting program: /data/Code/D/error [Thread debugging using libthread_db enabled] [New Thread 0xb7d656c0 (LWP 14104)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7d656c0 (LWP 14104)] 0x080495fe in _D5error3darFiZi (d=-6) at error.d:23 23 return 1 + * cast(int*) d; // null pointer exception (gdb) backtrace
Ah, this looks nice. And the file name shows in the function names. If everyone wasn't telling me it's a licence issue, I'd take it for granted there's a bug in DMD.
Apr 02 2009
parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2009-04-02 20:51:26 +0200, Georg Wrede <georg.wrede iki.fi> said:

 Simon Gomizelj wrote:
 On Thu, 02 Apr 2009 04:56:46 -0400, Georg Wrede <georg.wrede iki.fi> wrote:
 
 With gdb I can either debug a core dump or an actual running process. 
 For example, with
 
 import std.stdio;
 
 int main()
 {
      readWrite();
      return 8;
 }
 
 void readWrite()
 {
      auto line = readln();   // here it waits, and that's when I debug
                              // in another window
      write("Rivi oli: ", line);
 }
 
 I get the following stack trace (it looks the same whether I debug a 
 core dump or a running instance)
 





      delimiter=10, fp=0x62e420) at iogetdelim.c:79




 
 This is not perfect, 5..7 are functions written in D, but main is 
 missing. Then, trying to examine a core dump from something that gets a 
 segfault, I wrote the following, expecting that I'd get a grandiose 
 stack trace
 
 
 $ cat npe.d
 import std.stdio;
 
 int main()
 {
      return foo(3);
 }
 
 int foo(int a)
 {
      return 1 + bar(a - 3);
 }
 
 int bar(int b)
 {
      return 1 + car(b - 3);
 }
 
 int car(int c)
 {
      return 1 + dar(c - 3);
 }
 
 int dar(int d)
 {
      return 1 + * cast(int*) d; // null pointer exception
 }
 
 
 
 Turns out I got zilch!
 


 
 I have DMD on Fedora 10, and used
 dmd -g -debug -v read2.d
 to compile. Incidentally, using
 dmd -gc -debug -v read2.d
 does seem to give the same stack trace.
 
While I can't explain why gdb and dmd don't seem to work nicely together, you'd have much better luck using ldc. Compiling with ldc, this is the backtrace I got when debugging read2.d on my maching (and is what you're probably looking for): (gdb) run Starting program: /data/Code/D/error [Thread debugging using libthread_db enabled] [New Thread 0xb7d656c0 (LWP 14104)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0xb7d656c0 (LWP 14104)] 0x080495fe in _D5error3darFiZi (d=-6) at error.d:23 23 return 1 + * cast(int*) d; // null pointer exception (gdb) backtrace
Ah, this looks nice. And the file name shows in the function names. If everyone wasn't telling me it's a licence issue,
No the license issue is just for including this in tango
 I'd take it for granted there's a bug in DMD.
you are right, on mac with dmd I get the full trace, on linux not. About the missing line and file information I think dmd does not add that on mac/linux.
Apr 03 2009
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Fawzi Mohamed wrote:
 you are right, on mac with dmd I get the full trace, on linux not. About 
 the missing line and file information I think dmd does not add that on 
 mac/linux.
You can see using dumpobj -p on the object files that dmd *does* put in the information.
Apr 03 2009
parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2009-04-03 10:33:19 +0200, Walter Bright <newshound1 digitalmars.com> said:

 Fawzi Mohamed wrote:
 you are right, on mac with dmd I get the full trace, on linux not. 
 About the missing line and file information I think dmd does not add 
 that on mac/linux.
You can see using dumpobj -p on the object files that dmd *does* put in the information.
then the correct statement is that libbdf is not able to interpret that information correctly, because both on mac and on linux gdb and addr2line are not able to use it
Apr 03 2009
parent Walter Bright <newshound1 digitalmars.com> writes:
Fawzi Mohamed wrote:
 then the correct statement is that libbdf is not able to interpret that 
 information correctly, because both on mac and on linux gdb and 
 addr2line are not able to use it
Right. I just don't know what is wrong with it. It appears to be correct according to the dwarf spec.
Apr 03 2009
prev sibling parent reply Fawzi Mohamed <fmohamed mac.com> writes:
Well inlined functions will have no frame, also last call optimization 
(tail optimization) removes the frame.
the backtrace typically gets the return address (i.e. the adress of the 
next instruction, not of the calling instruction).
Normally the code tries to guess the calling instruction as the one 
before the return instruction, but it does not always work.
So one has to expect that the backtrace might miss some frames.
But normally this is not a problem.
The tracing of tango svn version (that uses libc backtrace) seems to 
work rather well.
It does not give you the names, but as said that is due to a license problem.

gdb uses the same tools (and libbdf), that as jive has shown works well 
(but is GPL).
So I think that things are working as expected, even if maybe not as 
you would like :)

Fawzi

On 2009-04-02 10:56:46 +0200, Georg Wrede <georg.wrede iki.fi> said:

 With gdb I can either debug a core dump or an actual running process. 
 For example, with
 
 import std.stdio;
 
 int main()
 {
      readWrite();
      return 8;
 }
 
 void readWrite()
 {
      auto line = readln();   // here it waits, and that's when I debug
                              // in another window
      write("Rivi oli: ", line);
 }
 
 I get the following stack trace (it looks the same whether I debug a 
 core dump or a running instance)
 





      delimiter=10, fp=0x62e420) at iogetdelim.c:79




 
 This is not perfect, 5..7 are functions written in D, but main is 
 missing. Then, trying to examine a core dump from something that gets a 
 segfault, I wrote the following, expecting that I'd get a grandiose 
 stack trace
 
 
 $ cat npe.d
 import std.stdio;
 
 int main()
 {
      return foo(3);
 }
 
 int foo(int a)
 {
      return 1 + bar(a - 3);
 }
 
 int bar(int b)
 {
      return 1 + car(b - 3);
 }
 
 int car(int c)
 {
      return 1 + dar(c - 3);
 }
 
 int dar(int d)
 {
      return 1 + * cast(int*) d; // null pointer exception
 }
 
 
 
 Turns out I got zilch!
 


 
 I have DMD on Fedora 10, and used
 dmd -g -debug -v read2.d
 to compile. Incidentally, using
 dmd -gc -debug -v read2.d
 does seem to give the same stack trace.
Apr 02 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
Fawzi Mohamed wrote:
 Well inlined functions will have no frame, also last call optimization 
 (tail optimization) removes the frame.
If I were to write a compiler, then using "-g -debug", etc. would make sure neither happens!
 the backtrace typically gets the return address (i.e. the adress of the 
 next instruction, not of the calling instruction).
 Normally the code tries to guess the calling instruction as the one 
 before the return instruction, but it does not always work.
A first idea is to have the compiler insert a few NOPs when compiling with -debug, but then again if it were that easy, somebody else would've thought of it already.
 So one has to expect that the backtrace might miss some frames.
 But normally this is not a problem.
While I've seldom needed debuggin tools or stack tracing, I can imagine they're indispensable for people who have to quickly fix others' code. I guess most folks here, especially Walter(?) really do most of their coding on "new" and "own" things, where there's less need for such? But in a busy corporate environment with dozens of coders on the project, and people having to debug (or actually ending up because the called function doesn't work right) each other's code, it's different.
 The tracing of tango svn version (that uses libc backtrace) seems to 
 work rather well.
 It does not give you the names, but as said that is due to a license 
 problem.
Aarrghhh. What most frustrates me is when something obvious can't be done because of external trivialities.
 gdb uses the same tools (and libbdf), that as jive has shown works well 
 (but is GPL).
 So I think that things are working as expected, even if maybe not as you 
 would like :)
It's a shame.
Apr 02 2009
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
== Quote from Georg Wrede (georg.wrede iki.fi)'s article
 Fawzi Mohamed wrote:
 The tracing of tango svn version (that uses libc backtrace) seems to
 work rather well.
 It does not give you the names, but as said that is due to a license
 problem.
Aarrghhh. What most frustrates me is when something obvious can't be done because of external trivialities.
The Tango plugin architecture for backtrace was designed so that the backtrace code doesn't have to be integrated into Tango itself, eliminating the license problem. But I can see how this might be a problem if you want to bundle a backtrace library with Tango :-)
Apr 02 2009
parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2009-04-02 21:18:55 +0200, Sean Kelly <sean invisibleduck.org> said:

 == Quote from Georg Wrede (georg.wrede iki.fi)'s article
 Fawzi Mohamed wrote:
 
 The tracing of tango svn version (that uses libc backtrace) seems to
 work rather well.
 It does not give you the names, but as said that is due to a license
 problem.
Aarrghhh. What most frustrates me is when something obvious can't be done because of external trivialities.
The Tango plugin architecture for backtrace was designed so that the backtrace code doesn't have to be integrated into Tango itself, eliminating the license problem. But I can see how this might be a problem if you want to bundle a backtrace library with Tango :-)
having some stacktracing by default there was the number one request at the tango reference, and also in the wish list for a while. The idea is not to disallow external solutions, but to have something working there by default. Please note that something using GPL code even as plugin forces the whole application to be GPL, which is not acceptable for anyone not wanting to release its application as GPL. Fawzi
Apr 03 2009
parent =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Fawzi Mohamed wrote:
 On 2009-04-02 21:18:55 +0200, Sean Kelly <sean invisibleduck.org> said:
 
 == Quote from Georg Wrede (georg.wrede iki.fi)'s article
 Fawzi Mohamed wrote:
 The tracing of tango svn version (that uses libc backtrace) seems to
 work rather well.
 It does not give you the names, but as said that is due to a license
 problem.
Aarrghhh. What most frustrates me is when something obvious can't be done because of external trivialities.
The Tango plugin architecture for backtrace was designed so that the backtrace code doesn't have to be integrated into Tango itself, eliminating the license problem. But I can see how this might be a problem if you want to bundle a backtrace library with Tango :-)
having some stacktracing by default there was the number one request at the tango reference, and also in the wish list for a while. The idea is not to disallow external solutions, but to have something working there by default. Please note that something using GPL code even as plugin forces the whole application to be GPL, which is not acceptable for anyone not wanting to release its application as GPL.
The glibc has functions for stack tracing (backtrace and backtrace_symbols) and it's licensed under the LGPL, so there should be no problem... Jerome - -- mailto:jeberger free.fr http://jeberger.free.fr Jabber: jeberger jabber.fr -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAknXbuQACgkQd0kWM4JG3k8AxQCeOws+fxLtAa0wbZ0YDiVgFyaQ ht4AoLODMa7nV9eNtyRKoDbqrymcJcPQ =BzNy -----END PGP SIGNATURE-----
Apr 04 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Georg Wrede wrote:
 Fawzi Mohamed wrote:
 Well inlined functions will have no frame, also last call optimization 
 (tail optimization) removes the frame.
If I were to write a compiler, then using "-g -debug", etc. would make sure neither happens!
However, closures in D1 have a stack frame that is within the creating function's stack frame, and gdb assumes that means a corrupt stack. There's no real way around this.
Apr 03 2009
parent reply Fawzi Mohamed <fmohamed mac.com> writes:
On 2009-04-03 19:24:25 +0200, Christopher Wright <dhasenan gmail.com> said:

 Georg Wrede wrote:
 Fawzi Mohamed wrote:
 Well inlined functions will have no frame, also last call optimization 
 (tail optimization) removes the frame.
If I were to write a compiler, then using "-g -debug", etc. would make sure neither happens!
However, closures in D1 have a stack frame that is within the creating function's stack frame, and gdb assumes that means a corrupt stack. There's no real way around this.
Now this is more clear, thanks!
Apr 03 2009
parent Georg Wrede <georg.wrede iki.fi> writes:
Fawzi Mohamed wrote:
 On 2009-04-03 19:24:25 +0200, Christopher Wright <dhasenan gmail.com> said:
 
 Georg Wrede wrote:
 Fawzi Mohamed wrote:
 Well inlined functions will have no frame, also last call 
 optimization (tail optimization) removes the frame.
If I were to write a compiler, then using "-g -debug", etc. would make sure neither happens!
However, closures in D1 have a stack frame that is within the creating function's stack frame, and gdb assumes that means a corrupt stack. There's no real way around this.
Now this is more clear, thanks!
If the current D closure architecture is considered stable and permanent, then maybe the gdb or glibc folks might want to look at it? And while at it, they'd probably know right off the bat what seems to be the problem with D stack traces not currently showing properly.
Apr 10 2009