日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux+Windows:程序崩潰時,在C++代碼中,如何獲取函數(shù)調(diào)用棧信息

一、前言

程序在執(zhí)行過程中 crash 是非常嚴重的問題,一般都應(yīng)該在測試階段排除掉這些問題,但是總會有漏網(wǎng)之魚被帶到 release 階段。

為南譙等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計制作服務(wù),及南譙網(wǎng)站建設(shè)行業(yè)解決方案。主營業(yè)務(wù)為網(wǎng)站設(shè)計制作、做網(wǎng)站、南譙網(wǎng)站設(shè)計,以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務(wù)。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!

因此,程序的日志系統(tǒng)需要偵測這種情況,在代碼崩潰的時候獲取函數(shù)調(diào)用棧信息,為 debug 提供有效的信息。

這篇文章的理論知識很少,直接分享 2 段代碼:在 Linux 和 Windows 這 2 個平臺上,如何用C++ 來捕獲函數(shù)調(diào)用棧里的信息。

二、Linux 平臺

1. 注冊異常信號的處理函數(shù)

需要處理哪些異常信號

 
 
 
 
  1. #include 
  2. #include 
  3. #include 
  4. const std::map Signals = {
  5.     {SIGINT, "SIGINT"},    
  6.     {SIGABRT, "SIGABRT"}, 
  7.     {SIGFPE, "SIGFPE"},   
  8.     {SIGILL, "SIGILL"},  
  9.     {SIGSEGV, "SIGSEGV"}
  10.     // 可以添加其他信號
  11. };

注冊信號處理函數(shù)

 
 
 
 
  1. struct sigaction action;
  2. sigemptyset(&action.sa_mask);
  3. action.sa_sigaction = &sigHandler;
  4. action.sa_flags = SA_SIGINFO; 
  5.  for (const auto &sigPair : Signals)
  6.  {
  7.     if (sigaction(sigPair.first, &action, NULL) < 0)
  8.         fprintf(stderr, "Error: sigaction failed! \n");
  9.  }

2. 捕獲異常,獲取函數(shù)調(diào)用棧信息

 
 
 
 
  1. void sigHandler(int signum, siginfo_t *info, void *ctx)
  2. {
  3.     const size_t dump_size = 50;
  4.     void *array[dump_size];
  5.     int size = backtrace(array, dump_size);
  6.     char **symbols = backtrace_symbols(array, size);
  7.     std::ostringstream oss;
  8.     for (int i = 0; i < size; ++i)
  9.     {
  10.         char *mangleName = 0;
  11.         char *offsetBegin = 0;
  12.         char *offsetEnd = 0;
  13.         for (char *p = symbols[i]; *p; ++p)
  14.         {
  15.             if ('(' == *p)
  16.             {   
  17.                  mangleName = p;
  18.             }   
  19.             else if ('+' == *p)
  20.             {
  21.                 offsetBegin = p;
  22.             }
  23.             else if (')' == *p)
  24.             {
  25.                 offsetEnd = p;
  26.                 break;
  27.             }
  28.         }
  29.         if (mangleName && offsetBegin && offsetEnd && mangleName < offsetBegin)
  30.         {
  31.             *mangleName++ = '\0';
  32.             *offsetBegin++ = '\0';
  33.             *offsetEnd++ = '\0';
  34.             
  35.             int status;
  36.             char *realName = abi::__cxa_demangle(mangleName, 0, 0, &status);
  37.             if (0 == status)
  38.                 oss << "\tstack dump [" << i << "]  " << symbols[i] << " : " << realName << "+";
  39.             else
  40.                 oss << "\tstack dump [" << i << "]  " << symbols[i] << mangleName << "+";
  41.             oss << offsetBegin << offsetEnd << std::endl;
  42.             free(realName);
  43.         }
  44.         else
  45.         {
  46.             oss << "\tstack dump [" << i << "]  " << symbols[i] << std::endl;
  47.         }
  48.     }
  49.     free(symbols);
  50.     oss << std::endl;
  51.     std::cout << oss.str(); // 打印函數(shù)調(diào)用棧信息
  52. }

