共计 2171 个字符,预计需要花费 6 分钟才能阅读完成。
导读 | 这篇文章主要讲述在 Linux 和 Windows 这 2 个平台上,如何用 C ++ 来捕获函数调用栈里的信息。 |
一、前言
程序在执行过程中 crash 是非常严重的问题,一般都应该在测试阶段排除掉这些问题,但是总会有漏网之鱼被带到 release 阶段。
因此,程序的日志系统需要侦测这种情况,在代码崩溃的时候获取函数调用栈信息,为 debug 提供有效的信息。
这篇文章的理论知识很少,直接分享 2 段代码:在 Linux 和 Windows 这 2 个平台上,如何用 C ++ 来捕获函数调用栈里的信息。
二、Linux 平台
1. 注册异常信号的处理函数
需要处理哪些异常信号
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) | |
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 | |
三、Windwos 平台 | |
在 Windows 平台下的代码实现,参考了国外某个老兄的代码,如下: | |
1. 设置异常处理函数 | |
#include | |
#include | |
SetUnhandledExceptionFilter(exceptionHandler); | |
2. 捕获异常,获取函数调用栈信息 | |
void exceptionHandler(LPEXCEPTION_POINTERS info) | |
{ | |
CONTEXT *context = info->ContextRecord; | |
std::shared_ptr RaiiSysCleaner(nullptr, [&](void *) {SymCleanup(GetCurrentProcess()); | |
}); | |
const size_t dumpSize = 64; | |
std::vector frameVector(dumpSize); | |
DWORD machine_type = 0; | |
STACKFRAME64 frame = {}; | |
frame.AddrPC.Mode = AddrModeFlat; | |
frame.AddrFrame.Mode = AddrModeFlat; | |
frame.AddrStack.Mode = AddrModeFlat; | |
#ifdef _M_IX86 | |
frame.AddrPC.Offset = context->Eip; | |
frame.AddrFrame.Offset = context->Ebp; | |
frame.AddrStack.Offset = context->Esp; | |
machine_type = IMAGE_FILE_MACHINE_I386; | |
#elif _M_X64 | |
frame.AddrPC.Offset = context->Rip; | |
frame.AddrFrame.Offset = context->Rbp; | |
frame.AddrStack.Offset = context->Rsp; | |
machine_type = IMAGE_FILE_MACHINE_AMD64; | |
#elif _M_IA64 | |
frame.AddrPC.Offset = context->StIIP; | |
frame.AddrFrame.Offset = context->IntSp; | |
frame.AddrStack.Offset = context->IntSp; | |
machine_type = IMAGE_FILE_MACHINE_IA64; | |
frame.AddrBStore.Offset = context.RsBSP; | |
frame.AddrBStore.Mode = AddrModeFlat; | |
#else | |
frame.AddrPC.Offset = context->Eip; | |
frame.AddrFrame.Offset = context->Ebp; | |
frame.AddrStack.Offset = context->Esp; | |
machine_type = IMAGE_FILE_MACHINE_I386; | |
#endif | |
for (size_t index = 0; index | |
主要是利用了 StackWalk64 这个函数,从地址转换为函数名称。 | |
利用以上几个神器,基本上可以获取到程序崩溃时的函数调用栈信息,定位问题,有如神助! | |
阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配 | |
腾讯云新客低至 82 元 / 年,老客户 99 元 / 年 | |
代金券:在阿里云专用满减优惠券 | |
正文完
星哥玩云-微信公众号
