分享在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 分享