Printing stack trace from a signal handler

2019-02-10 02:50发布

问题:

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?

回答1:

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.



回答2:

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.