使用Windbg动态调试目标程序去分析异常的两实战案例分享

目录

1、前言

2、案例1:程序退出时弹出报错提示框

2.1、问题说明

2.2、到系统应用程序日志中看系统有没有自动生成dump文件

2.3、将Windbg附加到目标程序上进行动态调试

3、案例2:程序在运行过程中弹出ASSERT断言提示框

3.1、问题说明

3.2、将Windbg附加到进程上调试

3.3、Windbg是如何找到pdb文件的?

4、使用Windbg静态分析dump文件以及动态调试目标进程的一般步骤

5、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C++软件分析工具从入门到精通案例集锦(专栏文章正在更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html开源组件及数据库技术(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html       有时我们需要将Windbg附加到目标程序进程上动态调试,去排查软件运行过程中出现的异常。今天以最近项目中遇到的两个问题实例,给大家详细讲解一下使用Windbg动态调试去分析问题的完整过程,以供大家借鉴或参考。

1、前言

       Windbg是微软提供的一款强大的调试器工具,是分析C++软件异常问题的必备利器。使用Windbg分析软件异常主要有两种方式,一种是使用Windbg静态分析dump文件,一种是将Windbg附加到目标进程上进行动态调试。在日常工作中,主要使用静态分析dump文件的方式,但在少部分场景下可能没有生成dump文件或者生成的dump不足以排查出问题,这就需要使用Windbg进行动态调试了。

       本文主要来讲述使用Windbg动态调试的相关主题内容。在以往排查的多个问题实例的基础上,对需要使用Windbg进行动态调试的场景进行了总结,主要有以下几种场景:(主要看没有生成dump文件的场景)

1)程序发生死循环或死锁时
程序并没有发生异常闪退或崩溃,仅仅是发生死循环或死锁,程序还在持续运行。因为没有产生异常,程序中安装的异常捕获模块是无法感知到的,所以无法生成dump文件。分析这类问题,需要将Windbg附加到出问题的进程上进行动态调试,去查看线程的函数调用堆栈等信息。
2)程序发生异常,但异常捕获模块没有捕获到
程序中虽然安装了异常捕获模块,但异常捕获模块只能捕获到大部分异常崩溃,还有一小部分异常是感知不到的,感知不到的情况下是没法生成dump文件的。比如程序运行过程中发生的一些闪退问题,异常捕获模块没有感知到,可以尝试使用Windbg去动态调试,去尝试复现问题。Windbg在动态调试时,一旦程序发生异常,Windbg会第一时间感知到并中断下来,就可以去查看函数调用堆栈等信息去分析了。
3)异常捕获模块感知到了异常,但导出dump文件时产生了二次崩溃,dump文件生成失败
异常捕获模块感知到了异常,但在导出dump文件时异常捕获模块产生了崩溃(即产生了二次崩溃),dump文件生成失败。

4)程序运行过程中检测到不正常,直接调用abort函数强制结束进程,导致程序闪退
程序闪退,主要有两种原因,一种是运行过程遇到了异常直接崩溃退出,一种是程序中监测到不正场直接调用abort直接将进程终止。

代码中根据变量的值或者函数的返回值检测到不正常,可能会因为程序相关的业务没法正常执行认为程序没有继续存活下去的必要了,直接调用abort函数强行将当前进程终止掉,程序直接闪退。这种情况下的闪退,并不是因为执行汇编代码产生了异常崩溃,而是直接主动调用abort函数导致的,所以异常捕获模块感知不到,也就无法生成dump文件。
对于这种调用abort导致程序闪退的情况,可以将Windbg附加到进程上动态调试,abort函数内部会发出一个特殊的异常信号让调试器Windbg中断下来,这样Windbg就能感知到,通过查看此时的函数调用堆栈进行分析了。
5)用IDE调试程序时产生异常,但看不到有效的函数调用堆栈,可以尝试使用Windbg进行动态调试
有时我们在用IDE调试代码遇到异常崩溃时,可能看不到有效的函数调用堆栈(比如只能看到一两行函数调用记录,或者只能看到底层模块的模块名,看不到具体的函数),可以尝试使用Windbg动态调试去查看到问题发生时的完整函数调用堆栈。
6)程序启动崩溃或失败时
程序启动崩溃或启动失败时,可以尝试用Windbg去启动程序,程序发生异常时Windbg就会中断下来,就可以进行分析了。
7)程序弹出报错提示框时
程序弹出报错提示框,此时进程还在的,可以将Windbg附加到进程上进行分析。当然也可以直接打开Windows任务管理器直接导出dump文件供事后分析。

       关于使用Windbg动态调试场景的详细说明及相关的问题案例,在此就不再赘述了,感兴趣的,可以查看我之前写的长篇文章:

