向大厂看齐!为自己的程序增加自动转储的功能!
如果你还不清楚什么是转储文件,不知道什么时候需要转储文件,请参考转储文件系列文章的第一篇 —— 转储文件知多少。
前言
不知道各位小伙伴有没有遇到过 微信
或者 QQ
崩溃的情况。它们在崩溃的时候都会自动弹出一个对话框,提示用户上传相关文件,供开发人员分析问题的原因。有的小伙伴儿可能不太清楚我在说什么。没关系,下图就是微信崩溃后自动弹出的界面。
如果勾选了 发送错误报告(S)
按钮,点击 确定(O)
按钮后,会把收集到的文件上传给开发人员。同样的,如果勾选了 重启程序(R)
,点击 确定(O)
按钮后,微信会自动重启。有没有觉得很酷?我们自己的程序可以做到类似的效果吗?答案是肯定的。如果感兴趣,就请继续阅读吧!
MiniDumpWriteDump
微软提供了专门的 API
来生成转储文件,这个 API
就是 MiniDumpWriteDump()
。
BOOL MiniDumpWriteDump(HANDLE hProcess,DWORD ProcessId,HANDLE hFile,MINIDUMP_TYPE DumpType,PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);
简单介绍下每个参数:
hProcess
:要转储的进程句柄。打开进程的时候,至少需要指定
PROCESS_QUERY_INFORMATION
和PROCESS_VM_READ
权限。如果需要转储 句柄信息,还需要PROCESS_DUP_HANDLE
权限。如果需要转储线程信息,需要THREAD_ALL_ACCESS
权限。ProcessId
:要转储的进程ID
。有点不太理解为什么要额外传递一个进程 ID 的参数,调用
GetProcessId()
就可以根据hProcess
获取进程 ID 了,难道是为了效率?希望有知道的小伙伴儿指点一二。hFile
:通过CreateFile()
等API
打开的,用来保存dump
的文件句柄。DumpType
:转储类型。此参数会直接影响转储文件的大小,如果想自己写一个手动收集dump
的工具,了解下这个参数会很有用。稍后介绍。ExceptionParam
:指向异常信息结构MINIDUMP_EXCEPTION_INFORMATION
的指针。如果本参数为NULL
,则转储文件中不会包含异常信息。
typedefstruct _MINIDUMP_EXCEPTION_INFORMATION {DWORD ThreadId;PEXCEPTION_POINTERS ExceptionPointers;BOOL ClientPointers;} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;
UserStreamParam
:指向用户自定义信息结构MINIDUMP_USER_STREAM_INFORMATION
的指针。如果本参数为NULL
,则转储文件中不会包含用户定义的信息。
typedefstruct _MINIDUMP_USER_STREAM_INFORMATION {ULONG UserStreamCount;PMINIDUMP_USER_STREAM UserStreamArray;} MINIDUMP_USER_STREAM_INFORMATION, *PMINIDUMP_USER_STREAM_INFORMATION;
CallbackParam
:指向回调例程MINIDUMP_CALLBACK_INFORMATION
的指针。如果此参数为NULL
,转储过程中不会执行任何回调例程。
typedefstruct _MINIDUMP_CALLBACK_INFORMATION {MINIDUMP_CALLBACK_ROUTINE CallbackRoutine;PVOID CallbackParam;} MINIDUMP_CALLBACK_INFORMATION, *PMINIDUMP_CALLBACK_INFORMATION;
本结构中的CallbackParam
是传递给回调函数的参数,用户可以指定一些自己需要传递的参数,很常见的做法。CallbackRoutine
是回调函数,类型为 MINIDUMP_CALLBACK_ROUTINE
。原型如下:
typedefBOOL(WINAPI * MINIDUMP_CALLBACK_ROUTINE) (_Inout_ PVOID CallbackParam,_In_ PMINIDUMP_CALLBACK_INPUT CallbackInput,_Inout_ PMINIDUMP_CALLBACK_OUTPUT CallbackOutput);
因为 DumpType
会影响最后生成的转储文件的大小,这里介绍下这个参数。
DumpType 参数
DumpType
类型为 MINIDUMP_TYPE
。以下定义摘自 10.0.18362.0
版本的 minidumpapiset.h
,应该是比较全的了。如果你问我:你怎么知道 MINIDUMP_TYPE
定义在这个文件里?答案很简单:用 File Locator
搜的呗。
typedefenum _MINIDUMP_TYPE {MiniDumpNormal = 0x00000000,MiniDumpWithDataSegs = 0x00000001,MiniDumpWithFullMemory = 0x00000002,MiniDumpWithHandleData = 0x00000004,MiniDumpFilterMemory = 0x00000008,MiniDumpScanMemory = 0x00000010,MiniDumpWithUnloadedModules = 0x00000020,MiniDumpWithIndirectlyReferencedMemory = 0x00000040,MiniDumpFilterModulePaths = 0x00000080,MiniDumpWithProcessThreadData = 0x00000100,MiniDumpWithPrivateReadWriteMemory = 0x00000200,MiniDumpWithoutOptionalData = 0x00000400,MiniDumpWithFullMemoryInfo = 0x00000800,MiniDumpWithThreadInfo = 0x00001000,MiniDumpWithCodeSegs = 0x00002000,MiniDumpWithoutAuxiliaryState = 0x00004000,MiniDumpWithFullAuxiliaryState = 0x00008000,MiniDumpWithPrivateWriteCopyMemory = 0x00010000,MiniDumpIgnoreInaccessibleMemory = 0x00020000,MiniDumpWithTokenInformation = 0x00040000,MiniDumpWithModuleHeaders = 0x00080000,MiniDumpFilterTriage = 0x00100000,MiniDumpWithAvxXStateContext = 0x00200000,MiniDumpWithIptTrace = 0x00400000,MiniDumpScanInaccessiblePartialPages = 0x00800000,MiniDumpValidTypeFlags = 0x00ffffff,
} MINIDUMP_TYPE;
下面是每个选项的意义,主要翻译自官方帮助文档。
名称 | 描述 |
---|---|
MiniDumpNormal | 只包含调用栈相关信息 |
MiniDumpWithDataSegs | 包含已加载的模块的数据段信息,比如全局变量 |
MiniDumpWithFullMemory | 包含全部可访问的内存 |
MiniDumpWithHandleData | 包含句柄信息 |
MiniDumpFilterMemory | 过滤一些敏感信息,保护重建调用栈需要的信息 |
MiniDumpScanMemory | 扫描,以包含引用内存 |
MiniDumpWithUnloadedModules | 包含最近被卸载的模块信息 |
MiniDumpWithIndirectlyReferencedMemory | 包含未直接引用的内存 |
MiniDumpFilterModulePaths | 过滤某块的路径信息 |
MiniDumpWithProcessThreadData | 包含完整的进程和线程信息 |
MiniDumpWithPrivateReadWriteMemory | 包含页面属性为 PAGE_READWRITE 的页面 |
MiniDumpWithoutOptionalData | 不包含可选数据 |
MiniDumpWithFullMemoryInfo | 包含内存区信息 |
MiniDumpWithThreadInfo | 包含线程状态信息 |
MiniDumpWithCodeSegs | 包含所有代码和有关的内存段 |
MiniDumpWithoutAuxiliaryState | 关闭辅助内存收集 |
MiniDumpWithFullAuxiliaryState | 使用所有的内存收集器 |
MiniDumpWithPrivateWriteCopyMemory | 包含页面属性为 PAGE_WRITECOPY 的页面 |
MiniDumpIgnoreInaccessibleMemory | 忽略不可访问的页面 |
MiniDumpWithTokenInformation | 包含安全令牌相关信息。可以在调试的时候使用 "!token" 命令 |
MiniDumpWithModuleHeaders | 包含模块头相关信息 |
MiniDumpFilterTriage | 添加与筛选器分类相关的数据 |
MiniDumpWithAvxXStateContext | |
MiniDumpWithIptTrace | |
MiniDumpValidTypeFlags | 设置所有标志位 |
说明:
MINIDUMP_TYPE
的值是不断发展变化的(向后兼容),旧版本的DbgHelp.dll
可能不支持某些值,具体可以参考 微软官方介绍 MINIDUMP_TYPE 的文档[1]。
关于MINIDUMP_TYPE
每一项的作用更为详细的介绍请参考 Effective minidumps (Part 1)[2] 和 Effective minidumps (Part 2)[3]。真的是超级详细,强烈建议大家点开看一看!唯一的遗憾是作者写的比较早,很多新出现的标志没总结进来,但仍然是非常好的参考资料!
MiniDumpWriteDump()
可以用来生成转储文件,我们应该怎么使用呢?
使用场景
通常,我们希望在自己的程序发生异常的时候,能自动保存一份转储文件,供我们事后分析。我们需要做的大概是:捕获各种异常,在异常处理函数中判断发生的异常是否能恢复,如果不能恢复就保存转储文件和其它一些关键文件(比如,程序的配置文件,出现问题时的屏幕截图等),并一起打包并保存,然后提示用户,让用户上传我们打包好的文件供我们分析。当程序发生异常的时候,我们很难确定发生异常的进程的运行状态。所以我们需要启动一个新的进程,并在新进程中调用 MiniDumpWriteDump()
来保存异常进程的信息。
以上的操作看起来比较简单,但是处理起来,有很多细节需要考虑。比如,我们需要捕获哪些异常?怎么捕获这些异常?保存好的文件怎么上传?通过什么形式上传?等等等等…… 如果有可以直接拿来使用的框架,就太好了!别说,还真有!
相关开源库
以上的这些功能,早已经有开源软件可以用了。作为一个谦卑的程序员,尽量复用现有的轮子吧。给大家推荐一些不错的开源库。
CrashRpt[4] (之前在项目里用过,如果你想自己手动实现一个类似的,可以参考此项目的代码)。
除了
CrashRpt
,chromium
里使用的 crashpad[5] 也是一个非常好的选择。google
出品,质量有保障。crashpad
的前身是 breakpad[6](根据google
官方介绍,breakpad
使用的是进程内报告机制,不再建议大家使用)。适用于
.NET
程序的 CrashReporter[7]。其它平台(
Android
,iOS
等)也有类似的开源库。可以在github
上搜索crash report
。我就不截图了。
说明:
本文介绍的方法只适用于我们自己的程序。如果我们想转储其它进程,我们需要借助现有工具(当然,如果有时间和精力,也可以自己写一个)。关于抓取转储的工具的介绍,可以参考之前的文章—— 你需要知道的 N 种抓取 dump 的工具。
总结
我们可以通过
MiniDumpWriteDump()
来保存转储文件。我们可以借助
CrashRpt
,CrashPad
等开源框架来为我们的程序添加崩溃转储功能。
参考资料
《软件调试》
MiniDumpWriteDump 文档[8]
Effective minidumps (Part 1)[2]
Effective minidumps (Part 2)[3]
References:
[1]
微软官方介绍 MINIDUMP_TYPE 的文档: https://docs.microsoft.com/zh-cn/windows/win32/api/minidumpapiset/ne-minidumpapiset-minidump_type
[2]
Effective minidumps (Part 1): http://www.debuginfo.com/articles/effminidumps.html
[3]
Effective minidumps (Part 2): http://www.debuginfo.com/articles/effminidumps2.html
[4]
CrashRpt: http://crashrpt.sourceforge.net/
[5]
crashpad: https://github.com/chromium/crashpad
[6]
breakpad: https://github.com/google/breakpad
[7]
CrashReporter: https://github.com/ravibpatel/CrashReporter.NET
[8]
MiniDumpWriteDump 文档: https://docs.microsoft.com/zh-cn/windows/win32/api/minidumpapiset/nf-minidumpapiset-minidumpwritedump
猜你喜欢:
转储文件系列:
转储文件知多少
你需要知道的 N 种抓取 dump 的工具
你生成的转储文件有问题吗?
JIT Debug Info 简介
调试系列:
调试实战——你知道怎么使用DebugView查看调试信息吗?
调试实战——程序CPU占用率飙升,你知道如何快速定位吗?
调试实战——崩溃在ComFriendlyWaitMtaThreadProc
调试实战——使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs
调试实战——调试PInvoke导致的内存破坏
调试实战——调试excel启动时死锁
调试实战——调试DLL卸载时的死锁
调试实战——调试TerminateThread导致的死锁
排错系列:
排错实战——VS清空最近打开的工程记录
排错实战——拯救加载调试符号失败的IDA
排错实战——你知道拖动窗口时只显示虚框怎么设置吗?
排错实战——解决Tekla通过.tsep安装插件失败的问题
排错实战——使用process explorer替换任务管理器
排错实战——通过对比分析sysinternals事件修复程序功能异常
欢迎留言交流
向大厂看齐!为自己的程序增加自动转储的功能!相关推荐
- 段错误 (核心已转储)_向大厂看齐!为自己的程序增加自动转储的功能!
如果你还不清楚什么是转储文件,不知道什么时候需要转储文件,请参考转储文件系列文章的第一篇 -- 转储文件知多少. 前言 不知道各位小伙伴有没有遇到过 微信 或者 QQ 崩溃的情况.它们在崩溃的时候都会 ...
- php 微信机器人_微信小程序机器人自动客服功能
现在微信小程序在开发中比较流行,本文就教大家一种微信新功能:客服机器人的小程序,这个小程序也可以做其他类型的自动客服程序,在olami平台加上相应的问题和答案,就可以了. 整个小程序界面包含2个部分, ...
- 通过Swashbukle给DotNet Core Web API 增加自动文档功能
DotNet Core Web API给开发者提供了一个很好的框架来开发Restful的API.那么这些API接口该如何管理起来呢?Swagger是一个很好的选择,Swagger不需要开发者额外去维护 ...
- 为微信小程序增加换肤功能
起源 之前,我做了一个展示类的微信小程序,本来都快要完结的了,可是突然,我才听说还要给小程序增加一个换肤功能,这个换肤功能可不是简单的写两套不同的样式表就行了,因为他要可以在后台动态替换背景,底图,文 ...
- 微信小程序图片自动播放功能
小程序图片自动轮换滚动功能 在看小程序源码时,发现该小程序用内置组件"swiper"实现图片滚动功能.经过测试效果很不错,因此记录下实现方法. 使用小程序组件swiper实现滑块视 ...
- C++--在单文档的应用程序增加多个视图
在mfc的单文档的应用程序(Application)设计时,一般是一种文档(Documnet)对应一种视图(View) .然而在有些时候我需要一种文档用多种视图来展现,具体步骤如下: 我们有两个假设 ...
- 《Hadoop MapReduce实战手册》一1.4 给WordCount MapReduce程序增加combiner步骤
本节书摘来异步社区<Hadoop MapReduce实战手册>一书中的第1章,第1.4节,作者: [美]Srinath Perera , Thilina Gunarathne 译者: 杨卓 ...
- java 程序增加 防盗_防盗Java EE –保护Java EE企业应用程序的安全
java 程序增加 防盗 Øredev离我们仅有几天的路程,我受邀作了两次演讲. 其中之一是关于我最喜欢的主题:安全性和Java EE. 它旨在实现两个目标. 一方面向典型的Java EE开发人员介绍 ...
- iPad iPhone程序增加和删除启动画面
直接拖放到程序目录下面就可以了. Default.png iPhone默认启动图片, 320x480或者320x460 Default@2x.png iPhone ...
最新文章
- Centos 7下搭建WordPress
- git Rebase 代替合并
- MCU为什么内部不集成晶振
- display none的元素重新展示如何撑开页面_寻根问底之——元素隐藏你知多少?
- 功能测试人员技能提升路线图,试从第一个脚步到年薪50W...
- php程序员会什么,php程序员是什么
- 牛客网--华为机试在线训练1:字符串最后一个单词的长度
- CentOS 7.x 安装 Maven
- android 把数据导入到excel文件中的三种方法
- 基于能量采集的认知无线电功率分配
- 神州微型计算机,神舟笔记本序列号查维修-怎样根据神舟笔记本电脑的序列号查询...
- pth转onnx:RuntimeError: Exporting the operator uniform to ONNX opset version 9 is not supported.
- 7-1 最大子列和问题 (20分)(两种解法,包含联机算法)
- EAS中没有的核算项目新增
- 从西天取经的九九八十一难来看Java设计模式:模板方法模式
- 文献精读丨GWAS+TRN多组学方法揭示小麦穗发育调控过程
- 线性离散系统的分析与校正
- 计算机毕设结束语致谢,毕业设计结束语和致谢
- Spring cloud报错com.netflix.hystrix.exception.HystrixRuntimeException
- java 中free,FreeJava 的使用方法(三)FreeJava的使用,freejava使用方法
热门文章
- win7将 esc与 capslock 互换
- c# 类的基本知识,未完,待续
- cocos android-1,cocos2dx在windows下开发,编译到android上(1)
- 【本周面试题】第5周 - 开发工具相关
- 软件工程现行国标汇集
- React Native在Android当中实践(五)——常见问题
- 【tomcat】servlet原理及其生命周期
- /hgfs下无共享文件夹?/mnt下没有hgfs文件夹?vmhgfs-fuse:找不到命令?
- 图片加载框架Picasso - 源码分析
- php -- 用文本来存储内容,file_put_contents,serialize,unserialize