这篇文章主要讲述在 Linux 和 Windows 这 2 个平台上,如何用C++ 来捕获函数调用栈里的信息。
一、前言
程序在执行过程中 crash 是非常严重的问题,一般都应该在测试阶段排除掉这些问题,但是总会有漏网之鱼被带到 release 阶段。
因此,程序的日志系统需要侦测这种情况,在代码崩溃的时候获取函数调用栈信息,为 debug 提供有效的信息。
这篇文章的理论知识很少,直接分享 2 段代码:在 Linux 和 Windows 这 2 个平台上,如何用C++ 来捕获函数调用栈里的信息。
二、Linux 平台
1. 注册异常信号的处理函数 需要处理哪些异常信号
#include
#include
#include
const std::map Signals = {
{SIGINT, "SIGINT"},
{SIGABRT, "SIGABRT"},
{SIGFPE, "SIGFPE"},
{SIGILL, "SIGILL"},
{SIGSEGV, "SIGSEGV"}
// 可以添加其他信号
};
注册信号处理函数
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_sigaction = &sigHandler;
action.sa_flags = SA_SIGINFO;
for (const auto &sigPair : Signals)
{
if (sigaction(sigPair.first, &action, NULL) < 0)
fprintf(stderr, "Error: sigaction failed! \n");
}
2. 捕获异常,获取函数调用栈信息
void sigHandler(int signum, siginfo_t *info, void *ctx)
{
const size_t dump_size = 50;
void *array[dump_size];
int size = backtrace(array, dump_size);
char **symbols = backtrace_symbols(array, size);
std::ostringstream oss;
for (int i = 0; i < size; ++i)
{
char *mangleName = 0;
char *offsetBegin = 0;
char *offsetEnd = 0;
for (char *p = symbols[i]; *p; ++p)
{
if ('(' == *p)
{
mangleName = p;
}
else if ('+' == *p)
{
offsetBegin = p;
}
else if (')' == *p)
{
offsetEnd = p;
break;
}
}
if (mangleName && offsetBegin && offsetEnd && mangleName < offsetBegin)
{
*mangleName++ = '\0';
*offsetBegin++ = '\0';
*offsetEnd++ = '\0';
int status;
char *realName = abi::__cxa_demangle(mangleName, 0, 0, &status);
if (0 == status)
oss
关注
打赏
