日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

發布時間:2024/9/27 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 栈windows linux,Linux+Windows: 程序崩溃时,在 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?sigactionaction;

sigemptyset(&action.sa_mask);

action.sa_sigaction?=?&sigHandler;

action.sa_flags?=?SA_SIGINFO;

for(const?auto?&sigPair?:?Signals)

{

if?(sigaction(sigPair.first,?&action,NULL)?

fprintf(stderr,?"Error:?sigaction?failed!?\n");

}

2. 捕獲異常,獲取函數調用棧信息

void?sigHandler(intsignum,?siginfo_t?*info,?void?*ctx)

{

const?size_t?dump_size?=?50;

void?*array[dump_size];

intsize=?backtrace(array,?dump_size);

char**symbols?=?backtrace_symbols(array,size);

std::ostringstream?oss;

for(inti?=?0;?i?

{

char*mangleName?=?0;

char*offsetBegin?=?0;

char*offsetEnd?=?0;

for(char*p?=?symbols[i];?*p;?++p)

{

if?('('==?*p)

{

mangleName?=?p;

}

elseif?('+'==?*p)

{

offsetBegin?=?p;

}

elseif?(')'==?*p)

{

offsetEnd?=?p;

break;

}

}

if?(mangleName?&&?offsetBegin?&&?offsetEnd?&&?mangleName?

{

*mangleName++?=?'\0';

*offsetBegin++?=?'\0';

*offsetEnd++?=?'\0';

intstatus;

char*realName?=?abi::__cxa_demangle(mangleName,?0,?0,?&status);

if?(0?==?status)

oss?<

else

oss?<

oss?<

free(realName);

}

else

{

oss?<

}

}

free(symbols);

oss?<

std::cout?<

}

三、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_tindex=?0;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_tindex=?0;index

dump?+=?getSymbolInfo(index,?frameVector);

dump?+=?"\n";

}

std::cout?<

}

主要是利用了 StackWalk64 這個函數,從地址轉換為函數名稱。

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

【編輯推薦】

【責任編輯:姜華 TEL:(010)68476606】

點贊 0

總結

以上是生活随笔為你收集整理的栈windows linux,Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。