2

How to print full backtrace when exception is thrown? I have the following test program to rise exception and print backtrace:

#include <iostream>
#include <iostream> 
#include <exception>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>


void do_backtrace(int signo);

const struct catchSignals_t{
  int signo;
  const char *name;
} catchSignals[] = {
        { SIGSEGV, "SIGSEGV" },
        { SIGILL,  "SIGILL"  },
        { SIGFPE,  "SIGFPE"  },
        { SIGABRT, "SIGABRT" },
        { SIGBUS,  "SIGBUS"  },
        { SIGUSR2, "SIGUSR2" }
};


bool regHandlers() {
    bool result = true;

    for (auto i: catchSignals) {
        result = result && (signal(i.signo, do_backtrace) != SIG_ERR);

        if (!result)
            std::cerr <<  "Failed to install signal:" << i.name;
    }

    return result;
};


void do_backtrace(int signo) {
    std::cerr << "Received signal " << signo << std::endl;
    void * array[50];
    int size = backtrace(array, 50);

    std::cerr << " backtrace returned " << size << " frames\n\n";


    char ** messages = backtrace_symbols(array, size);

    for (int i = 0; i < size && messages != NULL; ++i) {
        std::cerr << "[bt]: (" << i << ") " << messages[i] << std::endl;
    }
    std::cerr << std::endl;

    free(messages);
//    abort();

    exit(0);

}

void on_terminate() {
    std::cout << "on_terminate called" << std::endl;

    static bool tried_throw = false;

    try {
        // try once to re-throw currently active exception
        if (!tried_throw++) throw;
    }
    catch (const std::exception &e) {
        std::cerr << __FUNCTION__ << " caught unhandled exception. what(): "
                  << e.what() << std::endl;
    }
    catch (...) {
        std::cerr << __FUNCTION__ << " caught unknown/unhandled exception." 
                  << std::endl;
    }

    do_backtrace(6);
}

namespace {
    static const bool SET_TERMINATE = std::set_terminate(on_terminate);
}

void foo() 
{

    kill(getpid(), SIGABRT);

    abort();
//    throw 20;
}


int main() {
    regHandlers();


    foo();
    return 1;
}

On x86 host PC it prints full backtrace and I can translate addresses to findout the where exception throwed, but on target arm this is completely different output. Looks like:

on_terminate backtrace returned 3 frames

[bt]: (0) ./a.out() [0x8a2c]
[bt]: (1) /usr/lib/libstdc++.so.6(+0x4a1e8) [0xb6ecf1e8]
[bt]: (2) /usr/lib/libstdc++.so.6(_ZSt9terminatev+0x1c) [0xb6ecf210]

Aborted (core dumped)

And this problem not only with exceptions this could be seen with signal handler - backtrace also not full and I can not find where it rised.

Updated!

build command:

arm-buildroot-linux-gnueabi-g++ --std=c++11 -funwind-tables -mapcs-frame -rdynamic main.cc -o test

When using abort() in code - backtrace is following:

Received signal 6
 backtrace returned 3 frames

[bt]: (0) ./test(_Z12do_backtracei+0x50) [0x8df8]
[bt]: (1) /lib/libc.so.6(__default_sa_restorer_v2+0) [0xb6c90dc0]
[bt]: (2) /lib/libc.so.6(gsignal+0x38) [0xb6c8fb58]

From this backtrace it is not possible to say where code crashed (where abort() used).

When using kill(getpid(), SIGABRT) in code - backtrace is following and it looks OK:

Received signal 6
 backtrace returned 6 frames

[bt]: (0) ./test(_Z12do_backtracei+0x50) [0x8e58]
[bt]: (1) /lib/libc.so.6(__default_sa_restorer_v2+0) [0xb6c61dc0]
[bt]: (2) /lib/libc.so.6(kill+0xc) [0xb6c60e3c]
[bt]: (3) ./test(_Z3foov+0x20) [0x90e4]
[bt]: (4) ./test(main+0x14) [0x90fc]
[bt]: (5) /lib/libc.so.6(__libc_start_main+0x114) [0xb6c4aff4]
Yuri
  • 1,179
  • 4
  • 13
  • 27
  • Possible duplicate of [print stack trace in arm-linux](http://stackoverflow.com/questions/10877377/print-stack-trace-in-arm-linux) – artless noise Jul 26 '16 at 13:31
  • Can you at least confirm that `-funwind-tables` and `-mapcs-frame` (and not use `-fomit-frame-pointer`) correct the issue? See: [ARM Link and frame register](http://stackoverflow.com/questions/15752188/arm-link-register-and-frame-pointer) for some details on tracing. – artless noise Jul 26 '16 at 13:34
  • I compiled test program with command: arm-buildroot-linux-gnueabi-g++ --std=c++11 -funwind-tables -mapcs-frame main.cc But backtrace still not full. I expect to get the place where abort() called. – Yuri Jul 27 '16 at 08:48
  • When triggering segmentation fault it prints full backtrace but when use abort() it just starts with (gsignal+0x38) – Yuri Jul 27 '16 at 09:37
  • Can you try the option `-rdynamic` for library tracing and/or look at [Getting saved IP from a signal handler](http://stackoverflow.com/questions/5397041/getting-the-saved-instruction-pointer-address-from-a-signal-handler)? – artless noise Jul 28 '16 at 13:06
  • No effect, probably libc must be compiled with above flags? When i sending SIGABRT by kill(self_pid, sigabrt) instead of using abort() it works ok as expected - i see full backtrace. But when using abort or throw exception it does not. – Yuri Jul 28 '16 at 13:44
  • The code and bt output updated above, i will add sleep() tomorrow and come back with results. – Yuri Jul 28 '16 at 16:54
  • sleep() not helped. Any way backtrace returns different numbers of frames, this is not issue with buffered c++ streams. – Yuri Jul 29 '16 at 07:37
  • Okay; `kill` is different than `abort`. See: [killing child process](http://stackoverflow.com/questions/12427524/killing-child-processes-at-parent-process-exit), for instance an `atexit` handler will not be called. I think something in the code maybe different on termination of the ARM vs PC. You should compare `strace` output of x86 vs PC. – artless noise Jul 29 '16 at 16:49
  • I believe you're running into this issue: http://gcc.1065356.n5.nabble.com/ARM-Linux-EABI-unwinding-through-a-segfault-handler-td692287.html Basically, on ARM EABI you can't unwind across the signal handler. The e-mail thread explains it in some detail, but unfortunately there doesn't seem to be a fix yet. – Kristof Provost Aug 01 '16 at 14:42
  • Kristof Provost, does not agree with you because when using kill(getpid(), SIGABRT) unwinding from signal handler works OK as expected. But for some reason unfortunately not with abort(), it makes hard to investigate crashes on ARM. – Yuri Aug 23 '16 at 07:59

0 Answers0