C++程序中dump文件生成方法详解

最近项目中新作成了一个动态链接库,长时间运行后,偶尔会崩溃。根据log分析,被调用的动态库函数最外层catch到了这个异常,但是不能定位哪里出了问题。另外虽然上层exe是有dump文件输出处理的,但是在C++中,如果异常被捕获并处理的情况下,系统就不会生成dump文件了。如果仍希望在try-catch块中捕获异常的同时生成dump文件,就必须在catch块中手动调用生成dump文件的函数。这样可以在异常被捕获后仍然生成dump文件以供后续分析。本文详细介绍下怎么生成dump文件。


链接库

Windows平台上用Windows调试帮助库中的函数MiniDumpWriteDump来生成dump文件。

dbghelp.h头文件

#include <dbghelp.h>

dbghelp.lib库

项目【属性】→【链接器】→【输入】→【附加依赖项】→ 添加dbghelp.lib
在这里插入图片描述


dump生成原理:

生成dump文件的原理是在未处理异常发生时,系统调用设置的未处理异常过滤器回调函数,并将异常信息传递给这个回调函数。回调函数可以利用这些异常信息,如异常指针和线程ID,来创建一个包含应用程序状态快照的dump文件。这个快照包括了应用程序的内存、寄存器状态、堆栈信息等,可以帮助开发人员在应用程序崩溃时进行调试和分析。

SetUnhandledExceptionFilter函数是Windows平台上用于设置未处理异常过滤器的函数。
MiniDumpWriteDump函数是Windows平台上用于输出dump文件的函数。


代码实例

dump文件名和输出路径设置

dump文件名和输出路径没有什么硬性要求,根据各自程序的需求来即可。

本文
dump文件名:当前模块名+当前时间
dump输出路径:当前模块所在同级目录

// 获取当前模块的路径
std::string GetCurrentModuleFilePath()
{
	char buffer[MAX_PATH];
	GetModuleFileName(nullptr, buffer, MAX_PATH);
	return std::string(buffer);
}

// 获取当前模块的名字(不含后缀)
std::string GetModuleName(const std::string& filePath)
{
	std::string fileName = "";

	size_t lastSlash = filePath.find_last_of("\\");
	size_t lastDot = filePath.find_last_of(".");
	if (lastSlash != std::string::npos 
		&& lastDot != std::string::npos
		&& lastDot > lastSlash)
	{
		fileName = filePath.substr(lastSlash + 1, lastDot - lastSlash - 1);
	}

	return fileName;
}

// 获取当前时间(2023-11-23_18-42-345形式)
std::string GetCurrentTimeWithFormat() 
{
	SYSTEMTIME st;
	GetLocalTime(&st);

	std::string fileName;
	fileName = std::to_string(st.wYear) + "-" + std::to_string(st.wMonth) + "-" + std::to_string(st.wDay) + "_" + std::to_string(st.wHour) + "-" + std::to_string(st.wMinute) + "-" + std::to_string(st.wSecond) + "-" + std::to_string(st.wMilliseconds);

	return fileName;
}

未处理异常过滤器回调函数

// 未处理异常过滤器回调函数																																		
LONG WINAPI UnhandledExceptionFilterCallback(EXCEPTION_POINTERS *pExceptionPointers)
{
	std::string moduleFilePath = GetCurrentModuleFilePath();
	std::string moduleFileName = GetModuleName(moduleFilePath);
	std::string currentTime = GetCurrentTimeWithFormat();

	// 获取dump文件名字
	std::string dumpFileName = moduleFileName + "_" + currentTime + ".dmp";

	// 获取dump文件输出路径
	std::string dumpFilePath = "";
	size_t pos = moduleFilePath.find_last_of("\\");
	if (pos != std::string::npos)
	{
		dumpFilePath = moduleFilePath.substr(0, pos + 1) + dumpFileName;
	}
	else
	{
		dumpFilePath = dumpFileName;
	}

	// 创建dump文件
	HANDLE hDumpFile = CreateFile(dumpFilePath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hDumpFile != INVALID_HANDLE_VALUE) 
	{
		MINIDUMP_EXCEPTION_INFORMATION miniDumpExceptionInfo;
		miniDumpExceptionInfo.ThreadId = GetCurrentThreadId();           // 表示引发异常的线程的线程标识符
		miniDumpExceptionInfo.ExceptionPointers = pExceptionPointers;    // 指向包含有关异常上下文信息的指针的指针
		miniDumpExceptionInfo.ClientPointers = FALSE;                    // 指示是否包含有关客户端指针的信息。如果设置为 TRUE,则会包含客户端指针的信息;如果设置为 FALSE,则不会包含客户端指针的信息。
		
		/*
		Note
		在 Windows 编程中,客户端指针通常指的是指向客户端应用程序内存中的数据结构或对象的指针。
		当生成 dump 文件时,包含客户端指针的信息可能会暴露应用程序的内部结构和数据,可能包含敏感信息,因此在某些情况下可能需要禁用客户端指针的信息以保护隐私和安全。
		*/

		// 根据自己的需要指定dump文件的类型,一般MiniDumpNormal就可
		MINIDUMP_TYPE miniDumpType = (MINIDUMP_TYPE)(MiniDumpNormal
			| MiniDumpWithHandleData
			| MiniDumpScanMemory
			| MiniDumpWithProcessThreadData
			| MiniDumpWithThreadInfo);

		// 写入dump文件
		BOOL bMiniDumpWriteSuccessful = MiniDumpWriteDump(
			GetCurrentProcess(),     // 获取进程句柄
			GetCurrentProcessId(),   // 获取进程ID
			hDumpFile,               // 要写入的dump文件句柄
			miniDumpType,            // 指定dump文件的类型
			&miniDumpExceptionInfo,  // 指向包含异常信息的结构体指针
			NULL,                    // 指向用户自定义数据的结构体指针
			NULL                     // 指向回调函数的结构体指针
		);                      
		CloseHandle(hDumpFile);
	}

	return EXCEPTION_EXECUTE_HANDLER;
}

