何时使用Windbg静态分析?何时使用Windbg动态调试?

目录

1、概述

2、使用Windbg静态分析dump文件

2.1、异常捕获模块自动生成dump文件

2.2、从Windows任务管理器中导出dump文件

2.3、从正在动态调试的Windbg中使用命令导出dump文件

2.4、使用Windbg静态分析dump文件的一般步骤

3、使用Windbg动态调试目标进程

3.1、程序发生异常,但异常捕获模块没有捕获到

3.2、异常捕获模块感知到了异常,但导出dump文件时产生了二次崩溃

3.3、程序并没有发生C++异常,只是发生卡死或死循环,异常捕获模块感知不到

3.4、程序运行过程中检测到不正常,调用abort函数强制结束进程,导致程序闪退

3.5、Visual Studio调试程序时产生异常,但看不到有效的函数调用堆栈,可以尝试使用Windbg进行动态调试

3.6、程序启动崩溃或失败时

3.7、程序弹出报错提示框时

3.8、使用Windbg动态调试目标进程的一般步骤

4、其他场景说明

5、在实际排查问题时,可能要尝试多种排查方法

6、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具案例集锦(专栏文章正在更新中...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N6B9https://blog.csdn.net/chenlycly/category_11931267.html       使用Windbg分析C++软件问题时,可以静态分析,也可以动态调试。经常有朋友问,到底什么时候使用Windbg静态分析?什么时候Windbg进行动态调试?下面根据近几年来排查C++软件异常遇到的问题场景和项目实例,给大家做个详细的总结。

1、概述

       一般情况下,有dump文件时,使用Windbg静态分析dump文件即可;没有dump文件时,可能就需要使用Windbg去动态调试目标进程了。如果dump文件中的信息不足以分析出问题时,也可以尝试使用Windbg去动态调试。

       此外,如果使用Visual Studio调试代码时遇到异常,但在Visual Studio中分析不出来问题,比如刚启动调试时就产生异常或者报错,可以使用Windbg动态调试进行分析。 

2、使用Windbg静态分析dump文件

      Windbg静态分析的对象就是dump文件,必须要有dump文件。一般生成dump文件的方式主要有三种,分别是异常捕获模块生成、从Windows任务管理器中导出、从正在调试的Windbg中使用命令导出。

2.1、异常捕获模块自动生成dump文件

        为了让软件能自动捕获运行时的异常,一般会在软件中安装异常捕获模块。当软件发生异常时,异常捕获模块感知到异常,自动将包含异常上下文信息导出到dump文件中。有的软件甚至会弹出崩溃反馈提示框,比如如下所示的企业微信的提示框:

提示用户上传log日志和dump文件。为什么不自动上传呢?因为要上传用户机器上的文件,可能会涉及到用户隐私和用户信息安全,不能随意上传,必须经过用户授权后上传或者让用户上传。

       异常捕获库可以选用Google开源库CrashRpt,或者使用Chrome开源代码中的Breakpad或者Crashpad,对于QT程序则可以选用qBreakpad。程序发生异常时,异常捕获模块感知到,会将异常上下文信息导出到dump文件中。事后可以取来dump文件,使用Windbg进行静态分析了。

       异常捕获模块一般是调用系统API函数miniDumpWriteDump去生成dump文件,可以控制传给该API函数的参数去控制生成的dump文件的大小。此时一般生成的是比较小的mini dump文件,因为dump文件是保存在用户电脑上,不能生成全dump文件,因为全dump文件比较大(包含了所有内存信息,文件大小可能接近进程的总虚拟内存),会占用用户大量的磁盘空间。此外,dump文件可能要上传服务器,文件过大会给上传带来较大的网络负担,所以dump文件也不能太大。一般分析mini dump文件就能定位问题了。

2.2、从Windows任务管理器中导出dump文件

       如果程序中的线程出现卡死(可能是死循环或死锁引发的)或者程序运行弹出报错提示框,这些情况下程序的进程还在,可以直接到Windows任务管理器中手动导出dump文件。事后取来dump文件进行分析。

        从Windows任务管理器中导出dump文件的操作步骤是这样的。打开Windows任务管理器,找到出问题的目标进程,右键点击该进程,在弹出的右键菜单中点击“创建转储文件”菜单项:

即可导出包含进程上下文信息的到dump文件中。

       其实程序出现卡死或者运行报错时,还为时不晚的,可以直接将Windbg附加到进程上进行分析的。但有些客户比较敏感(比如安全级别比较高),不允许远程到机器上将Windbg附加上去,甚至都连Windbg都不让安装,这是就可以让客户手动从Windows任务管理器的进程列表中导出。这种方式导出的dump文件是全dump文件,文件会比较大,包含了进程的所有内存信息。

2.3、从正在动态调试的Windbg中使用命令导出dump文件

       可能正在使用Windbg调试目标进程,但一时半会又分析不出问题,不能长时间占用出问题的电脑,电脑主人还需要用。我们可以使用Windbg命令.dump导出当前正在调试的进程的dump文件,具体的命令样式可以这样:

.dump /ma D:\0606.dmp

事后取来dump文件,然后使用Windbg静态分析这个dump文件,继续分析问题。一般此时导出的也是全dump文件。

2.4、使用Windbg静态分析dump文件的一般步骤

       取来dump文件,使用Windbg打开,首先输入.excr命令切换到发生异常的上下文,然后使用kn命令查看发生异常时的函数调用堆栈,然后将函数调用堆栈与源码对应起来分析。一般此时需要根据函数调用堆栈中的模块,去找这些模块的pdb文件,然后再去查看函数调用堆栈,有了pdb文件中的函数及变量符号后,函数调用堆栈中可以看到具体的函数名称和代码行号:

甚至可以直接在Windbg中查看函数中局部变量的值或者函数所在类对象的成员变量的值。

       关于Windbg静态分析dump文件的详细步骤及相关要点,可以参见我之前写的文章:

使用Windbg静态分析dump文件的一般步骤及要点详解https://blog.csdn.net/chenlycly/article/details/130873143

3、使用Windbg动态调试目标进程

       如果没有生成dump文件,则没法使用Windbg进行静态分析,这时就需要使用Windbg进行动态调试了,即将Windbg动态附加到目标进程上进行调试。动态调试有两种方式:

1)直接使用Windbg启动目标程序;
2)先将目标程序启动起来,然后将Windbg附加到目标进程上。

