dump文件类型与dump文件生成方法详解

news2024/11/28 8:36:55

目录

1、概述

2、dump文件的分类

2.1、dump按大小分类

2.2、查看dump文件中函数调用堆栈中变量的值

3、调用SetUnhandledExceptionFilter设置异常处理回调函数,然后调用MiniDumpWriteDump生成dump文件

4、使用Google开源库CrashRpt捕获异常,并自动生成dump文件

4.1、开源库CrashRpt捕获异常的原理及缺陷

4.2、使用微软detours技术对CrashRpt进行改进

5、通过Windows任务管理器导出目标进程的dump文件

6、从正在动态调试的Windbg中导出dump文件

6.1、有时需要将Windbg动态调试目标进程

6.2、使用.dump命令导出dump文件

6.3、将Windbg附加到目标进程上的方法

7、最后


VC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=M85Bhttps://blog.csdn.net/chenlycly/article/details/124272585C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)icon-default.png?t=M85Bhttps://blog.csdn.net/chenlycly/article/details/125529931        我们在处理C++软件运行异常崩溃问题时,主要是通过事后分析dump文件去排查的。这就需要程序能感知到异常崩溃并自动生成包含异常上下文信息的dump文件。除了程序自动生成dump文件外,有时我们可能需要通过其他途径去产生dump文件。今天我们就来详细地讲讲dump文件的相关内容。

1、概述

       我们在处理C++软件运行异常崩溃问题时,主要是通过事后分析dump文件去排查的,能否在异常发生时自动生成dump文件就显得尤为关键了。

       对于Windows系统,一般我们会在程序中安装异常捕获模块,去自动捕获软件异常,即当软件发生异常时,异常莫捕获模块能感知到,并自动生成包含异常上下文的dump文件。对于Linux系统,则会自动生成包含异常上下文的coredump文件,我们可以配置生成的文件名称。本文主要讲述Windows系统中dump文件的相关内容。

       Windows程序中安装的异常捕获模块主要用来捕获发生异常崩溃的场景,有些在运行过程中发生的非崩溃异常,异常捕获模块可能感知不到,也就无法生成dump文件。比如程序发生了死循环、死锁等非崩溃的运行异常时,异常捕获模块是感知不到的,这时候如果需要导出dump文件,就需要使用其他手段了。

       此外,异常捕获模块只能捕获大部分情况下的异常崩溃,有少部分场景是捕获不到的,这时候可能就需要使用Windbg(WIndows平台)或者gdb(Linux平台)调试器去动态调试了,如果调试器在运行过程中捕获到了异常,会中断下来,可以通过命令手动将dump文件导出来。

       在Windows平台上,产生dump文件的方式主要有三种:

1)异常捕获模块感知到异常时自动生成dump文件;
2)通过Windows任务管理器导出dump文件;
3)用Windbg动态调试时用Windbg命令导出dump文件。

2、dump文件的分类

2.1、dump按大小分类

       根据生成的dump文件的大小,可以将dump文件分两类,一类是很小的mini dump文件,一类是很大的全dump文件。软件的异常捕获模块在感知到异常时自动生成的dump文件,会自动保存在指定的目录中,可能会因为崩溃多次生成多个dump文件,会占用用户很多的磁盘空间,所以对于自动生成的dump文件,我们一般生成只包含部分信息的mini dump文件,mini dump文件的大小一般在几MB左右。

       异常捕获模块是通过调用API函数MiniDumpWriteDump生成dump文件的,那如何去控制生成的dump文件的大小的呢?是通过设置调用MiniDumpWriteDump函数时传入的参数,去控制dump文件大小的。

       从Windows任务管理器中导出的dump文件、从动态调试的Windbg中使用.dump命令导出的dump文件,一般都是包含进程完整信息的全dump文件。全dump文件则比较大,一般都有几百MB,甚至有1GB以上。因为全dump文件中保存了进程的所有内存信息,所以全dump文件的大小,接近对应进程占用的总虚拟内存的大小,所以文件会比较大。

