Windows上获取当前调用堆栈信息,StackWalker的C语言实现

引子

这几天为了用编程的方式获取当前的调用堆栈信息,在网上进行了查询。发现在Linux平台上获取当前调用堆栈的信息相对容易。但在windows平台上获取当前调用堆栈的信息就不是那么容易。

网上有不少介绍windows平台上获取调用堆栈的文献,还有一些示例性的代码,但是绝大多数都不完整,没有办法直接运行得到结果。顺便说一句,有些人都没有验证是否可以得到正确的结果,就把代码贴了出来;有些人转载相关的文献,也是以讹传讹,给后来者许多的误导。

综合查找结果:GitHub上的这个项目StackWalker是最靠谱的,这个项目以前放在codeproject上。

网上有一些文献引荐了这个项目。经过下载,调试运行,该项目确实通过编程获取了当前的调用堆栈信息,而且显示的信息包括源文件名,行号,函数名等,非常完整,与visual studio自带的调用堆栈查看窗口的输出相比,能够直接看出是在源文件的哪一行的哪一个函数被调用了,确实是良心之作。

目前有一个小小的遗憾,就是这个StackWalker是用C++实现的,如果在C语言的代码中就不方便调用了。再次在网上,包括在StackWalker的项目页面中进行了查找,发现还没有一个用C语言实现的,在Windows上获取当前调用堆栈信息的项目。因此决定对StackWalker进行改造,实现一个C语言版的StackWalker。

正式开始

StackWalker原来的文件包打开后如下图所示:
在这里插入图片描述
其中核心文件用红笔勾出来了,主要就是main.cpp,StackWalker.cpp,StackWalker.h ,其它的文件主要是各种版本的VC的解决方案文件,这次改写使用VS2010,所以此处也将VS2010的解决方案文件用红笔勾了出来。

在系统中有两个核心类,class StackWalker,class StackWalkerInternal 。这次的改写工作主要就是将这两个类用Struct实现,由于Struct不能定义成员函数,只能定义函数指针,所以还要做指针与函数的绑定工作。

为了逻辑上更加清晰,将StackWalker.cpp 拆分成了三部分,StackWalker.c,StackWalker_Internal.c,StackWalker_struct.c 。这三部分别由.c文件与.h文件组成,测试用的代码放在main.c中。

改写后的文件夹结构如下:
在这里插入图片描述
这次改写涉及到的主要工作有如下几点:

  1. class转写为struct,但struct中不能定义函数,只能定义函数指针,函数指针与实际函数的绑定要手工完成;构造函数与析构函数要另外实现,并在合适的时机手工调用;
  2. new操作符要改写为工厂方法,delete操作符要改写为工厂方法
  3. this指针改写为self指针,并在参数列表中添加self指针项,在头文件中增加新的相关函数的声明
  4. 原来在类中定义的方法,要单独做为函数实现,并且加上原类名做前缀,避免名字冲突
  5. 原本在类中定义的结构体,枚举单独抽取出来
  6. 原本可以块中随时定义的变量,按标准c的要求,必须定义在块开始处,vc2010编译器不完全支持c99, 这样一来,很多方法变成函数后,变量的定义位置要移到函数开始处
  7. 原本C++中重载的方法,现在要重新命名
  8. 一些与操作系统相关的函数,C++版本与C版本的参数个数并不一样,需要手工追加一些实参。其中最受影响的函数有:_tcscat_s与_snprintf_s 。

下图是运行结果截图:
在这里插入图片描述
观察用红色箭头标出的部分,可以清楚地看到函数的调用堆栈信息:

e:\temp\t7\stackwalker_c\stackwalker_c\stackwalker.c (274): StackWalker_ShowCallstack
e:\temp\t7\stackwalker_c\stackwalker_c\stackwalker.c (226): StackWalker_ShowCurrentCallstack
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (31): Func5
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (37): Func4
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (41): Func3
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (45): Func2
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (49): Func1
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (54): StackWalkTest
e:\temp\t7\stackwalker_c\stackwalker_c\main.c (60): main

项目详情

直接在此处贴代码太过于烦琐,也不方便查看,因此将这个改写过的项目上传到了CSDN。感兴趣的朋友可以移步到此下载

如果不想使用积分,可以给我留言(CSDN不希望留邮箱)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Stackwalker 是一个调试工具,用于获取程序运行时的函数调用信息。它可以帮助开发人员快速定位程序中的问题,并提供更好的调试体验。 Stackwalker 可以在 C++ 等编程语言中使用,并且可以跨平台使用。一些常见的 Stackwalker 实现包括 StackWalk64 和 StackTrace。 ### 回答2: Stackwalker是一个用于跟踪程序运行时调用栈的工具。在软件开发中,调用栈对于排查和调试问题是非常重要的。调用栈可以显示程序在执行过程中被调用的函数和它们之间的关系。 Stackwalker能够帮助开发人员获取调用栈的信息,这对于分析程序中的错误和异常非常有帮助。它可以显示每个函数的地址和函数调用的顺序,帮助开发人员跟踪代码的执行路径。 Stackwalker可以通过一些调试技术来实现。例如,在C/C++程序中,可以使用调试器的接口来获取调用栈的信息。通过调试器,Stackwalker可以获得函数和地址的信息,并将它们按照调用顺序组织起来。 使用Stackwalker可以帮助开发人员定位问题的根源。当程序发生错误或崩溃时,开发人员通过查看调用栈的信息,可以确定是哪个函数调用出了问题,从而更快地定位和修复错误。 总之,Stackwalker是一个很有用的工具,可以帮助开发人员追踪程序在运行时的调用信息。它对于排查和解决问题非常有帮助,提高了代码调试和分析的效率和准确性。 ### 回答3: StackWalker是一个用于跟踪程序运行过程中调用栈的工具。在程序执行时,每个函数调用都会在调用栈中生成一个帧,记录了该函数的调用信息和局部变量等。StackWalker可以通过遍历调用栈来获取每个帧的信息,从而实现调用栈的分析和跟踪。 使用StackWalker可以在程序运行时获取当前线程的调用栈,并输出调用信息。这对于调试程序中的错误非常有帮助,可以帮助开发人员确定错误发生的位置以及函数的调用路径。通过分析调用栈,还可以检查函数的调用关系,帮助开发人员理解程序的执行流程和调用顺序。 StackWalker可以用于不同编程语言和平台。在C++中,可以通过调用StackWalker提供的接口来获取调用信息StackWalker提供了一些方法,如GetCurrentStackTrace()用于获取当前线程的调用栈;GetCallstackEntry()用于获取指定帧的调用信息等。通过使用这些方法,可以实现调用栈的遍历和分析。 总而言之,StackWalker是一个方便的工具,能够帮助开发人员在程序运行时跟踪调用栈,并获取调用栈的相关信息。它在程序调试和错误定位中起到了重要的作用,对于分析程序的执行流程和调用关系非常有帮助。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值