未处理异常过滤器函数的调用

未处理异常过滤器函数的调用应该在main函数(MFC程序的话是InitInstance函数)入口或者dll函数的入口。

int main(){
	// 设置未处理异常过滤器
	SetUnhandledExceptionFilter(UnhandledExceptionFilterCallback);
	
    // 程序逻辑
    //......
}

try-catch模块场合

如果异常发生在try快中,且被catch捕捉到,系统就不会生成dump文件了。如果仍希望在try-catch块中捕获异常的同时生成dump文件,就必须在catch块中手动调用生成dump文件的函数。

catch
{
	// 其他处理......
	UnhandledExceptionFilterCallback(nullptr)}

注意事项

在生成dump文件时,有一些注意事项需要考虑:

  • 文件大小:生成的dump文件可能会很大,特别是在应用程序的内存占用较大时。确保生成dump文件的目标位置有足够的磁盘空间。
  • 调试符号:为了更好地分析dump文件,通常需要应用程序的调试符号(PDB文件)。确保在生成dump文件时,同时保存了相关的调试符号信息。
  • 版本一致性:在分析dump文件时,确保使用与生成dump文件时相同版本的调试符号和源代码。否则,可能会导致分析结果不准确。

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

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

相关文章

Python requests请求响应以流stream的方式打印输出

如果你使用的请求库是requests&#xff0c;那么你必须了解的大模型里的请求怎么响应式的接收并打印出来的。 这里给大家写一下正式的书写方式: import requestsurl "http://localhost:8080/stream"payload {} headers {}response requests.request("GET&q…

创新洞察|展望2030 – 企业数字化转型的10大趋势(阿里研究院)

企业是否一定要 数字化创新 转型&#xff1f;究竟如何数字化转型&#xff1f;难点和坑又是什么&#xff1f;阿里研究院副院长针对未来十年中国的数字化转型提出十个方面需要关注的趋势&#xff1a;1.大国优势 2. 重构的消费者决策体系 3. 下一代数字原生企业 4. 所有企业都会成…

Endnote软件添加期刊引用格式

在下述网址中&#xff0c;找到你想要添加的期刊&#xff0c;下载引用格式文件&#xff08;后缀为.ens格式&#xff09; https://endnote.com/downloads/styles/?wpv_post_searchInformationfusion&wpv_aux_current_post_id12829&wpv_view_count12764-TCPID12829 下载…

ELK企业级日志分析平台——logstash

部署 新建一台虚拟机elk4部署logstash [rootelk4 ~]# yum install -y jdk-11.0.15_linux-x64_bin.rpm[rootelk4 ~]# yum install -y logstash-7.6.1.rpm 命令方式 [rootelk4 bin]# /usr/share/logstash/bin/logstash -e input { stdin { } } output { stdout {} } elasticsearc…

数仓成本下降近一半,StarRocks 存算分离助力云览科技业务出海

成都云览科技有限公司倾力打造了凤凰浏览器&#xff0c;专注于为海外用户提供服务&#xff0c;公司致力于构建一个全球性的数字内容连接入口&#xff0c;为用户带来更为优质、高效、个性化的浏览体验。 作为数据驱动的高科技公司&#xff0c;从数据中挖掘价值一直是公司核心任务…

【C++】——标准模板库STL作业(其一)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

Python-Django的“日志功能-日志模块(logging模块)-日志输出”的功能详解

01-综述 可以使用Python内置的logging模块来实现Django项目的日志记录。 所以与其说这篇文章在讲Django的“日志功能-日志模块-日志输出”&#xff0c;不如说是在讲Pthon的“日志功能-日志模块-日志输出”&#xff0c;即Python的logging模块。 下面用一个实例来进行讲解。 …

纯干货之阿里云云计算认证,赶紧收藏!