2.2、查看dump文件中函数调用堆栈中变量的值

       有时我们需要去查看Windbg中线程函数调用堆栈中某个函数中局部变量或者类对象的成员变量值,去辅助分析问题,变量的值可能是关键线索,如下:

但能不能查看到目标变量的值(变量内存中的值),取决于dump文件的类型。对于mini dump文件,只能看到部分变量的值,很多变量的值是看到不到的,能否看到目标变量的值是要看运气的。而全dump文件,则是包含了进程所有内存的信息,是可以看到所有变量的值的。

       通过查看目标变量的值去定位问题的方法,我们在项目中已经用过多次了,比如下面的三篇文章:
通过查看Windbg中的变量值去定位C++软件异常问题icon-default.png?t=M85Bhttps://blog.csdn.net/chenlycly/article/details/125731044通过查看windbg中变量值去定位C++软件异常的又一典型案例分享 icon-default.png?t=M85Bhttps://blog.csdn.net/chenlycly/article/details/125793532

通过查看Windbg中汇编指令及内存中的值去定位软件崩溃问题 icon-default.png?t=M85Bhttps://blog.csdn.net/chenlycly/article/details/127033741

3、调用SetUnhandledExceptionFilter设置异常处理回调函数,然后调用MiniDumpWriteDump生成dump文件

       程序中可以调用系统API函数SetUnhandledExceptionFilter去设置异常处理回调函数,当发生异常时系统会回调这个函数,这样程序就能感知到,然后在回调函数中调用系统API函数MiniDumpWriteDump就可以生成dump文件了。相关代码如下所示:

// unhandled exception callback set with SetUnhandledExceptionFilter()
static LONG WINAPI SEHUnhandledExceptionFilter(EXCEPTION_POINTERS* pExInfo)
{
        HANDLE hDumpFile;
        hDumpFile = CreateFile(sFile, GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

        MINIDUMP_EXCEPTION_INFORMATION ExpParam;
        ExpParam.ThreadId = GetCurrentThreadId();
        ExpParam.ExceptionPointers = pExceptionPointers;
        ExpParam.ClientPointers = TRUE;

        MINIDUMP_TYPE MiniDumpWithDataSegs = (MINIDUMP_TYPE)(MiniDumpNormal
                | MiniDumpWithHandleData
                | MiniDumpWithUnloadedModules
                | MiniDumpWithIndirectlyReferencedMemory
                | MiniDumpScanMemory
                | MiniDumpWithProcessThreadData
                | MiniDumpWithThreadInfo);

        BOOL bMiniDumpSuccessful = FALSE;
        bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);
        
    return EXCEPTION_EXECUTE_HANDLER;
}

// Install structured exception handler
LPTOP_LEVEL_EXCEPTION_FILTER pOldExceptionFilter = SetUnhandledExceptionFilter( SEHUnhandledExceptionFilter );

       但SetUnhandledExceptionFilter只对调用其的线程有作用,即将异常回调函数设置给当前的线程,其他线程的异常需要另外设置回调函数。软件从上层到底层一般会包含多个dll模块,模板中可能创建了线程,整个进程中会包含多个线程,没法直接给所有线程设置异常回调的,所以这种方法不够通用,需要改进。

4、使用Google开源库CrashRpt捕获异常,并自动生成dump文件

       可以使用Google的C++开源异常捕获库CrashRpt,将CrashRpt引入到项目中,作为程序的异常捕获库。

4.1、开源库CrashRpt捕获异常的原理及缺陷

        开源的CrashRpt异常捕获库是动态地将已加载的库的导入表中创建线程的API函数CreateThread HOOK成自定义的MyCreateThread函数(不管调用哪个创建线程的接口,最终都会走到CreateThread API接口中的),这样就会走进HOOK函数MyCreateThread,在该函数中就额可以调用系统API函数SetUnhandledExceptionFilter给每个创建的线程挂载异常处理回调函数了。

       但CrashRpt这种处理机制是有缺陷的,没法给软件所有模块的所有线程都挂载上异常处理回调函数的,只能给在CrashRpt库之前加载的dll库挂载异常处理回调函数,在CrashRpt之后加载的库就没法去HOOK了,这样就会导致没进行HOOK操作的那些dll库中发生的异常都捕获不到了。在exe启动时,会把所有依赖的库加载到进程空间中,我们没法控制所有的库都在CrashRpt库之前被加载的,这也导致了有些模块的异常崩溃CrashRpt是捕获不到的。