当目标程序发生异常,Windbg就会感知到,会自动中断下来,这样使用Windbg命令就能查看当前发生的异常类型并查看此时的函数调用堆栈了。

       没有生成dump文件,有几种场景,这些场景需要使用Windbg的动态调试了,下面来详细介绍一下。

3.1、程序发生异常,但异常捕获模块没有捕获到

       程序中安装的异常捕获模块,并不能感知并捕获所有场景下的异常,即还是有少部分异常是捕获不到的。捕获不到的,自然就不会生成dump文件了。我们在项目中也时常会遇到,程序在使用过程中发生闪退或崩溃,异常捕获模块没捕获到,没有生成dump文件。一般遇到这类情况,都会让测试人员将Windbg附加到目标进程上,和目标进程一起跑,一旦目标进程运行过程中发生异常,Windbg会第一时间感知到并中断下来,此时就可以查看发生的异常类型和函数调用堆栈了。

3.2、异常捕获模块感知到了异常,但导出dump文件时产生了二次崩溃

       程序发生了异常,异常捕获模块感知到了,但在导出dump文件的过程中产生了二次崩溃,可能没生成dump文件,或者生成的dump文件大小为0,这种情况下也需要使用Windbg进行动态调试的。这个场景我们在项目中也遇到过多次。

3.3、程序并没有发生C++异常,只是发生卡死或死循环,异常捕获模块感知不到

       程序并没有发生C++异常,只是业务逻辑上产生异常(比如不能正常处理业务了),比如发生多线程死锁或死循环。因为并没有产生C++异常,异常捕获模块是感知不到的,所以也就无法生成dump文件。这个也需要将Windbg附加到进程上进行动态调试,进行详细分析的。

3.4、程序运行过程中检测到不正常,调用abort函数强制结束进程,导致程序闪退

       如果程序在运行过程中监测到不正常的情况,直接调用abort函数强制将进程终止了,这样给人一种程序发生崩溃闪退的感觉。这种情况也是没有发生C++异常,异常捕获模块也是感知不到的,所以也不会产生dump文件。比如在开源jsoncpp库中,如果解析的json节点的类型不匹配,会被jsoncpp内部检测到,会触发abort函数的调用,相关代码截图如下:

        再比如WebRTC开源库中在监测到malloc动态申请内存失败后,也会触发abort函数的调用,强行终止进程。估计是因为动态申请内存失败了,相关业务无法正常展开了,程序活着也没意思了,所以就强行终止进程了。相关代码截图如下:

       上述两类问题,我们在实际项目中都遇到过。遇到这类情况,也可以将Widnbg附加到目标进程上进行动态调试,尝试着去复现问题。如果程序调用abort函数,就会触发Windbg中断下来,然后查看函数调用堆栈,通过函数调用堆栈就知道是什么函数调用触发的abort函数的调用的。那为什么调用abort函数会让正在调试的调试器Windbg中断下来呢?因为abort函数内部会raise(产生)一个SIGABRT信号终止异常,如果当前正在调试状态,会让调试器中断下来。abort函数的内部实现源码如下所示:

/***
*void abort() - abort the current program by raising SIGABRT
*
*Purpose:
*   print out an abort message and raise the SIGABRT signal.  If the user
*   hasn't defined an abort handler routine, terminate the program
*   with exit status of 3 without cleaning up.
*
*   Multi-thread version does not raise SIGABRT -- this isn't supported
*   under multi-thread.
*******************************************************************************/
void __cdecl abort (
        void
        )
{
    _PHNDLR sigabrt_act = SIG_DFL;
 
#ifdef _DEBUG
    if (__abort_behavior & _WRITE_ABORT_MSG)
    {
        /* write the abort message */
        _NMSG_WRITE(_RT_ABORT);
    }
#endif  /* _DEBUG */
 
 
    /* Check if the user installed a handler for SIGABRT.
     * We need to read the user handler atomically in the case
     * another thread is aborting while we change the signal
     * handler.
     */
    sigabrt_act = __get_sigabrt();
    if (sigabrt_act != SIG_DFL)
    {
        raise(SIGABRT);
    }
 
    /* If there is no user handler for SIGABRT or if the user
     * handler returns, then exit from the program anyway
     */
    if (__abort_behavior & _CALL_REPORTFAULT)
    {
        _call_reportfault(_CRT_DEBUGGER_ABORT, STATUS_FATAL_APP_EXIT, EXCEPTION_NONCONTINUABLE);
    }
 
    /* If we don't want to call ReportFault, then we call _exit(3), which is the
     * same as invoking the default handler for SIGABRT
     */
    _exit(3);
}

        关于调用abort函数强行终止进程场景的详细说明,可以参见我之前写的文章:

C++程序中执行abort等操作导致没有生成dump文件的问题案例分析https://blog.csdn.net/chenlycly/article/details/129003869

3.5、Visual Studio调试程序时产生异常,但看不到有效的函数调用堆栈,可以尝试使用Windbg进行动态调试

       如果使用Visual Studio调试代码的过程中产生了异常,但在Visual Studio中看不到完整的或者有效的函数调用堆栈,分析不出来问题,比如刚启动调试时就产生异常或者报错,可以尝试着使用Windbg动态调试进行分析。

3.6、程序启动崩溃或失败时

       当程序启动崩溃闪退,会因为某些原因启动失败时,可以尝试使用Windbg启动程序进行动态调试。可能Debug下不好复现,也可能即使复现用Visual Studio调试也很难排查。有可能问题只在客户机器上才会出现,没法到客户机器上使用Visual Studio调试代码。这些场景下的问题,使用Windbg去动态调试分析很方便。

3.7、程序弹出报错提示框时

       程序在运行过程中出现异常,弹出报错提示框,此时进程还在,此刻将Windbg附加到进程上还来的及,可以直接分析。可能问题很难复现,错过了就很难复现了,所以要及时地将Windbg附加到进程上分析。即使一时半会分析不出原因,也可以将进程上下文导出到dump文件中,事后再去分析。

3.8、使用Windbg动态调试目标进程的一般步骤

       将Windbg附加到目标进程上,一旦目标进程产生异常,Windbg就会感知到并中断下来,此时使用kn命令查看发生异常时的函数调用堆栈,然后将函数调用堆栈与源码对应起来分析。一般此时需要根据函数调用堆栈中的模块,去找这些模块的pdb文件,然后再去查看函数调用堆栈,有了pdb文件中的函数及变量符号后,函数调用堆栈中可以看到具体的函数名称和代码行号,甚至可以直接在Windbg中查看函数中局部变量的值或者函数所在类对象的成员变量的值。

       关于Windbg动态调试目标进程的详细步骤及相关要点,可以参见我之前写的文章:

使用Windbg动态调试目标进程的一般步骤及要点详解https://blog.csdn.net/chenlycly/article/details/131029795