一、阿里云&云计算认证&#xff0c;引领未来 想必大家对阿里这个企业都很熟悉&#xff0c;我们平时常用的支付宝、淘宝、钉钉、飞猪等等都是阿里的产业&#xff0c;用在我们生活的各个方面。 但大家可能不知道的是&#xff0c;阿里云的云计算技术也是领先全国甚至全球的&…

机器学习实战-第4章 基于概率论的分类方法: 朴素贝叶斯

朴素贝叶斯 概述 贝叶斯分类是一类分类算法的总称,这类算法均以贝叶斯定理为基础,故统称为贝叶斯分类。本章首先介绍贝叶斯分类算法的基础——贝叶斯定理。最后,我们通过实例来讨论贝叶斯分类的中最简单的一种: 朴素贝叶斯分类。 贝叶斯理论 & 条件概率 贝叶斯理论 …

CAN基础知识

CAN 简介 CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO 国际标准化的串行通信 协议。在当前的汽车产业中&#xff0c;出于对安全性、舒适性、方便性、低公害、低成本的要求&#xff0c;各种 各样的电子控制系统被开发了出来…

保姆级 Keras 实现 YOLO v3 一

保姆级 Keras 实现 YOLO v3 一 一. YOLO v3 总览二. 特征提取网络特征提取网络代码实现 三. 特征融合特征融合代码实现 四. 网络输出模型输出代码实现 五. 网络模型代码实现六. 代码下载 如果要给 YOLO 目标检测算法一个评价的话, 就是快和准, 现在已经到了 v8, 但是我为什么还…

【考研数据结构代码题7】求一元多项式之和

题目&#xff1a;编写一个算法&#xff0c;求一元多项式之和 考纲&#xff1a;一元多项式的表示与相加 题型&#xff1a;代码填空或算法设计 难度&#xff1a;★★★ 参考代码 typedef struct node{float coef;//系数int exp;//次数struct node *next; }polynode; polynode *…

Volcano3D绘制3D火山图

一边学习&#xff0c;一边总结&#xff0c;一边分享&#xff01; 本期教程内容 **注&#xff1a;**本教程详细内容 Volcano3D绘制3D火山图 一、前言 火山图是做差异分析中最常用到的图形&#xff0c;在前面的推文中&#xff0c;我们也推出了好几期火山图的绘制教程&#xff0…

红队攻防实战之内网穿透隐秘隧道搭建

别低头&#xff0c;皇冠会掉&#xff1b;别流泪&#xff0c;贱人会笑。 本文首发于先知社区&#xff0c;原创作者即是本人 0x00 前言 构建内网隐蔽通道&#xff0c;从而突破各种安全策略限制&#xff0c;实现对目标服务器的完美控制。 当我们从外网成功获得攻击点的时候&…

【LeetCode】挑战100天 Day13(热题+面试经典150题)

【LeetCode】挑战100天 Day13&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-152.1 题目2.2 题解 三、面试经典 150 题-153.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&…

ComfyUI搭建使用教程

ComfyUI 是一个基于节点流程式的stable diffusion AI 绘图工具WebUI&#xff0c; 你可以把它想象成集成了stable diffusion功能的substance designer&#xff0c; 通过将stable diffusion的流程拆分成节点&#xff0c;实现了更加精准的工作流定制和完善的可复现性。但节点式的工…

STM32F103C8T6第6天:adc、iic、spi、温湿度dht11在lcd1602显示

1. ADC介绍 ADC是什么&#xff1f; Analog-to-Digital Converter&#xff0c;指模拟/数字转换器 ADC的性能指标 量程&#xff1a;能测量的电压范围分辨率&#xff1a;ADC能辨别的最小模拟量&#xff0c;通常以输出二进制数的位数表示&#xff0c;比如&#xff1a;8、10、1…

人工智能:一种现代的方法 第十四章 概率推理

文章目录 人工智能&#xff1a;一种现代的方法 第十四章 概率推理本章前言14.1 不确定性问题域中的知识表示14.1.1 联合概率分布14.1.2贝叶斯网络 14.2 贝叶斯网络的语义14.2.1表示联合概率分布14.2.2 紧致性14.2.3 节点排序14.2.4 贝叶斯网络中的条件独立关系14.3 条件分布的有…

div中添加el-loading(局部loading的使用)

效果&#xff1a;在div中实现el-loading <div class"content-main">{{ hotList }}</div>getHotList(columnType) {this.$nextTick(() > {var loading this.$loading({lock: true,text: "努力加载中...",spinner: "el-icon-loading&qu…

【LeetCode刷题-回溯】-- 47.全排列II

47.全排列II 主要需要解决全排列不重复的问题&#xff0c;设定一个规则&#xff0c;保证在填第i个数的时候重复数字只会被填入一次即可&#xff0c;而在本题中&#xff0c;我们选择对原数组排序&#xff0c;保证相同的数字都相邻&#xff0c;然后每次填入的数一定是这个数所在重…