4.2、使用微软detours技术对CrashRpt进行改进

       后来我们针对上述缺陷,对CrashRpt库进行了改进,使用微软开源的detours项目中的代码将windows系统库中的UnhandledExceptionFilter接口给HOOK掉。因为基本所有的异常都会最终进入到该系统函数中,我们将UnhandledExceptionFilter接口HOOK成我们自定义的接口,我们就能在该自定义的接口中感知到几乎所有的异常了。感知到异常后,就可以生成包含异常上下文的dump文件了。这样就能很好的解决老版本CrashRpt不能hook后加载的库的问题,新版本的CrashRpt就可以作用于当前进程的所有模块了,基本可以捕获到进程的所有异常了。

       当然改进后的CrashRpt也不是所有的异常都能捕获到,但可以捕获大概90%以上的异常。对于捕获不到的场景,可以尝试将Windbg调试器挂载到目标进程上,看看动态调试时能否感知到。对于将Windbg挂载到目标进程上进行动态调试的相关说明,下面会详细地讲到。

5、通过Windows任务管理器导出目标进程的dump文件

        当程序运行弹出报错提示框或者程序卡死时,程序的进程还在的(进程还没退出),可以到Windows任务管理器中找到该进程,将包含进程上下文信息的dump文件导出来。具体的操作步骤是,打开Windows任务管理器找到目标进程,右键点击该进程,在弹出的右键菜单中点击“创建转储文件”菜单项,如下所示:

即可完成进程dump文件的导出了。

       当然出现这类问题时,我们可以直接将Windbg调试器直接挂载到出问题的进程上,去直接查看进程上下文,查看线程的函数调用堆栈。但问题可能出现在客户的机器上(不能占用客户时间或者客户因为安全涉密问题没法进行远程操作),或者将Windbg挂到目标进程上后一时半会分析不出问题,这些时候就可以选择从Windows任务管理器中导出目标进程的dump文件。

       这种导出dump文件的方式我们会时不时地使用到,比如前段时间帮兄弟项目组排查他们软件死锁问题时,当时的dump文件就是从任务管理器中导出的。

6、从正在动态调试的Windbg中导出dump文件

6.1、有时需要将Windbg动态调试目标进程

       有少数异常崩溃,程序中安装的异常捕获模板是捕获不到的,当遇到这类问题时,可以尝试将Windbg附加到目标进程上调试运行,看看Windbg在异常发生时能否感知到异常。当Windbg感知到异常时,就会中断下来,这样我们就可以进行分析及其他操作了。

       对于好复现的崩溃,这种方法处理很快;对于很难复现的问题,只能将Windbg附加到进程上和进程一起运行,直到出现异常为止(遇到这类难复现的问题时,我们都是让测试同事挂着Windbg和程序一起跑的)。

       有人可能会说,如果Windbg在动态调试的过程中捕获到了异常直接分析就好了,为啥还要从Windbg导出dump文件呢?这不是多此一举吗?其实是这样的,有的问题可能没法很快分析出来,我们不能长时间占用别人的电脑,别人也有很多活要干的,那么这时就可以从Windbg中导出dump文件,事后将dump取来进行详细的分析。

6.2、使用.dump命令导出dump文件

       从Windbg中导出dump文件的命令如下:

 .dump /ma D:\20221118.dmp

其中.dump是命令名,/ma是参数,D:\20221118.dmp是存放dump文件的完整路径,Windbg中的运行效果如下:

