linux怎么导出堆栈信息,在Linux与Windows上获取当前堆栈信息的方法

在编写稳定可靠的软件服务时经常用到输出堆栈信息,以便用户/开发者获取准确的运行信息。常用在日志输出,错误报告,异常检测。

在Linux有比较简便的函数获取堆栈信息:

#include

#include

#include

#include

#include

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

printf("[%d] %s\n",i,msgs[i]);

exit(1);

}

void baz() {

int *foo = (int*)-1; // make a bad pointer

printf("%d\n",*foo); // causes segfault

}

void bar() { baz(); }

void foo() { bar(); }

int main(int argc,char **argv) {

signal(SIGSEGV,handler); // install our handler

foo(); // this will call foo,bar,and baz. baz segfaults.

}

以上代码从参考的stackoverflow中稍作修改而来。核心就是backtrace与backtrace_symbols两个函数。

Windows下推荐用StackWalker这个开源代码,支持X86,AMD64,IA64。

如果你需要一个最简的代码,那么下面是我抽取出来的代码,明显比Linux要复杂一些。(Win的很多功能实现起来要复杂一些,当然也有很多功能实现要比Linux简单很多。)

我会做一些讲解,在后面。

#include "stdafx.h"

#include

#include

#include

#include

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,FALSE);

sire = SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS);

CONTEXT ctx = { 0 };

ctx.ContextFlags = CONTEXT_FULL;

RtlCaptureContext(&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,&me);

while (info) {

auto dw = SymLoadModule64(ph,me.szExePath,me.szModule,(DWORD64)me.modBaseAddr,me.modBaseSize);

if (!Module32Next(snap,&me))break;

}

CloseHandle(snap);

auto thread = GetCurrentThread();

PIMAGEHLP_SYMBOL64 sym = (IMAGEHLP_SYMBOL64 *)malloc(sizeof(IMAGEHLP_SYMBOL64) + 100);

if (!sym)

return;

memset(sym,sizeof(IMAGEHLP_SYMBOL64) + 100);

sym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);

sym->MaxNameLength = 100;

IMAGEHLP_LINE64 line = { 0 };

line.SizeOfStruct = sizeof(line);

for (;;) {

auto result = StackWalk(imageType,ph,thread,&sf,&ctx,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,&offset,sym)) {

UnDecorateSymbolName(sym->Name,und_fullname,100,UNDNAME_COMPLETE);

cout << und_fullname;

}

if (SymGetLineFromAddr64(ph,&offset_for_line,&line)) {

cout << " " << line.FileName << "(" << line.LineNumber << ")";

}

cout << endl;

}

}

else

break;

}

SymCleanup(ph);

}

}

int main()

{

ph = GetCurrentProcess();

foo();

return 0;

}

编译请链接dbghelp.lib

核心就是StackWalk与SymGetSymFromAddr64,SymGetLineFromAddr64。

StackWalk用于获取下一层堆栈。

SymGetSymFromAddr64用于获取当前函数名。

SymGetLineFromAddr64用于获取函数所在文件及行号。

为了这三个函数正常工作,还要初始化符号相关功能(SymInitialize),取得当前线程描述表(RtlCaptureContext),加载用到的模块(SymLoadModule64)。

用到了这两个头文件。

上面代码执行后会在控制台输出堆栈信息。

这篇在Linux与Windows上获取当前堆栈信息的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程小技巧。

总结

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值