4、其他场景说明

       产品发布后,问题是出在Release版本下的。如果使用Windbg静态分析dump文件分析不出来问题时,可以尝试使用Windbg动态调试的。如果使用Windbg分析不出来问题,并且问题是好复现的,则可以尝试使用Visual Studio去调试代码,进行Release下调试。如果问题出在底层的dll模块,则可以使用Visual Studio附加到进程调试的方式去单独调试这个dll模块,附加到进程调试还是很方便的。

       此外,我们有时甚至需要在Visual Studio中查看并单步调试汇编代码。CPU中执行的是一句一句汇编代码(或者叫二进制机器码,两者是等价的),看汇编代码才能看到代码的执行细节。一行C++源码可能对应多行汇编代码,有时我们要知道C++源码为何有问题,可以尝试在Visual Studio中转到汇编代码页面,去单步调试汇编代码,通过调试汇编代码去寻找真相

5、在实际排查问题时,可能要尝试多种排查方法

       在排查问题的过程中,可能需要使用多种排查方法,一个方法排查不出来,就换另一种方法;或者将两个或两个以上的方法结合起来使用,直到定位问题为止!此外,除了使用调试器,还可以考虑同时使用其他的软件分析工具去辅助定位,比如Process Explorer或Process Monitor等。

        之前使用多种方法去排查一个线程栈溢出的问题,相关问题排查实例记录文章如下:

线程栈溢出异常,程序崩溃在汇编代码test dword ptr [eax],eax上的问题排查https://blog.csdn.net/chenlycly/article/details/131743305在上述问题中先后使用了多种排查方法,从Windbg静态分析dump文件,到Windbg动态调试目标进程,再到使用Visual Studio调试源码,最后去单行调试汇编代码。最终调试汇编代码,才找出问题的原因。

6、最后

       本文根据近几年来排查C++软件异常遇到的问题场景和实例,给大家做个详细的总结,希望能给大家提供一个详细的借鉴或参考。此外,分析问题的方法是多样的,不是一成不变的,要根据具体情况去灵活选用一种或多种方法去排查。需要通过大量的实践去积累经验的,经验多了,处理问题的思路就多了,处理问题就更加得心应手了!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/38777.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

animation.css无法显示动画效果问题解决

在使用【微信开发者工具】开发微信小程序时发现无法在开发者工具中展示出动画效果来 但是真机调试中可以正常的显示动画效果 【关于微信小程序中如何使用animation.css,参考微信小程序使用animation.css_THE WHY的博客-CSDN博客 】 同时发现在官网上点击各个动画并…

oled拼接屏在柳州的户外广告中有哪些应用展现?

柳州oled拼接屏是一种高端的显示屏,它采用了OLED技术,具有高亮度、高对比度、高色彩饱和度、高刷新率等优点,能够呈现出更加真实、清晰、细腻的图像效果。 同时,柳州oled拼接屏还具有拼接功能,可以将多个屏幕拼接在一…

Http 接口测试框架

目录 前言: 实际效果 框架的下一步 最新框架图(红色部分未完成) 部分代码 你需要做的 前言: 在进行HTTP接口测试时,使用一个可靠的测试框架可以提高测试效率和质量。HTTP接口测试框架是一种用于自动化测试HTTP接…

Appium-Python-Client 源码剖析 (一) driver 的元素查找方法

目录 前言 源码版本:0.9 结构图: mobileby.py appium 的 webdriver.py selenium 的 webdriver.py seleniumdriver appiumdriver 前言 Appium-Python-Client是一个用于Python语言的Appium客户端库,它提供了丰富的API和功能,用于编写和…

FFmpeg 命令行实现居中高清上下模糊播放效果

FFmpeg 命令行实现居中高清上下模糊播放效果。 1、16:9 的横屏原视频,以 16:9 竖屏上下模糊播放 以该效果播放视频的命令如下: ffplay -i horizontal_test_video_169.mp4 -vf \ "split[a][b]; \ [a]crop(ih/16*9):ih,scaleiw/10:-1,gblursigma5…

周考一之重做