参数/ma是导出包含所有信息的dump文件,即全dump文件。至于.dump命令还支持哪些命令,可以到Windbg的帮助文档中查看:

       前段时间兄弟项目组遇到的一个软件崩溃问题就是通过Windbg动态调试(附加到目标进程上)捕获到的。当时测试同事找到了崩溃复现的方法,很容易复现,但软件中安装的异常捕获模块就是捕获不到,后来让测试同事手动将Windbg附加到目标进程后复现崩溃,Windbg捕获到了异常,手动使用命令将dump文件导了出来。

6.3、将Windbg附加到目标进程上的方法

        将Windbg附加到目标进程上进行动态调试有两种方式:

1)直接使用Windbg打开目标exe程序,即使用Windbg启动目标进程;
2)将Windbg附加到已经运行的进程上。

       具体使用哪种方式,要看具体的场景。如果问题出在程序启动的过程中,则需要选择使用Windbg启动程序;如果是运行过程中出现的问题,则两种方式都可以使用。

7、最后

       本文结合多年的项目实战经验,详细讲述了dump文件的分类与dump文件生成方法,希望这些内容能对相关的朋友们提供一些借鉴和参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内网域环境搭建教程

搭建环境 win2012(DC):10.10.10.161 win2008 : 10.10.10.160 win7 : 10.10.10.157 环境配置 WIN2012域控机配置 将域控机配置成静态IP 更改计算机名 方便之后识别 安装域控制器和DNS服务 重启——安装 升级配置为域控制器 配置根域名为…

TOUGH2系列建模方法及在CO2地质封存、水文地球化学、地热、地下水污染等领域中的实践技术应用

TOUGH2系列软件是由美国劳伦斯伯克利实验室开发的,旨在解决非饱和带中地下水、热运移的通用模拟软件。和传统地下水模拟软件Feflow和Modflow不同,TOUGH2系列软件采用模块化设计和有限积分差网格剖分方法,通过配合不同EOS模块,软件…

[Geek Challenge 2022] crypto部分

这个比赛是一个网友让我看看的,这个比赛很有意思,crypto题全是百度网盘,pwn题全是谷歌网盘,这样我这pwn题就基本over了。还好这些crypto都不怎么难,都答出来了。最后成绩到10名了。 w_or_m? 第1个50分的题&#xff…

股票level2接口-API程序化文档说明

股票level2接口-API程序化文档说明,新手在API程序化上跟随老手进行。这是一种新的模式,适合那些想要而不知道如何投资正确项目的人。 股票level2接口TickRecord 逐笔说明(部分) 现在网络发展,使用组也很常见&#xff…

Html代替<iframe>标签的三种方法<object>, <embed>和<video>

背景 某平台对iframe标签做了些许限制但是前端代码有bug导致提交不了代码, 最开始想着是不是能够在本地替换js文件从而绕过bug 简单搜索后找到了 chrome浏览器F12调式,修改替换js文件这篇博客, 简单试了下虽然能替换成功但是效果不理想, 改不了平台就只能适应平台了…

mysql日志持久化机制

文章目录前言binlog的持久化机制redo log 的持久化机制组提交MySQL的io瓶颈性能优化总结前言 之前的文章介绍过,mysql 的日志是保证数据恢复的关键。那么日志肯定是要持久化到磁盘的,不然也会出现断电或者重启丢失的问题。那么接下来,我们将…

哈佛大学:三个简单的方式,患癌风险降低60%以上

癌症是全球主要的公共卫生问题,近年来,由于饮食、环境、人口的老龄化等因素,全球癌症发病率不断增长,癌症作为主要死因的情况日益突出。根据国际癌症研究机构(IARC)发布的2020年全球最新癌症数据&#xff0…

求斐波那契数(递归,非递归)

目录 一、斐波那契数? 二、递归实现求第n个斐波那契数 2.1代码与运行结果 2.1.1图解递归过程 三、非递归求法 3.1为什么不用递归求法 3.2非递归 一、斐波那契数? 它指的是这样的数列:1,1,2,3&#xff0…

【附源码】计算机毕业设计JAVA智能社区管理系统

