搜索

Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息

发表于 2025-11-03 06:38:55 来源:全栈开发

一、程序前言

程序在执行过程中 crash 是崩溃非常严重的问题,一般都应该在测试阶段排除掉这些问题,代码调用但是中何栈信总会有漏网之鱼被带到 release 阶段。

因此,获取函数程序的程序日志系统需要侦测这种情况,在代码崩溃的崩溃时候获取函数调用栈信息,为 debug 提供有效的高防服务器代码调用信息。

这篇文章的中何栈信理论知识很少,直接分享 2 段代码:在 Linux 和 Windows 这 2 个平台上,获取函数如何用C++ 来捕获函数调用栈里的程序信息。

二、崩溃Linux 平台

1. 注册异常信号的代码调用处理函数

需要处理哪些异常信号

#include <execinfo.h> #include <cxxabi.h> #include <signal.h> const std::map<int, std::string> 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++ = ;             *offsetBegin++ = ;             *offsetEnd++ = ;             int status;             char *realName = abi::__cxa_demangle(mangleName, 0, 0, &status);             if (0 == status)                 oss << "tstack dump [" << i << "]  " << symbols[i] << " : " << realName << "+";             else                 oss << "tstack dump [" << i << "]  " << symbols[i] << mangleName << "+";             oss << offsetBegin << offsetEnd << std::endl;             free(realName);         }         else         {             oss << "tstack dump [" << i << "]  " << symbols[i] << std::endl;         }     }     free(symbols);     oss << std::endl;     std::cout << oss.str(); // 打印函数调用栈信息 } 

三、Windwos 平台

在 Windows 平台下的获取函数代码实现,源码库参考了国外某个老兄的代码,如下:

1. 设置异常处理函数

#include <windows.h> #include <dbghelp.h> SetUnhandledExceptionFilter(exceptionHandler); 

2. 捕获异常,获取函数调用栈信息

void exceptionHandler(LPEXCEPTION_POINTERS info) {     CONTEXT *context = info->ContextRecord;     std::shared_ptr<void> RaiiSysCleaner(nullptr, [&](void *) {       SymCleanup(GetCurrentProcess());     });   const size_t dumpSize = 64;   std::vector<uint64_t> 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 < frameVector.size(); ++index)   {     if (StackWalk64(machine_type,            GetCurrentProcess(),            GetCurrentThread(),            &frame,            context,            NULL,            SymFunctionTableAccess64,            SymGetModuleBase64,            NULL)) {       frameVector[index] = frame.AddrPC.Offset;     } else {       break;     }   }   std::string dump;   const size_t kSize = frameVector.size();   for (size_t index = 0; index < kSize && frameVector[index]; ++index) {     dump += getSymbolInfo(index, frameVector);     dump += "n";   } std::cout << dump;  } 

主要是利用了 StackWalk64 这个函数,从地址转换为函数名称。

利用以上几个神器,基本上可以获取到程序崩溃时的函数调用栈信息,定位问题,有如神助!

随机为您推荐
版权声明:本站资源均来自互联网,如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

Copyright © 2016 Powered by Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息,全栈开发  滇ICP备2023006006号-32sitemap

回顶部