在Linux与Windows上获取当前堆栈信息的方法
在编写稳定可靠的软件服务时经常用到输出堆栈信息,以便用户/开发者获取准确的运行信息。常用在日志输出,错误报告,异常检测。
在Linux有比较简便的函数获取堆栈信息:
#include#include #include #include #include voidhandler(intsig){ void*array[5]; size_tsize; //getvoid*'sforallentriesonthestack size=backtrace(array,5); //printoutalltheframestostderr fprintf(stderr,"Error:signal%d:\n",sig); char**msgs=backtrace_symbols(array,size); for(inti=1;i 以上代码从参考的stackoverflow中稍作修改而来。核心就是backtrace与backtrace_symbols两个函数。
Windows下推荐用StackWalker这个开源代码,支持X86,AMD64,IA64。
如果你需要一个最简的代码,那么下面是我抽取出来的代码,明显比Linux要复杂一些。(Win的很多功能实现起来要复杂一些,当然也有很多功能实现要比Linux简单很多。)
我会做一些讲解,在后面。
#include"stdafx.h" #include#include #include #include usingnamespacestd; HANDLEph; voidbaz() { int*v=0; *v=0; } voidbar() { baz(); } voidfoo(){ __try{ bar(); } __except(EXCEPTION_EXECUTE_HANDLER){ autosire=SymInitialize(ph,0,FALSE); sire=SymSetOptions(SymGetOptions()|SYMOPT_LOAD_LINES|SYMOPT_FAIL_CRITICAL_ERRORS); CONTEXTctx={0}; ctx.ContextFlags=CONTEXT_FULL; RtlCaptureContext(&ctx); STACKFRAME64sf={0}; #ifdef_M_IX86//ignoreIA64 autoimageType=IMAGE_FILE_MACHINE_I386; sf.AddrPC.Offset=ctx.Eip; sf.AddrPC.Mode=AddrModeFlat; sf.AddrFrame.Offset=ctx.Ebp; sf.AddrFrame.Mode=AddrModeFlat; sf.AddrStack.Offset=ctx.Esp; sf.AddrStack.Mode=AddrModeFlat; #elif_M_X64 autoimageType=IMAGE_FILE_MACHINE_AMD64; sf.AddrPC.Offset=ctx.Rip; sf.AddrPC.Mode=AddrModeFlat; sf.AddrFrame.Offset=ctx.Rsp; sf.AddrFrame.Mode=AddrModeFlat; sf.AddrStack.Offset=ctx.Rsp; sf.AddrStack.Mode=AddrModeFlat; #endif MODULEENTRY32me; autosnap=CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId()); autoinfo=Module32First(snap,&me); while(info){ autodw=SymLoadModule64(ph,0,me.szExePath,me.szModule,(DWORD64)me.modBaseAddr,me.modBaseSize); if(!Module32Next(snap,&me))break; } CloseHandle(snap); autothread=GetCurrentThread(); PIMAGEHLP_SYMBOL64sym=(IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64)+100); if(!sym) return; memset(sym,0,sizeof(IMAGEHLP_SYMBOL64)+100); sym->SizeOfStruct=sizeof(IMAGEHLP_SYMBOL64); sym->MaxNameLength=100; IMAGEHLP_LINE64line={0}; line.SizeOfStruct=sizeof(line); for(;;){ autoresult=StackWalk(imageType,ph,thread,&sf,&ctx,0,SymFunctionTableAccess64,SymGetModuleBase64,0); if(result){ DWORD64offset=0; DWORDoffset_for_line=0; CHARund_fullname[100]; if(sf.AddrPC.Offset!=0){ if(SymGetSymFromAddr64(ph,sf.AddrPC.Offset,&offset,sym)){ UnDecorateSymbolName(sym->Name,und_fullname,100,UNDNAME_COMPLETE); cout< 编译请链接dbghelp.lib
核心就是StackWalk与SymGetSymFromAddr64,SymGetLineFromAddr64。
StackWalk用于获取下一层堆栈。
SymGetSymFromAddr64用于获取当前函数名。
SymGetLineFromAddr64用于获取函数所在文件及行号。
为了这三个函数正常工作,还要初始化符号相关功能(SymInitialize),取得当前线程描述表(RtlCaptureContext),加载用到的模块(SymLoadModule64)。
用到了
这两个头文件。 上面代码执行后会在控制台输出堆栈信息。
这篇在Linux与Windows上获取当前堆栈信息的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。