项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven Vue 等等组成,B/…

安泰测试-信号发生器常见的故障与解决方法

信号发生器是一种能提供各种频率、波形和输出电平电信号的设备。在测量各种电信系统或电信设备的振幅特性、频率特性、传输特性及其它电参数时,以及测量元器件的特性与参数时,用作测试的信号源或激励源,经常和示波器是老搭档,也是…

三菱FX3U——ST编程流水灯

当D0的默认值为0时,赋值1; TON_1每隔1秒触发输出M1,M1触发D0左移一位,D0的值相当于每1秒乘以2; 在通过M1复位定时TON_1; 每一秒使一个输出得电,当D0的值不在选项内的值,将D0赋值为0&#xff1…

无序和混乱终结者,极狐GitLab Workflow 到底有什么魔力?

效率和质量是软件产品追求的两个核心关键点,软件产品研发是一个覆盖多阶段、涉及多团队的过程,业界也已经总结出了一些很好的实践,在保证研发效率的同时还能保证代码质量。比如代码提交规范、Code Review、代码准入、CI/CD。 但是由于缺乏行之…

冒死开源。阿里新产Spring Boot+Spring Cloud微服务开发实战笔记

昨天跟粉丝聊到了一个问题,他说现在很多招聘要求需要有微服务经验,本人目前生产上没有微服务经验,该如何弥补? 小编在这儿就分享一份学习资料,这份资料既是初学者学习微服务开发的技术宝典,又是中级开发人…

不同版本的谷歌浏览器跨域怎么设置?

由于项目前端使用8001端口,后端使用的8080端口,因此前端调用后端接口时需要跨域,在浏览器中需要设置跨域,否则会由于跨域安全性导致请求失败。 一. 浏览器版本大于49 1.在chrome中,需要新建一个chrome浏览器的快捷方…

HiveSQL分位数函数percentile()使用详解+实例代码

前言 作为数据分析师每个SQL数据库的函数以及使用技能操作都得点满,尤其是关于统计函数的使用方法。关于统计出数据的中位数,众数和分位数的方法必须掌握几种,一般在实际业务上大部分都是以写SQL查询为主,因为如果想用Python的Pa…

植物大战僵尸变态辅助开发系列教程(E语言实现和VC6实现)(下)

植物大战僵尸变态辅助开发系列教程(E语言实现和VC6实现)(下)36、全屏秒杀37、秒杀实现37、PVZ聚怪38、种植CALL的查找与调用39、OpenProcess错误40、错误:constchar[19]”转换为“LPCWSTR”附录:36、全屏秒…

opencv的相机校准和3D建模的理论知识

一、相机标定的四个坐标系 1、世界坐标系(Xw,Yw,Zw):也称真实或现实世界坐标系,或全局坐标系。它是客观世界的绝对坐标,由用户任意定义的三维空间坐标系。一般的3D场景都用这个坐标系来表示。 …

SSM框架使用多数据源(druid连接池)

最近有个数据归集的需求用到了多数据源,在业务库保存后同时向归集库插入或数据。之前好像还没做过这块的东西,简单记录下防止下次又忘记了~ 踩过的几个坑都是某些知识点不熟悉导致的,而且都是框架配置相关的.. 先上代码,再扯淡 …

PyQt5 拖拽与剪贴板

拖拽与剪切板拖拽剪贴板拖拽 基于MIME类型的拖拽数据传输时基于QDrag类的QMimeData对象管理的数据与其对应的MIME类型相关联。 MimeData类函数允许检测和使用方法的MIME类型 判断函数设置函数获取函数MIME类型hasText()text()setText()text/plainhasHtml()html()setHtml()tex…

【Java八股文总结】之SpringBoot

文章目录SpringBoot1、Spring Boot的优点?2、Spring Boot自动配置原理3、如何定义一个SpringBoot Starter?4、SpringBoot启动原理?5、SpringBoot的常用注解Spring Cache1、Spring Cache介绍2、Spring Cache注解Sharding-JDBCSpringBoot 1、S…