Thread overview
geting stack trace from signal handlers
Jun 05, 2013
Timothee Cour
Jun 06, 2013
nazriel
Jun 06, 2013
Timothee Cour
Jun 07, 2013
nazriel
Jun 07, 2013
Timothee Cour
Jun 06, 2013
Timothee Cour
June 05, 2013
how do i get a stacktrace inside handleTermination?

If not currently possible, could we have a compile flag that would enable
this kind of feature? (making code slower would be OK, its an opt in
feature)
Ideally we'd also be able to walk up or down the stack trace (kind of what
gdb would do, but I'd like to be able to do that without resorting to gdb,
using a language/library solution)

----

import core.sys.posix.signal;
import std.c.stdlib;
import std.stdio;

void main(string[] args)
{
        bsd_signal(SIGINT, &handleTermination);

        while (true)
        {

        }
}

extern(C) void handleTermination(int signal)
{
        writefln("Caught signal: %s", signal);
        exit(signal);
}

-----


June 06, 2013
On Wednesday, 5 June 2013 at 21:05:53 UTC, Timothee Cour wrote:
> how do i get a stacktrace inside handleTermination?
>
> If not currently possible, could we have a compile flag that would enable
> this kind of feature? (making code slower would be OK, its an opt in
> feature)
> Ideally we'd also be able to walk up or down the stack trace (kind of what
> gdb would do, but I'd like to be able to do that without resorting to gdb,
> using a language/library solution)
>
> ----
>
> import core.sys.posix.signal;
> import std.c.stdlib;
> import std.stdio;
>
> void main(string[] args)
> {
>         bsd_signal(SIGINT, &handleTermination);
>
>         while (true)
>         {
>
>         }
> }
>
> extern(C) void handleTermination(int signal)
> {
>         writefln("Caught signal: %s", signal);
>         exit(signal);
> }
>
> -----

You mean call stack?
Maybe something like this:
http://dpaste.dzfl.pl/99f217be

---
import core.sys.posix.signal;
import std.c.stdlib;
import std.stdio;
import std.conv;

void main(string[] args)
{
       bsd_signal(SIGINT, &handleTermination);

       while (true)
       {

       }
}

extern(C) void handleTermination(int signal)
{
       writefln("Caught signal: %s", signal);
       getTrace();
       exit(signal);
}

extern (C) void* thread_stackBottom();
extern (C) char** backtrace_symbols(void**, int size);

void getTrace() {
    void*[10] callstack;
    void** stackTop;
    void** stackBottom = cast(void**) thread_stackBottom();

    asm {
        mov [stackTop], RBP;
    }

    auto curr = stackTop;

    size_t i;
    for (i = 0; stackTop <= curr &&
        curr < stackBottom && i < 10;)
    {
        callstack[i++] = *(curr+1);
        curr = cast(void**) *curr;
    }

    auto ret = backtrace_symbols(callstack.ptr, cast(int) i);
    for (; i > 0; i--) {
        writeln((*ret).to!string());
        ret++;
    }
}
---
June 06, 2013
Great!
two issues (on OSX at least):

A)
it seems the top-most element of the call stack gets chopped off; eg in
your code, the main_module.main symbol will not appear in the stack trace.
Any idea why or how to fix that?
Is that some inlining issue ? I tried with dmd -g, or -gs or -gc.
This can be annoying when the top-most function is a large function and
it's not at all clear where the code stopped.

B)
there are no line numbers. I did a complex workaround by launching a
process and calling atos to get those, but isn't there a better way?



On Thu, Jun 6, 2013 at 8:44 AM, nazriel <spam@dzfl.pl> wrote:

> On Wednesday, 5 June 2013 at 21:05:53 UTC, Timothee Cour wrote:
>
>> how do i get a stacktrace inside handleTermination?
>>
>> If not currently possible, could we have a compile flag that would enable
>> this kind of feature? (making code slower would be OK, its an opt in
>> feature)
>> Ideally we'd also be able to walk up or down the stack trace (kind of what
>> gdb would do, but I'd like to be able to do that without resorting to gdb,
>> using a language/library solution)
>>
>> ----
>>
>> import core.sys.posix.signal;
>> import std.c.stdlib;
>> import std.stdio;
>>
>> void main(string[] args)
>> {
>>         bsd_signal(SIGINT, &handleTermination);
>>
>>         while (true)
>>         {
>>
>>         }
>> }
>>
>> extern(C) void handleTermination(int signal)
>> {
>>         writefln("Caught signal: %s", signal);
>>         exit(signal);
>> }
>>
>> -----
>>
>
> You mean call stack?
> Maybe something like this:
> http://dpaste.dzfl.pl/99f217be
>
>
> ---
> import core.sys.posix.signal;
> import std.c.stdlib;
> import std.stdio;
> import std.conv;
>
>
> void main(string[] args)
> {
>        bsd_signal(SIGINT, &handleTermination);
>
>        while (true)
>        {
>
>        }
> }
>
> extern(C) void handleTermination(int signal)
> {
>        writefln("Caught signal: %s", signal);
>        getTrace();
>        exit(signal);
> }
>
> extern (C) void* thread_stackBottom();
> extern (C) char** backtrace_symbols(void**, int size);
>
> void getTrace() {
>     void*[10] callstack;
>     void** stackTop;
>     void** stackBottom = cast(void**) thread_stackBottom();
>
>     asm {
>         mov [stackTop], RBP;
>     }
>
>     auto curr = stackTop;
>
>     size_t i;
>     for (i = 0; stackTop <= curr &&
>         curr < stackBottom && i < 10;)
>     {
>         callstack[i++] = *(curr+1);
>         curr = cast(void**) *curr;
>     }
>
>     auto ret = backtrace_symbols(callstack.**ptr, cast(int) i);
>     for (; i > 0; i--) {
>         writeln((*ret).to!string());
>         ret++;
>     }
> }
> ---
>


June 06, 2013
just to be clear, this is what i get:

0   test_stacktrace_sigint              0x0000000102e2f69f
handleTermination + 35
1   libsystem_c.dylib                   0x00007fff919d794a _sigtramp + 26
2   ???                                 0x0000000000000005 0x0 + 5
3   test_stacktrace_sigint              0x0000000102e4c18d
D2rt6dmain211_d_run_mainUiPPaPUAAaZiZi7runMainMFZv + 33

iterm#2 is unreadable.


On Thu, Jun 6, 2013 at 2:50 PM, Timothee Cour <thelastmammoth@gmail.com>wrote:

> Great!
> two issues (on OSX at least):
>
> A)
> it seems the top-most element of the call stack gets chopped off; eg in
> your code, the main_module.main symbol will not appear in the stack trace.
> Any idea why or how to fix that?
> Is that some inlining issue ? I tried with dmd -g, or -gs or -gc.
> This can be annoying when the top-most function is a large function and
> it's not at all clear where the code stopped.
>
> B)
> there are no line numbers. I did a complex workaround by launching a
> process and calling atos to get those, but isn't there a better way?
>
>
>
> On Thu, Jun 6, 2013 at 8:44 AM, nazriel <spam@dzfl.pl> wrote:
>
>> On Wednesday, 5 June 2013 at 21:05:53 UTC, Timothee Cour wrote:
>>
>>> how do i get a stacktrace inside handleTermination?
>>>
>>> If not currently possible, could we have a compile flag that would enable
>>> this kind of feature? (making code slower would be OK, its an opt in
>>> feature)
>>> Ideally we'd also be able to walk up or down the stack trace (kind of
>>> what
>>> gdb would do, but I'd like to be able to do that without resorting to
>>> gdb,
>>> using a language/library solution)
>>>
>>> ----
>>>
>>> import core.sys.posix.signal;
>>> import std.c.stdlib;
>>> import std.stdio;
>>>
>>> void main(string[] args)
>>> {
>>>         bsd_signal(SIGINT, &handleTermination);
>>>
>>>         while (true)
>>>         {
>>>
>>>         }
>>> }
>>>
>>> extern(C) void handleTermination(int signal)
>>> {
>>>         writefln("Caught signal: %s", signal);
>>>         exit(signal);
>>> }
>>>
>>> -----
>>>
>>
>> You mean call stack?
>> Maybe something like this:
>> http://dpaste.dzfl.pl/99f217be
>>
>>
>> ---
>> import core.sys.posix.signal;
>> import std.c.stdlib;
>> import std.stdio;
>> import std.conv;
>>
>>
>> void main(string[] args)
>> {
>>        bsd_signal(SIGINT, &handleTermination);
>>
>>        while (true)
>>        {
>>
>>        }
>> }
>>
>> extern(C) void handleTermination(int signal)
>> {
>>        writefln("Caught signal: %s", signal);
>>        getTrace();
>>        exit(signal);
>> }
>>
>> extern (C) void* thread_stackBottom();
>> extern (C) char** backtrace_symbols(void**, int size);
>>
>> void getTrace() {
>>     void*[10] callstack;
>>     void** stackTop;
>>     void** stackBottom = cast(void**) thread_stackBottom();
>>
>>     asm {
>>         mov [stackTop], RBP;
>>     }
>>
>>     auto curr = stackTop;
>>
>>     size_t i;
>>     for (i = 0; stackTop <= curr &&
>>         curr < stackBottom && i < 10;)
>>     {
>>         callstack[i++] = *(curr+1);
>>         curr = cast(void**) *curr;
>>     }
>>
>>     auto ret = backtrace_symbols(callstack.**ptr, cast(int) i);
>>     for (; i > 0; i--) {
>>         writeln((*ret).to!string());
>>         ret++;
>>     }
>> }
>> ---
>>
>
>