使用 Windbg 分析软件异常时的诸多细节与技巧总结icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/135517926        最近项目中遇到了两个使用Windbg动态调试分析问题的实例,在这里给大家大概地分享一下。


         在这里,给大家重点推荐一下我的几个热门畅销专栏:

专栏1:(该专栏订阅量接近400个,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!)

C++软件调试与异常排查从入门到精通系列文章汇总icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931

本专栏根据近几年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的实战问题分析实例,带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!

专栏中的文章均是通过项目实战总结出来的(通过项目实战积累了大量的异常排查素材和案例),有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!

专栏2: 

C/C++基础与进阶(专栏文章,持续更新中...)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html

以多年的开发实战为基础,总结并讲解一些的C/C++基础与进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域的多个方面的内容,同时给出C/C++及网络方面的常见笔试面试题,并详细讲述Visual Studio常用调试手段与技巧!

专栏3: 

开源组件及数据库技术icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html

以多年的开发实战为基础,分享一些开源组件及数据库技术!


2、案例1:程序退出时弹出报错提示框

2.1、问题说明

       测试人员反馈,在其Win7的电脑上关闭我们的软件(退出软件)时,每次都会弹出应用程序已经停止运行的提示,如下所示:

并且这个问题在他的这台Win7电脑上是必现的。对比了一下,在Win10的电脑上运行程序,并没有这个问题,即不同的系统中表现是有差异的。但这个问题在Win7的系统中是必现的,会严重影响用户的体验,必须要解决掉。

       看到这个提示框,初步怀疑可能是程序退出时发生了异常(崩溃),所以系统弹出这个异常提示框。

2.2、到系统应用程序日志中看系统有没有自动生成dump文件

       既然怀疑是程序退出时产生了崩溃,所以尝试到系统应用程序日志中看看有没有程序的异常记录以及自动生成dump文件。具体的操作步骤是,右键点击“此电脑”,在弹出的右键菜单中点击“管理”菜单项,如下所示:

在打开的计算机管理窗口中,在路径 系统工具->事件查看器->Windows 日志->应用程序中点击“应用程序”节点:

右侧就会显示系统记录的应用程序事件。确实看到了程序发生崩溃的记录,但并没有生成dump文件的记录。如果系统自动生成了dump文件,则会在记录文字中给出dump文件的完整路径等信息。

       之前在客户那边遇到的一个程序崩溃的问题,没有生成dump文件,将Windbg直接挂载到目标程序进程上调试运行,也没感知到异常。后来在操作系统的应用程序日志中找到了程序的异常记录,并查看到了系统自动生成的dump文件路径,后来正是用这个dump文件定位了问题。之前我在文章中对这个问题进行了记录与总结,可以查看对应的文章:

使用Windbg分析从系统应用程序日志中找到的系统自动生成的dump文件去排查问题icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/132024253

2.3、将Windbg附加到目标程序上进行动态调试

       这个问题在测试同事的Win7电脑上是必现的,所以很适合使用Windbg动态调试去分析排查。

       于是重新启动程序,然后将Windbg附加到程序进程上(附加到进程上时会自动中断下来,输入g命令,让程序继续运行),然后退出程序复现问题。程序退出时果然发生了异常,Windbg感知到了并中断了下来,于是输入kn命令查看此时的函数调用堆栈:

       因为没有加载pdb符号文件,所以堆栈中看不到具体的函数名和行号,只能看到相关的模块名。于是使用lm命令查看堆栈中的模块的时间戳,找到对应时间点的pdb文件,然后将pdb文件的路径设置到Windbg中,然后再使用kn命令查看函数调用堆栈,如下所示:

堆栈中看到了具体的函数名和代码行号。堆栈中出问题的模块是协议开发组维护的,于是将函数调用堆栈等信息发给协议组的同事,让他们对照着C++源码去排查。后来他们排查出了原因,是对一块堆内存释放了两次,在第二次释放时产生了崩溃

3、案例2:程序在运行过程中弹出ASSERT断言提示框

3.1、问题说明

       为了排查某个问题,直接运行Debug版本的exe程序(不是使用Visual Studio调试运行程序),在执行某个操作时,弹出了如下的ASSERT断言提示框:

即代码中出现了断言错误,可能是代码运行过程中遇到了异常的变量值。

       这种断言其实排查起来很简单,如果直接使用Visual Studio调试运行的话,直接点击重试按钮,就会中断在发生异常的地方,然后查看函数调用堆栈就能很快定位问题。当前是直接运行Debug版本的exe程序,不是使用Visual Studio调试的,此时进程和问题都还在的,可以将Windbg附加到进程上,然后的点击ASSERT断言对话框中的重试按钮,然后Windbg就会中断下来。

