Debug_crash_Windbg调试

1 流程崩溃问题

对于程序运行异常的情况,如崩溃,可分为事后调试和运行时附加调试。事后调试一般有dump文件生成。若崩溃可复现,可以通过附加到正在运行的程序进行调试。代理进程名为VmModuleProxy.exe,一般使用windbg进行崩溃问题定位。
很多情况下都是流程运行导致代理进程崩溃,dump文件存在: VM安装目录\ Applications\log\ModuleProxy目录下。下面主要介绍怎样使用windbg,定位基本的代理进程崩溃问题。
这里所述的崩溃问题定位方式不仅仅适用于VmModuleProxy.exe,对于其他进程也可用相同的方式。

1.1 Windbg使用

由于模块代理进程VmModuleProxy.exe是64位程序,因为确认使用64位版本的windbg程序。

1.1.1 设置符号文件

在每一次VM发布时,每一份成果物(exe、dll)都存在对应的PDB文件(即调试符号文件)。这些文件一般在项目成果物路径上。这些文件对于定位崩溃问题至关重要。因此可将每次发布版对应的PDB文件保存下来,待调试问题时可重复利用。
以VM3.2版本为例。假设在我机器上对应的VM3.2版本的PDB路径为: E:\VM_Symbols\V320。
可以设置windbg的符号路径为srvE:\symbolcachehttp://msdl.microsoft.com/download/symbols; E:\VM_Symbols\V320。
Debug_crash_Windbg调试_第1张图片
图8 设置符号路径

Debug_crash_Windbg调试_第2张图片
图9 设置符号路径
其中srvE:\symbolcachehttp://msdl.microsoft.com/download/symbols,表示从微软官网下载系统符号并缓存在本地E:\symbolcache目录下,远程下载可能速度较慢。不过一般情况下,都是VM应用引起的崩溃,仅仅设置VM符号文件也足够定位问题。如下图10示例中的E:\VM_Symbols\V320。若想关注于模块中具体的哪步系统调用产生了问题,则需要设置系统符号路径。
Debug_crash_Windbg调试_第3张图片 图10 设置符号路径

请注意:在定位具体位置时,必须保证PDB符号文件是与VM中各项成果物同时产生的,即时间点必须匹配,否则会产生不正确的分析结果。

1.1.2 Dump文件分析

进程在崩溃之后,会有dump文件生成。按照上节所述,在设置好windbg的符号文件路径之后,就可以进行dump文件分析了。分为以下几个步骤。
第一步:打开dump文件,将dump文件拖放至windbg窗口中即可。
第二步:首先输入.ecxr,接着输入kb ; 或者直接输入analyze –v。这两项都可以切换到异常上下文,查看具体的崩溃堆栈位置。

Debug_crash_Windbg调试_第4张图片
图11 分析dump堆栈

如本例中的崩溃模块为IMVSImageCombineProcessModule,崩溃位置在MVBI_SEG_CannySelectThreshold_16s_C1R+0x151。在不能定位到源码的情况下,0x151表示此函数对应的汇编代码偏移位置。
一般堆栈是以XXXModule!FunctionName的形式呈现。XXXModule表示模块名,FunctionName表示当前调用函数。如果定位到到模块名属于VM自身的一部分,如算法模块、或者代理进程、或者模块框架(如IMVSCircleFindModu、VMModuleFrame),这样的结果一般具有参考价值。若最终定位到系统的库文件,如ntdll、或者kernelbase,那么需要进一步查看。
第三部: 若以上两步骤中,还不能定位属于VM中模块代码的问题,此时输入.lastevent,查看查看具体的崩溃原因:
情况1:对于CLR异常,请尝试修复.net环境。
在这里插入图片描述
情况2:堆栈不具有可读性或者内存越界(如Access violation、Stack overflow)。如下图所示,异常为内存越界,但异常模块属于系统模块,因为可以认为内存堆栈已被破坏,调试工具展示了不正确的结果。此种情况可能需要手动重构调用堆栈,较为复杂。若果异常可复现,那么可以尝试下节4.1.3介绍的实时附加调试的方式,这种方式较为简便。
在这里插入图片描述
在这里插入图片描述

1.1.3 可复现崩溃定位

对于可复现的问题,一般使用windbg附加到当前正在运行进程的方式,步骤如下:
第一步(可选):开启页堆操作,对于大部分的崩溃,一般都是由内存越界引起,开启页堆,可以在第一时间发现崩溃位置点。也就是说可以使得我们在异常第一现场及时发现,避免运行了一段时间后才导致崩溃。
在开始菜单、或在windbg安装目录下,打开gflags.exe。
Debug_crash_Windbg调试_第5张图片
图12 配置gflags