June 07, 2013
On Thursday, 6 June 2013 at 21:50:58 UTC, Timothee Cour wrote:
> Great!
> two issues (on OSX at least):
>
> A)
> it seems the top-most element of the call stack gets chopped off; eg in
> your code, the main_module.main symbol will not appear in the stack trace.
> Any idea why or how to fix that?
> Is that some inlining issue ? I tried with dmd -g, or -gs or -gc.
> This can be annoying when the top-most function is a large function and
> it's not at all clear where the code stopped.
>
I haven't got Mac OSX to test it out but I fixed it a little bit so it is less hacky:

http://dpaste.dzfl.pl/241c6fb5

Compiler switches you may want to consider are:
-gc -L--export-dynamic -O0

> B)
> there are no line numbers. I did a complex workaround by launching a
> process and calling atos to get those, but isn't there a better way?
>
Yeah, it is a complex issue. There are 2 ways to fix it from what I know.
1) pipe addresses to addr2line - easier
2) use libdwarf - more complex but also more out-of-box solution
>
June 07, 2013
On Fri, Jun 7, 2013 at 12:39 AM, nazriel <spam@dzfl.pl> wrote:

> On Thursday, 6 June 2013 at 21:50:58 UTC, Timothee Cour wrote:
>
>> Great!
>> two issues (on OSX at least):
>>
>> A)
>> it seems the top-most element of the call stack gets chopped off; eg in
>> your code, the main_module.main symbol will not appear in the stack trace.
>> Any idea why or how to fix that?
>> Is that some inlining issue ? I tried with dmd -g, or -gs or -gc.
>> This can be annoying when the top-most function is a large function and
>> it's not at all clear where the code stopped.
>>
>>  I haven't got Mac OSX to test it out but I fixed it a little bit so it
> is less hacky:
>
> http://dpaste.dzfl.pl/241c6fb5
>

Thanks, ya, the demangling part is the easy part :) (although demangle is
still incomplete in many cases...)



> Compiler switches you may want to consider are:
> -gc -L--export-dynamic -O0


export-dynamic or rdynamic are not available on OSX.
-gc doesn't change anything on dmd (and -O0 isn't available on dmd)
-gc -O0 doesn't change anything on ldc



>
>
>  B)
>> there are no line numbers. I did a complex workaround by launching a process and calling atos to get those, but isn't there a better way?
>>
>>  Yeah, it is a complex issue. There are 2 ways to fix it from what I know.
> 1) pipe addresses to addr2line - easier
>

OSX doesn't have addr2line, hence my solution based on piping to atos on OSX. It works except in a few cases where for some reason only the basename of the file is shown instead of full file path, but its a bit complex so i was hoping for simpler.



> 2) use libdwarf - more complex but also more out-of-box solution


Thanks for the link, that sounds promising! Will look at it.
under doc:
http://sourceforge.net/apps/trac/elftoolchain/wiki/libdwarf
relevant sections:
"Line Number Operations"