分享在Linux與Windows上獲取當前堆棧信息實例

下面小編就為大家帶來一篇在linuxwindows上獲取當前堆棧信息的方法。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

在編寫穩定可靠的軟件服務時經常用到輸出堆棧信息,以便用戶/開發者獲取準確的運行信息。常用在日志輸出,錯誤報告,異常檢測。

linux有比較簡便的函數獲取堆棧信息:

#include?<stdio.h>  #include?<execinfo.h>  #include?<signal.h>  #include?<stdlib.h>  #include?<unistd.h>      void?handler(int?sig)?{  ?void?*array[5];  ?size_t?size;    ?//?get?void*'s?for?all?entries?on?the?stack  ?size?=?backtrace(array,?5);    ?//?print?out?all?the?frames?to?stderr  ?fprintf(stderr,?"Error:?signal?%d:n",?sig);  ?char**?msgs?=?backtrace_symbols(array,?size);  ?for(int?i=1;i<size void int><p>以上代碼從參考的stack<a href="http://www.php.cn/wiki/414.html" target="_blank">錯誤報告</a>中稍作修改而來。核心就是backtrace與backtrace_symbols兩個函數。</p> <p>windows下推薦用StackWalker這個開源代碼,支持X86,AMD64,IA64。</p> <p>如果你需要一個最簡的代碼,那么下面是我抽取出來的代碼,明顯比Linux要復雜一些。(Win的很多功能實現起來要復雜一些,當然也有很多功能實現要比Linux簡單很多。)</p> <p>我會做一些講解,在后面。</p> <p class="jb51code"><br></p> <pre class="brush:php;toolbar:false">#include?"stdafx.h"  #include?<windows.h>  #include?<iostream>  #include?<dbghelp.h>  #include?<tlhelp32.h>    using?namespace?std;    HANDLE?ph;    void?baz()  {  ?int*?v?=?0;  ?*v?=?0;  }  void?bar()  {  ?baz();  }    void?foo(){  ?try?{  ??bar();  ?}  ?except(EXCEPTION_EXECUTE_HANDLER)?{  ??auto?sire?=?SymInitialize(ph,?0,?FALSE);  ??sire?=?SymSetOptions(SymGetOptions()?|?SYMOPT_LOAD_LINES?|?SYMOPT_FAIL_CRITICAL_ERRORS);  ??CONTEXT?ctx?=?{?0?};  ??ctx.ContextFlags?=?CONTEXT_FULL;  ??RtlCaptureContext(&amp;ctx);  ??STACKFRAME64?sf?=?{?0?};  ?#ifdef?_M_IX86?//?ignore?IA64  ??auto?imageType?=?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  ??auto?imageType?=?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    ??MODULEENTRY32?me;  ??auto?snap?=?CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,?GetCurrentProcessId());  ??auto?info?=?Module32First(snap,?&amp;me);  ??while?(info)?{  ???auto?dw?=?SymLoadModule64(ph,?0,?me.szExePath,?me.szModule,?(DWORD64)me.modBaseAddr,?me.modBaseSize);  ???if?(!Module32Next(snap,?&amp;me))break;  ??}  ??CloseHandle(snap);  ??auto?thread?=?GetCurrentThread();    ??PIMAGEHLP_SYMBOL64?sym?=?(IMAGEHLP_SYMBOL64?*)malloc(sizeof(IMAGEHLP_SYMBOL64)?+?100);  ??if?(!sym)  ???return;  ??memset(sym,?0,?sizeof(IMAGEHLP_SYMBOL64)?+?100);  ??sym-&gt;SizeOfStruct?=?sizeof(IMAGEHLP_SYMBOL64);  ??sym-&gt;MaxNameLength?=?100;    ??IMAGEHLP_LINE64?line?=?{?0?};  ??line.SizeOfStruct?=?sizeof(line);  ??for?(;;)?{  ???auto?result?=?StackWalk(imageType,?ph,?thread,?&amp;sf,?&amp;ctx,?0,?SymFunctionTableAccess64,?SymGetModuleBase64,?0);  ???if?(result)?{  ????DWORD64?offset?=?0;  ????DWORD?offset_for_line?=?0;  ????CHAR?und_fullname[100];    ????if?(sf.AddrPC.Offset?!=?0)?{  ?????if?(SymGetSymFromAddr64(ph,?sf.AddrPC.Offset,?&amp;offset,?sym))?{  ??????UnDecorateSymbolName(sym-&gt;Name,?und_fullname,?100,?UNDNAME_COMPLETE);  ??????cout?<p>編譯請鏈接dbghelp.lib</p> <p>核心就是StackWalk與SymGetSymFromAddr64,SymGetLineFromAddr64。</p> <p><span style="background-color: #ccffcc"><strong>StackWalk用于獲取下一層堆棧。</strong></span></p> <p><span style="background-color: #ccffcc"><strong>SymGetSymFromAddr64用于獲取當前函數名。</strong></span></p> <p><span style="background-color: #ccffcc"><strong>SymGetLineFromAddr64用于獲取函數所在文件及行號。</strong></span></p> <p>為了這三個函數正常工作,還要初始化符號相關功能(SymInitialize),取得當前線程描述表(RtlCaptureContext),加載用到的模塊(SymLoadModule64)。</p> <p>用到了<dbghelp.h><tlhelp32.h>這兩個頭文件。</tlhelp32.h></dbghelp.h></p> <p>上面代碼執行后會在控制臺輸出堆棧信息。</p></tlhelp32.h></dbghelp.h></iostream></windows.h>

? 版權聲明
THE END
喜歡就支持一下吧
點贊13 分享