Debug_crash_Windbg调试_第6张图片

图13 配置gflags
因为我们这里查流程崩溃问题,所以输入VmModuleProxy.exe,按tab,勾选“Enable page heap”,确定。
注意:定位完问题之后,在gflags中请将此配置删除,还原至初始设置,否则进程会额外占用内存资源,影响运行速度。
第二步:使用windbg附加在当前正在运行的代理进程。
启动VM后,打开windbg准备附加至进程VmModuleProxy.exe。
Debug_crash_Windbg调试_第7张图片
图14 附加进程
Debug_crash_Windbg调试_第8张图片
图15 附加进程

附加到进程后,首先会进入初始断点,此时程序处于挂起状态,输入命令”g”,让程序继续运行。
Debug_crash_Windbg调试_第9张图片
图16 越过初始断点

继续操作VM,当有崩溃异常出现时,windbg会中断代理进程运行,此时的调试与分析dump文件一致。借助于“.ecxr; kb” 或者 “analyze -v”查看具体的崩溃位置即可。
4.1.4 抓取dump文件
附加至待调试目标进程之后,此时目标进程处于中断状态。
输入:
.dump –ma D:\VmModuleProxy.dmp (说明:此命令会抓取进程的几乎所有信息,数据文件较大,网络传输方便时可使用此命令。这种文件信息较全,事后调试起来方便)
.dump –m D:\VmModuleProxy.dmp(说明:此命令抓取进程的基本信息,数据文件小,远程网络受限时,建议使用此方式)

2 流程卡死问题

 对于流程卡死问题,主要是由于某一算法或逻辑模块在执行时迟迟不退出,从而造成流程不能结束。其中又可细分为2种情况。

模块卡主
此时模块处于死锁或等待状态,代理进程的CPU利用率很低。

模块死循环
此时模块可能陷入不断循环,代理进程的CPU利用率居高不下。

不过在定位流程卡死问题时,有一个共同规律可遵循:就是在查看当前进程中每个执行线程堆栈快照时,若其中的某一个线程处于XXXModule::Process函数中,那么出问题的模块很可能就是它了。其中XXXModule是属于VM中的一个算法或逻辑模块名,Process表示该模块必须实现的一个接口,此接口名称不会变化。

2.1 模块卡住

当触发一次流程执行后,流程迟迟未结束,此时通过查看代理进程VmModuleProxy.exe的CPU利用率,若CPU占用率很低,此时大体可以判定流程中的某个模块在某处操作处于等待状态。
此种问题的解决办法就是附加至当前代理进程,打印出当前所有线程的堆栈快照,在其中找出处于XXXModule::Process调用的线程,此时出问题的模块就是XXXModule,具体的问题位置即导致卡住的函数可以通过查看调用堆栈函数来获得。
操作步骤如下:
第一步:打开windbg,配置对应的PDB符号文件路径。
第二步:附加至VmModuleProxy.exe,此时进程处于中断状态。
第三步:输入~*k,打印当前进程中所有的线程快照。
第四步:依次过目每个线程堆栈,查找其中有处于XXXModule::Process调用的线程,继而找出有问题的模块。
举个例子:
假如一个方案中存在:图像源、圆查找、线查找、blob分析,其中圆查找做了特殊处理,在执行流程时,会处于死等状态,用来模拟流程不能退出的情况。
在任务管理器中,查看进程,发现其CPU占用率几乎为0。
在这里插入图片描述
图17 查看代理进程CPU
使用Windbg附加至进程,查看当前所有线程快照。
Debug_crash_Windbg调试_第10张图片
图18 附加至模块代理进程
输入~*k打印每个线程的快照:
在这里插入图片描述
图19 打印进程内所有线程快照
在线程快照中找XXXModule::Process的标记,如下图中,可以看出问题模块为圆查找。
Debug_crash_Windbg调试_第11张图片
图20 查找处于XXXModule::Process中的模块

在本例中我们模拟卡死的模块就是圆查找,而图20中红框标注的部分就是我们需要定位的问题模块。

2.2 模块死循环

当触发一次流程执行后,流程迟迟未结束,此时通过查看代理进程VmModuleProxy.exe的CPU利用率,若CPU占用率很高(如对于4核CPU,单核占用率持续为25%),此时大体可以判定流程中的某个模块在某处处于循环状态。
对于死循环问题,借助于工具Process Explorer.exe可以方便快捷的查看。
举个例子:
假如一个方案中存在:图像源、圆查找、线查找、blob分析,其中圆查找做了特殊处理,在执行流程时,会不断的进行循环,用来模拟流程不能退出的情况。
第一步:打开Process Explorer.exe,使用64位。
第二步:配置符号文件路径。如图。
Debug_crash_Windbg调试_第12张图片
图21 配置Process Explorer符号路径