3.2、将Windbg附加到进程上调试

       将Windbg附加到弹出ASSERT断言的进程上,然后点击ASSERT断言提示框中的重试按钮,然后Windbg直接跳转到如下图的STL vector列表的数组下标操作符重载函数处:

vector subscript out of range,vector下标超过范围了。于是输入kn命令查看此时的函数调用堆栈:

堆栈中的第一行位于STL源码中,第二条位于我们的业务库中,所以要看第二条记录中的函数。

细心的朋友可能会有疑惑,我们并没有找pdb文件,为啥输出的函数调用堆栈信息中能看到具体的函数名和行号呢?这个问题接下来会详细讲!

根据第二条记录中显示的函数名和行号,找到源码中的位置,如下:

代码中使用数组下标的方式访问了vector列表vtUserDomainlist中的第一个元素,按照上面的指示,下标超过范围了。

       读第一个元素时就超过范围了,说明列表中没有元素,第一个位置的元素是不存在的。在访问列表元素时没有判断这个列表是否为空,就使用下标直接访问第1个元素了!

3.3、Windbg是如何找到pdb文件的?

       上面我们提到了,有人可能会有疑问,我们并没有去找pdb文件,为啥Windbg显示的函数调用堆栈中能显示出具体的函数名和行号呢?那是因为编译代码时生成的二进制文件中会自动写入默认的pdb文件路径(就是编译时生成的pdb文件路径)。以一个测试程序TestDlg.exe为例,我们直接使用Notepad++、记事本或者UltraEdit打开exe文件(可以先启动这些工具,然后将exe文件拖入到这些工具中即可以查看),然后以pdb关键字搜索,就能找到编译时写入的pdb文件的绝对路径,如下:

pdb文件的绝对路径为:

D:\VSProjects\TestDlg\Debug\TestDlg.pdb

而在本问题中,运行的Debug版本程序就是我机器上编译的程序也是在我机器上运行的,通过写入的pdb文件的绝对路径,在我机器上能找到这个pdb文件,所以Windbg就自动加载了,所以堆栈中能看到详细的函数名及代码行号了。

       如果将我机器上编译的exe主程序拷贝到其他机器上运行,在弹出上述的ASSERT断言提示框时将Windbg附加上去,在运行机器上就找不到pdb文件了,也就看不到详细的堆栈信息了。

4、使用Windbg静态分析dump文件以及动态调试目标进程的一般步骤

       为了让大家能够顺利地将Windbg用起来,有所参考,我之前详细总结了使用Windbg静态分析dump文件的一般步骤以及将Windbg附加到目标进程上进行动态调试的一般步骤,分别详细介绍了分析问题的详细步骤,并以具体的问题实例进行详细地演示,很有指导意义。

       使用Windbg静态分析dump文件的一般步骤,可以参考我之前写的文章:

使用Windbg静态分析dump文件的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/130873143      将Windbg附加到目标进程上进行动态调试的一般步骤,可以参考我之前写的文章:

使用Windbg动态调试目标进程的一般步骤及要点详解icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131029795

5、最后

       本文给出了两个将Windbg附加到程序进程上动态调试分析的实例,虽然不复杂,但都有一定的代表性,可以给大家提供一定的借鉴或参考。

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

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

相关文章

【Python笔记-设计模式】组合模式

一、说明 组合模式是一种结构型设计模式, 你可以使用它将对象组合成树状结构, 并且能像使用独立对象一样使用它们。 (一) 解决问题 处理树形结构:可以很好地处理树形结构的数据,使得用户可以统一对待单个对象和对象组合。统一接…

Java零基础 - 逻辑运算符

哈喽,各位小伙伴们,你们好呀,我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。 我是一名后…

第13讲实现自定义logout处理

