Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing stack trace from a signal handler

I need to print stack trace from a signal handler of 64-bit mutli-threaded C++ application running on Linux. Although I found several code examples, none of them compiles. My blocking point is getting the caller's (the point where the signal was generated) address from the ucontext_t structure. All of the information I could find, points to the EIP register as either ucontext.gregs[REG_EIP] or ucontext.eip. It looks like both of them are x86-specific. I need 64-bit compliant code for both Intel and AMD CPUs. Can anybody help?

like image 417
GMichael Avatar asked Feb 09 '12 08:02

GMichael


2 Answers

there is a glibc function backtrace. The man page lists an example the the call:

#define SIZE 100
void myfunc3(void) {
       int j, nptrs;

       void *buffer[100];
       char **strings;

       nptrs = backtrace(buffer, SIZE);
       printf("backtrace() returned %d addresses\n", nptrs);

       /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
          would produce similar output to the following: */

       strings = backtrace_symbols(buffer, nptrs);
       if (strings == NULL) {
           perror("backtrace_symbols");
           exit(EXIT_FAILURE);
       }

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

       free(strings);
   }

See the man page for more context.

it's difficult to tell if this really is guaranteed to work from a signal handler, since posix lists only a few reentrant functions that are guaranteed to work. Remember: a signal handler may be called while the rest of your process is right in the middle of an malloc call.

My guess is, that this usually works, but it may fail from time to time. For debugging this may be good enough.

like image 130
Jörg Beyer Avatar answered Oct 26 '22 19:10

Jörg Beyer


The usual way of getting a stack trace is to take the address of a local variable, then add some magic number to it, depending on how the compiler generates code (which may depend on the optimization options used to compile the code), and work back from there. All very system dependent, but doable if you know what you're doing.

Whether this works in a signal handler is another question. I don't know about the platform you describe, but a lot of systems install a separate stack for the signal handlers, with no link back to the interrupted stack in user accessible memory.

like image 27
James Kanze Avatar answered Oct 26 '22 19:10

James Kanze