How do I get the correct backtrace in the process signal handler (armv7-uclibc)?

I've done google many times to find the right solution for backtrace () in signal handler and pretty much everything, but I was unable to get backtrace in my signal handler - it is not a SIGUSR1 handler.

  • enable UCLIBC_HAS_BACKTRACE = y in uclibc config and compile it
  • verified that libubacktrace.so has been created
  • compiled my application binaries with the following options -r -rdynamic -fexception or -funwind-tables
  • The binary itself appears to be "split"

However, I was unable to get the full postback from the signal handler. Only the addresses of the functions that I called in the signal handler were printed.

If I use the target-gdb binary and attach the process using the gdb -pid command, I was able to get the full backtrace correctly.

Also, I tried pstack, but (pstack-1.2 - tried arm-patch, but it's horrible ... nothing printed) not very helpful.

Any advice?


1) Compiler options in Makefile

CFLAGS + = -g -fexceptions -funwind-tables -Werror $ (WARN) ...

2) Code

The code is very simple.

#define CALLSTACK_SIZE 10

static void print_stack(void) {
    int i, nptrs;
    void *buf[CALLSTACK_SIZE + 1];
    char **strings;

    nptrs = backtrace(buf, CALLSTACK_SIZE);
    printf("%s: backtrace() returned %d addresses\n", __func__, nptrs);

    strings = backtrace_symbols(buf, nptrs);

    if(strings == NULL) {
        printf("%s: no backtrace captured\n", __func__);
        return;
    }

    for(i = 0; i < nptrs; i++) {
        printf("%s\n", strings[i]);
    }

    free(strings);
}

...
static void sigHandler(int signum)
{
    printf("%s: signal %d\n", __FUNCTION__, signum);
    switch(signum ) {
    case SIGUSR2:
        // told to quit
        print_stack();
        break;
    default:
        break;
    }
}

      

+3


source to share


1 answer


Read carefully signal (7) and signal safety (7) .

The signal handler is limited (directly or indirectly) to only asynchronous signal-safe functions (practically speaking, most syscalls (2) only) and backtrace (3) or even printf (3) or malloc (3) or free

not asynchronous signal-safe. So your code is wrong: the signal handler sigHandler

calls printf

both indirectly (via print_stack

) free

and they are not asynchronous signal safe.

So your only option is to use a debugger gdb

.

More on POSIX signal.h and signaling concepts . In practical terms, almost the only sane thing a signal handler can do is set a global, thread-local, or static volatile sig_atomic_t

flag that should be tested elsewhere. It can also directly write (2) multiple bytes to pipe (7) that your application will read elsewhere (for example, in its event loop if it is a graphics application).



You can also use Ian Taylor libbacktrace

from within GCC
(if your program is compiled with debug information like with -g

). It's not guaranteed to work in signal handlers (since it doesn't only use asynchronous signal-protected functions), but it's practically useful.

Note that the kernel sets a call frame ( onto the call stack ) for sigreturn (2) when it handles the signal.

You can also use (especially if your application is single threaded) sigaltstack (2) to have an alternate signal stack. I'm not sure if this will be helpful.

If you have an event loop, you can use Linux signalfd (2) and request the event loop to poll

This. For SIGTERM

either or SIGQUIT

or SIGALRM

this is a pretty useful trick.

+4


source







All Articles