默认logout请求实现是有状态的,返回到login请求页面;我们现在是前后端分离处理,所以需要自定义实现logout 新建JwtLogoutSuccessHandler /*** 自定义Logout处理* author java1234_小锋 (公众号:java1234)…

Python算法题集_岛屿数量

Python算法题集_岛屿数量 题200:岛屿数量1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【双层循环递归】2) 改进版一【双层循环迭代】3) 改进版二【双层循环迭代高速双向队列】4) 改进版三【双层循环并查集】 4. 最优算法5. 相关资…

五、分类算法 总结

代码: from sklearn.datasets import load_iris, fetch_20newsgroups from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.naive_bayes import MultinomialNB from s…

基于JAVA的班级考勤管理系统 开源项目

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统基础支持模块2.2 班级学生教师支持模块2.3 考勤签到管理2.4 学生请假管理 三、系统设计3.1 功能设计3.1.1 系统基础支持模块3.1.2 班级学生教师档案模块3.1.3 考勤签到管理模块3.1.4 学生请假管理模块 3.2 数据库设…

Kubernetes二进制搭建

目录 1.操作系统初始化配置(所有节点同此操作) 2.部署etcd集群 etcd概述 准备签发证书环境 在master01节点上操作(192.168.88.22) 在两个node节点上操作 总结: 3.部署docker引擎 4.部署Master组件 总结&…

学习大数据所需的java基础(5)

文章目录 集合框架Collection接口迭代器迭代器基本使用迭代器底层原理并发修改异常 数据结构栈队列数组链表 List接口底层源码分析 LinkList集合LinkedList底层成员解释说明LinkedList中get方法的源码分析LinkedList中add方法的源码分析 增强for增强for的介绍以及基本使用发2.使…

五种多目标优化算法(MOJS、MOGWO、NSWOA、MOPSO、NSGA2)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 1.1MOJS 1.2MOGWO 1.3NSWOA 1.4MOPSO 1.5NSGA2 二、5种多目标优化算法性能对比 为了测试5种算法的性能将其求解9个多目标测试函数(zdt1、zdt2 、zdt3、 zdt4、 zdt6 、Schaffer、 Kursawe 、Viennet2、 Viennet3)&#xff0…

【虚拟仿真】Unity3D中实现3DUI,并且实现Button、InputField、Toggle等事件绑定

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 最近在项目中需要用到3DUI的展示,之前一般会用TextMeshPro进行展示: 但是,后面又需要添加按钮、Toggle等…

《nvm 安装》nodejs 版本管理工具

一.前言 如果先于 nvm 安装了 node,一定要先卸载! 两种卸载方式: 方式一 控制面板 -> 程序和功能 -> nodejs 删除 方式二 下载的 node 安装包有卸载选项 二. 安装 nvm 下载地址 中找到对应的安装包,我本机使用 window…

Autosar-Mcal配置详解-GPT

3.3.1添加GPT模块 方法与添加Dio相似,可参加Dio模块添加方法。 3.3.2 创建、配置GPT通道 1)根据需求创建GPT通道(即创建几个定时器) 本例中创建了3个定时器通道:1ms,100us,OsTimer。 2)配置GPT通道 配置T…

进度条小程序

文章目录 铺垫回车换行缓冲区概述强制冲刷缓冲区 简单实现倒计时功能进度条小程序版本一实例代码效果展示分析 版本二 铺垫 回车换行 回车和换行是两个独立的动作 回车是将光标移动到当前行的最开始(最左侧) 换行是竖直向下平移一行 在C语言中&…

图的遍历-----深度优先遍历(dfs),广度优先遍历(bfs)【java详解】

目录 简单介绍:什么是深度、广度优先遍历? 深度优先搜索(DFS,Depth First Search): 大致图解: 广度优先搜索(BFS,Breadth First Search): 大致图…

数据结构·顺序表

1数据结构简介 学习数据结构与算法之前,一般是先学数据结构,方便之后学习算法,那么数据结构拆开介绍,就是数据 和 结构,数据,生活中到处都是,结构,就是数据存储的方式,即…

分布式系统一致性与共识算法

分布式系统的一致性是指从系统外部读取系统内部的数据时,在一定约束条件下相同,即数据(元数据,日志数据等等)变动在系统内部各节点应该是一致的。 一致性模型分为如下几种: ① 强一致性 所有用户在任意时…

git使用过的命令记录

目录 git add .git commit --amendgit push -f origin HEAD:mastergit checkout .git stash想把某个pr的修改应用到本地git pull 将远程仓库的最新代码更新到本地git 撤销,放弃本地修改参考文档 git add . 将本地修改提交到暂存区 git commit --amend 如果本地有…

MySQL 8.0.36 WorkBench安装

一、下载安装包 百度网盘链接:点击此处下载安装文件 提取码:hhwz 二、安装,跟着图片来 选择Custom,然后点Next 顺着左边框每一项的加号打开到每一个项的最底层,点击选中最底层的项目,再点击传过去右边的绿色箭头&a…

MATLAB 导出可编辑的eps格式图像

任务描述:部分期刊要求提交可编辑的eps格式图像,方便美工编辑对图像进行美化 我试了直接print或者在figure窗口导出,发现导出的文件放到Adobe AI中并不能编辑,经Google找到解决办法: %EPS exportgraphics(gcf,myVect…

FFmpeg的HEVC解码器源代码学习笔记-1

一直想写一个HEVC的码流解析工具,看了雷神264码流解析工具,本来想尝试模仿写一个相似的265码流分析工具,但是发现265的解码过程和结构体和264的不太一样,很多结构体并没有完全暴露出来,没有想到很好的方法获得量化参数…