三、Windwos 平臺

在 Windows 平臺下的代碼實現(xiàn),參考了國外某個老兄的代碼,如下:

1. 設(shè)置異常處理函數(shù)

 
 
 
 
  1. #include 
  2. #include 
  3. SetUnhandledExceptionFilter(exceptionHandler);

2. 捕獲異常,獲取函數(shù)調(diào)用棧信息

 
 
 
 
  1. void exceptionHandler(LPEXCEPTION_POINTERS info)
  2. {
  3.     CONTEXT *context = info->ContextRecord;
  4.     std::shared_ptr RaiiSysCleaner(nullptr, [&](void *) {
  5.       SymCleanup(GetCurrentProcess());
  6.     });
  7.   const size_t dumpSize = 64;
  8.   std::vector frameVector(dumpSize);
  9.   DWORD machine_type = 0;
  10.   STACKFRAME64 frame = {};
  11.   frame.AddrPC.Mode = AddrModeFlat;
  12.   frame.AddrFrame.Mode = AddrModeFlat;
  13.   frame.AddrStack.Mode = AddrModeFlat;
  14. #ifdef _M_IX86
  15.   frame.AddrPC.Offset = context->Eip;
  16.   frame.AddrFrame.Offset = context->Ebp;
  17.   frame.AddrStack.Offset = context->Esp;
  18.   machine_type = IMAGE_FILE_MACHINE_I386;
  19. #elif _M_X64
  20.   frame.AddrPC.Offset = context->Rip;
  21.   frame.AddrFrame.Offset = context->Rbp;
  22.   frame.AddrStack.Offset = context->Rsp;
  23.   machine_type = IMAGE_FILE_MACHINE_AMD64;
  24. #elif _M_IA64
  25.   frame.AddrPC.Offset = context->StIIP;
  26.   frame.AddrFrame.Offset = context->IntSp;
  27.   frame.AddrStack.Offset = context->IntSp;
  28.   machine_type = IMAGE_FILE_MACHINE_IA64;
  29.   frame.AddrBStore.Offset = context.RsBSP;
  30.   frame.AddrBStore.Mode = AddrModeFlat;
  31. #else
  32.   frame.AddrPC.Offset = context->Eip;
  33.   frame.AddrFrame.Offset = context->Ebp;
  34.   frame.AddrStack.Offset = context->Esp;
  35.   machine_type = IMAGE_FILE_MACHINE_I386;
  36. #endif
  37.   for (size_t index = 0; index < frameVector.size(); ++index)
  38.   {
  39.     if (StackWalk64(machine_type,
  40.            GetCurrentProcess(),
  41.            GetCurrentThread(),
  42.            &frame,
  43.            context,
  44.            NULL,
  45.            SymFunctionTableAccess64,
  46.            SymGetModuleBase64,
  47.            NULL)) {
  48.       frameVector[index] = frame.AddrPC.Offset;
  49.     } else {
  50.       break;
  51.     }
  52.   }
  53.   std::string dump;
  54.   const size_t kSize = frameVector.size();
  55.   for (size_t index = 0; index < kSize && frameVector[index]; ++index) {
  56.     dump += getSymbolInfo(index, frameVector);
  57.     dump += "\n";
  58.   }
  59. std::cout << dump; 
  60. }

主要是利用了 StackWalk64 這個函數(shù),從地址轉(zhuǎn)換為函數(shù)名稱。

利用以上幾個神器,基本上可以獲取到程序崩潰時的函數(shù)調(diào)用棧信息,定位問題,有如神助!


網(wǎng)站題目:Linux+Windows:程序崩潰時,在C++代碼中,如何獲取函數(shù)調(diào)用棧信息
文章網(wǎng)址:http://m.5511xx.com/article/ccddigc.html