Getting stack traces on Unix systems automatically

What are the methods for automatically getting a stack trace on Unix systems? I do not mean just getting the main file or interactively connecting to GDB, but with a SIGSEGV handler that dumps the backtrace into a text file.

Bonus points for the following additional features:

  • Collection of additional information during a crash (for example, configuration files).
  • Send an error message to developers.
  • Ability to add this to the dlopen ed shared library
  • No GUI required
+7
stack-trace linux unix sigsegv
source share
4 answers

If you are on systems with BSD backtrace functionality available (Linux, OSX 1.5, BSD, of course), you can do this programmatically in your signal handler.

For example ( backtrace code obtained from IBM example ):

 #include <execinfo.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> void sig_handler(int sig) { void * array[25]; int nSize = backtrace(array, 25); char ** symbols = backtrace_symbols(array, nSize); for (int i = 0; i < nSize; i++) { puts(symbols[i]);; } free(symbols); signal(sig, &sig_handler); } void h() { kill(0, SIGSEGV); } void g() { h(); } void f() { g(); } int main(int argc, char ** argv) { signal(SIGSEGV, &sig_handler); f(); } 

Output:

 0 a.out 0x00001f2d sig_handler + 35 1 libSystem.B.dylib 0x95f8f09b _sigtramp + 43 2 ??? 0xffffffff 0x0 + 4294967295 3 a.out 0x00001fb1 h + 26 4 a.out 0x00001fbe g + 11 5 a.out 0x00001fcb f + 11 6 a.out 0x00001ff5 main + 40 7 a.out 0x00001ede start + 54 

This does not give bonus points for additional functions (except that a graphical interface is not required), but it has the advantage that it is very simple and does not require any additional libraries or programs.

+7
source share

FYI,

the proposed solution (using backtrace_symbols in the signal handler) breaks dangerously. DO NOT USE IT -

Yes, backtrace and backtrace_symbols will produce a return line and translate it into symbolic names:

  • backtrace_symbols allocates memory using malloc, and you can free it freely. If you crash due to memory corruption, your malloc arena will most likely get corrupted and cause a double error.

  • malloc and freely defend the malloc arena with internal lock. You may have encountered an error in the middle of malloc / free with a lock that will call this function or something that calls them deadlock.

  • You use puts, which uses a standard thread, which is also protected by blocking. If you were mistaken in the middle of printf, you again have a dead end.

  • On 32-bit platforms (for example, your regular PC 2 years ago), the kernel will set the return address for the internal glibc function instead of your crash function in your stack, so the single most important piece of information that you are interested in is what function a program error occurred, it will actually be damaged on this platform.

So, the code in the example is the worst kind of wrong one - it LOOKS as if it works, but it really will not give you unexpected ways to produce it.

By the way, is it interesting to do this right? check this one out .

Cheers, Gilad.

+15
source share

Here is an example of how to get more information using the demanger. As you can see, this file also writes the stacktrace file to the file.

 #include <iostream> #include <sstream> #include <string> #include <fstream> #include <cxxabi.h> void sig_handler(int sig) { std::stringstream stream; void * array[25]; int nSize = backtrace(array, 25); char ** symbols = backtrace_symbols(array, nSize); for (unsigned int i = 0; i < size; i++) { int status; char *realname; std::string current = symbols[i]; size_t start = current.find("("); size_t end = current.find("+"); realname = NULL; if (start != std::string::npos && end != std::string::npos) { std::string symbol = current.substr(start+1, end-start-1); realname = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status); } if (realname != NULL) stream << realname << std::endl; else stream << symbols[i] << std::endl; free(realname); } free(symbols); std::cerr << stream.str(); std::ofstream file("/tmp/error.log"); if (file.is_open()) { if (file.good()) file << stream.str(); file.close(); } signal(sig, &sig_handler); } 
+4
source share

Dereks solution is probably the best, but here's an alternative:

The latest version of the Linux kernel allows you to translate core dumps to a script or program. You can write a script to catch the main dump, collect all the necessary information and send everything back. This is a global parameter, so it applies to any failed program in the system. It will also require root privileges to configure. It can be configured through the / proc / sys / kernel / core _pattern file. Set it something like '| / Home / MyUser / bin / my-core-handler-script.

Ubuntu users also use this feature.

+2
source share

All Articles