我编写了这个(backtrace.hpp)以在我的程序像分段错误一样崩溃时显示调用堆栈。
#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(){}
};
通常是有用的。但有时,我只是得到这样的信息: $ /bin/sh: 第 1 行: 6571 分段错误 没有回溯输出。 为什么会出现这种情况?
在我的代码中,我像这样使用 backtrace.hpp:
#inlcude "backtrace.hpp"
int main(){
Backtrace b;
...
}
为什么会出现这种情况?
可以在信号处理程序中合法使用的函数非常少(async-signal-safe)。
malloc
和free
并不安全,backtrace_symbols()
调用malloc()
,使用std::cout
简直就是自找麻烦。
可以相当可靠地打印堆栈跟踪,但这需要很多的小心(以及相当多很多代码),而且你根本不小心。