Debug_crash_Windbg调试_第13张图片
图22 输入VM符号路径

配置好本机符号路径之后,点击OK即可。双击VmModuleProxy.exe,进入属性页。
Debug_crash_Windbg调试_第14张图片
图23 查看模块代理进程属性
切换至Threads标签页,查看当前线程的运行情况。
Debug_crash_Windbg调试_第15张图片
图24 查看当前线程运行状况

查看id为17372的线程,CPU利用率一直居高不下,可以肯定是此线程操作陷入了长时间循环导致。点击按钮Stack,进一步查看当前线程正在进行什么操作。
Debug_crash_Windbg调试_第16张图片

                       图25 定位到异常模块

如图25所示,id为17372的线程一直为忙碌状态,查看其当前正在调用IMVSCircleFindModu::Process调用中,这也就是我们需要查找的问题模块。

3 小结

本文主要介绍了方案加载、方案保存、流程崩溃、流程卡死问题的定位方法,这些问题也是在技术支持比例中占比较高,后续在处理项目支持问题时,可先参考文中的介绍方法将问题做初步处理,可一定程度上避免每次都去找开发人员定位,节省时间。
问题定位、排查原因本身就是一项比较繁杂的事情,除了这些常见问题之外,其他一些则需要结合现有的数据综合比对去看,目前并没有一种完美统一的方式。文中介绍的方式主要适用于日常的基本技术支持场景,对于其他复杂问题,则可能需要开发这边去协助解决。
文中提到的工具包括:Windbg、Process Explorer。在使用两者时,必须配置正确的PDB文件。
程序启动之前,通过配置gflags,启动之后再用windbg附加至进程,可以及时检测到异常并中断调试。特别需要注意的是:在定位完问题之后,请及时将调试程序的gflags配置恢复至默认,否则会额外占用内存,影响执行效率。

分析dump 步骤 说明
第一步:设置正确的调试符号路径 如:srvE:\symbolcachehttp://msdl.microsoft.com/download/symbols; E:\VM_Symbols\V310; 斜体表示的系统符号路径可选。
根据使用的模块(在VM中使用CTRL+M查看模块名),按需拷贝对应的pdb文件即可。其中VmModuleFrame.pdb最好一起拷贝过去。
第二步:打开dump文件,拖至windbg窗口即可
第三步:输入.ecxr,接着输入kb;或者直接输入analyze –v。切换到异常上下文,查看堆栈位置。 堆栈从底部依次向上查看。对找不到对应的算法模块名,可能堆栈被破坏。使用.lastevent命令,查看若是CLR异常,尝试修复.net环境。

附加调试 步骤 说明
第一步(可选):打开gflags,输入进程名VmModuleProxy,勾选”Enable page heap”。 开启页堆,主要是为了在异常出现时第一时间被调试器检测到。若异常发生时,使用kb查看的堆栈定位不到具体的算法模块或崩溃位置,可尝试开启此选项。
注意:调试完毕后,请还原此配置,否则会额外占用内存,影响运行效率。
第二步:附加值代理进程VmModuleProxy.exe。 之前最好设置pdb符号路径。若只是简单抓取dump,不进行调试,则不用。
第三步:操作VM,尝试复现异常,当复现时,会中断到windbg。
第四步:输入.ecxr,接着输入kb;或者直接输入analyze –v。切换到异常上下文,查看堆栈位置。 堆栈从底部依次向上查看。对找不到对应的算法模块名,可能堆栈被破坏。使用.lastevent命令,查看若是CLR异常,尝试修复.net环境。

模块卡死 步骤
第一步:打开windbg,配置对应的PDB符号文件路径。
第二步:附加至VmModuleProxy.exe,此时进程处于中断状态。
第三步:输入~*k,打印当前进程中所有的线程快照。
第四步:依次过目每个线程堆栈,查找其中有处于XXXModule::Process调用的线程,继而找出有问题的模块。

模块死循环 步骤 说明
第一步:确认VmModuleProxy.exe进程cpu占用率一致居高不下。 死循环表现为cpu单核占用率很高,造成流程不能结束
第二步:打开Process explorer.exe,配置符号路径。
第三步:进入VmModuleProxy.exe属性页,查看cpu占用率高的线程堆栈
第四步:查找XXXModule!Function XXXModule表示模块名称,Function表示当前正在执行的函数

工具 使用到的功能
windbg 命令:.ecxr; kb; analyze –v; ~*kb; .lastevent
gflags 页堆选项: “Enable page heap”
Process explorer 查看进程资源、线程堆栈

你可能感兴趣的:(Debug,debug)