输入一个学生的成绩,如果学习成绩>90分的同学用A表示,60-89分之间用B表示,60分以下的用C表示(10) public static void main(String[] args){ Scanner scanner new Scanner(System.in); System.out.println(“请输入学生成绩:…

短视频seo抖音矩阵号系统源码开发搭建分享

我们自主研发的短视频矩阵系统源码,技术研发的独立核心算法的视频内容管理和展示功能。无需额外的流量接口费用和复杂的配置,轻松地创建和管理短视频内容,短视频矩阵源码是指将抖音平台上的视频资源进行筛选、排序等操作,进而提升…

Python应用实例(二)数据可视化(一)

数据可视化(一) 1.安装Matplotlib2.绘制简单的折线图2.1 修改标签文字和线条粗细2.2 矫正图形2.3 使用内置样式2.4 使用scatter()绘制散点图并设置样式2.5 使用scatter()绘制一系列点2.6 自动计算数据2.7 自定义颜色2.8 使用颜色映射2.9 自动保存图表 数…

一文详解 requests 库中 json 参数和 data 参数的用法

在requests库当中,requests请求方法,当发送post/put/delete等带有请求体的请求时,有json和data2个参数可选。 众所周知,http请求的请求体格式主要有以下4种: application/jsonapplicaiton/x-www-from-urlencodedmult…

国内流行的数据可视化软件工具

在信息爆炸的时代,越来越多的数据堆积如山。但是,这些密集的数据没有重点且可读性较差。因此,我们需要数据可视化来帮助数据易于理解和接受。相比之下,可视化更直观、更有意义,使用适当的数据可视化工具来可视化数据非…

接下来讲一讲Vue的数据代理

首先讲一下原生js的数据代理 原生的 Object.defineProperty() let aa wewewlet person {name: "王李斌",age: 12} Object.defineProperty(person, "address", {// value: 14, 给字段设置值//enumerable:true, 设置动态设置的字段为可以遍历/…

C# MVC 多图片上传预览

一.效果图: 开发框架:MVC,Layui 列表主界面这里就不展示了,可以去看看这篇文章:Layui项目实战,这里讲的是“上传Banner”界面功能: 其中包括,多文件上传,预览&#xff0c…

MySQL数据库,冷备份,热备份,温备份,物理备份,逻辑备份

🧊冷备份 MySQL数据库冷备份的优点包括: 快速备份:冷备份只需要拷贝文件,因此备份速度非常快,不会影响数据库的读写操作。易于归档和恢复:冷备份可以通过简单拷贝文件进行归档和恢复,而且可以…

配置Hadoop_0

配置Hadoop_0 1配置Hadoop100模板虚拟机1.1配置Hadoop100模板虚拟机硬件1.2配置Hadoop100模板虚拟机软件1.3配置Hadoop100模板虚拟机IP地址1.4配置Hadoop100模板虚拟机主机名称/主机名称映射1.5配置Hadoop100模板虚拟机远程操作工具 1配置Hadoop100模板虚拟机 Hadoop100 内存…

信音电子在创业板IPO:募资约9亿元,预计上半年收入约4.3亿元

7月17日,信音电子(中国)股份有限公司(下称“信音电子”,SZ:301329)在深圳证券交易所创业板上市。本次上市,信音电子的发行价为21.00元/股,发行数量为为4300万股,募资总额…

uniapp 小程序 picker 日期时间段选择(精确到年月日时分+周几)

效果图&#xff1a; picker时间选择器 精确到年月日时分周几 需要引入moment.js&#xff0c;有可能引入后在项目内会报错&#xff0c;可以考虑把选择日期作为一个组件引入 1、timepage.vue组件封装 <template><view><picker mode"multiSelector" :va…

什么是计算机蠕虫?

计算机蠕虫诞生的背景 计算机蠕虫的诞生与计算机网络的发展密切相关。20世纪60年代末和70年代初&#xff0c;互联网还处于早期阶段&#xff0c;存在着相对较少的计算机和网络连接。然而&#xff0c;随着计算机技术的进步和互联网的普及&#xff0c;计算机网络得以迅速扩张&…

【产品设计】通用后台管理系统需求及原型设计

后台管理系统&#xff0c;会根据不同公司、不同业务的要求做出改变。 网上很多系统的参考多数为业务中台&#xff0c;过于带有业务色彩。做过三四个后台管理系统&#xff0c;从中总结了一个通用的功能和需求设计模版&#xff0c;供大家参考。本文适用于0-2岁的产品经理做基础功…

J2EEJSP自定义标签库01out标签if标签

目录 一.什么是标签 二.JSP自定义标签库 2.1 JSP标签库是什么 2.2 处理流程 2.3 如何自定义标签 2.4 标签类型 三.开发示例 3.1 out标签 1.创建助手类 2.编写tld&#xff08;标签库的描述&#xff09;文件&#xff0c;&#xff08;必须放在WEB-INF目录或其目录下&a…

基于深度学习的高精度安全帽背心检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度安全帽背心检测识别系统可用于日常生活中或野外来检测与定位安全帽背心目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的安全帽背心目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用…