I code this(backtrace.hpp) to show the call stack when my program crashed like segmentation fault.
#pragma once
#include <map>
#include <iostream>
#include <signal.h>
#include <sys/stat.h>
#include <execinfo.h>
#include <sys/types.h>
#include <unistd.h>
static const std::map<int, std::string> signals_map =
{
{SIGSEGV, "SIGSEGV"},
{SIGABRT, "SIGABRT"},
{SIGINT, "SIGINT"},
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
{SIGSYS, "SIGSYS"},
{SIGBUS, "SIGBUS"},
{SIGIOT, "SIGIOT"},
{SIGTRAP, "SIGTRAP"},
};
class Backtrace
{
private:
static void ExceptionHandler(int signum, siginfo_t* info, void* ctx){
int nptrs;
void *buffer[1024];
char **strings;
nptrs = backtrace(buffer, 1024);
strings = backtrace_symbols(buffer, nptrs);
if (strings == NULL) {
exit(EXIT_FAILURE);
}
std::cout<<std::endl<<"****** Crash Backtrace signal: "<<signals_map.at(signum)<<"******"<<std::endl<<std::endl;
for (int i = 2; i < nptrs; i++) {
std::cout<<" "<<strings[i]<<std::endl;
}
free(strings);
signal(signum, SIG_DFL);
}
public:
Backtrace(){
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_sigaction = &ExceptionHandler;
action.sa_flags = SA_SIGINFO;
for (const auto& signals: signals_map)
{
if (0 > sigaction(signals.first, &action, NULL))
{
std::cout<<"sigaction failed:"<<signals.second<<std::endl;
}
}
}
~Backtrace(){}
};
Usually, it is usefull. But sometimes, I just got info like: $ /bin/sh: line 1: 6571 Segmentation fault There is no backtrace output. Why does this happen?
In my code, I use the backtrace.hpp like this:
#inlcude "backtrace.hpp"
int main(){
Backtrace b;
...
}
There are very few functions you can legally use in a signal handler (the async-signal-safe ones).
The
mallocandfreeare not safe,backtrace_symbols()callsmalloc(), and usingstd::coutis simply asking for trouble.It's possible to print the crash stack trace fairly reliably, but that requires a lot of care (and quite a lot of code), and you aren't careful at all.
If your crash is happening due to heap corruption (as many crashes are), calling
backtrace_symbols()may crash, deadlock or simply fail. If either of these happens, your code would fail to print anything.