栈windows linux,Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息...
一、前言
程序在執(zhí)行過程中 crash 是非常嚴(yán)重的問題,一般都應(yīng)該在測試階段排除掉這些問題,但是總會有漏網(wǎng)之魚被帶到 release 階段。
因此,程序的日志系統(tǒng)需要偵測這種情況,在代碼崩潰的時候獲取函數(shù)調(diào)用棧信息,為 debug 提供有效的信息。
這篇文章的理論知識很少,直接分享 2 段代碼:在 Linux 和 Windows 這 2 個平臺上,如何用C++ 來捕獲函數(shù)調(diào)用棧里的信息。
二、Linux 平臺
1. 注冊異常信號的處理函數(shù)
需要處理哪些異常信號
#include?
#include?
#include?
const?std::map?Signals?=?{
{SIGINT,?"SIGINT"},
{SIGABRT,?"SIGABRT"},
{SIGFPE,?"SIGFPE"},
{SIGILL,?"SIGILL"},
{SIGSEGV,?"SIGSEGV"}
//?可以添加其他信號
};
注冊信號處理函數(shù)
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. 捕獲異常,獲取函數(shù)調(diào)用棧信息
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 平臺下的代碼實現(xiàn),參考了國外某個老兄的代碼,如下:
1. 設(shè)置異常處理函數(shù)
#include?
#include?
SetUnhandledExceptionFilter(exceptionHandler);
2. 捕獲異常,獲取函數(shù)調(diào)用棧信息
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 這個函數(shù),從地址轉(zhuǎn)換為函數(shù)名稱。
利用以上幾個神器,基本上可以獲取到程序崩潰時的函數(shù)調(diào)用棧信息,定位問題,有如神助!
【編輯推薦】
【責(zé)任編輯:姜華 TEL:(010)68476606】
點贊 0
總結(jié)
以上是生活随笔為你收集整理的栈windows linux,Linux+Windows: 程序崩溃时,在 C++ 代码中,如何获取函数调用栈信息...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 登和平视显示无法连接服务器,提醒信息的推
- 下一篇: vm客户机隔离不能选_开汽车美容店,这些