Windows 程序 dump 崩溃调试
Windows 程序捕获崩溃异常 生成dump
概述
事情的起因是,有个同事开发的程序,交付的版本程序,会偶尔随机崩溃了。
悲催的是没有输出log,也没有输出dump文件。
我建议他给程序代码加个异常捕获,在崩溃时生成dump,方便找出问题点。
隔了一天之后,短暂交流,发现他没有这个开发经验,我只好披挂上阵了。
开动
查阅MSDN文档,和stackoverlfow.com的相关文章,可知
SetUnhandledExceptionFilter 可以捕获触发系统崩溃的异常
风风火火开始写代码
- void exceptionHandler(PEXCEPTION_POINTERS excpInfo)
- {
- // your code to handle the exception. Ideally it should
- // marshal the exception for processing to some other
- // thread and wait for the thread to complete the job
- std::unique_lock<std::mutex> lk(g_handlerLock);
- generateMiniDump(nullptr, excpInfo);
- }
- LONG WINAPI unhandledException(PEXCEPTION_POINTERS excpInfo = nullptr)
- {
- DebugBreak();
- if (excpInfo == nullptr)
- {
- __try // Generate exception to get proper context in dump
- {
- RaiseException(EXCEPTION_BREAKPOINT, , , nullptr);
- }
- __except (exceptionHandler(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
- {
- }
- }
- else
- {
- exceptionHandler(excpInfo);
- }
- return ;
- }
- SetUnhandledExceptionFilter(unhandledException);
测试
在main函数入口,设置异常处理函数SetUnhandledExceptionFilter。
异常处理函数负责捕获异常,调用MiniDumpWriteDump生成dump文件,供开发者使用Windbg调试
编译运行
Access Volation C000005错误可以顺利捕获
令人费解的是,
abort,数组越界,虚函数调用异常等均无法捕获
系统把这些异常给拦截了,并给出了程序崩溃的提示窗口
改进
为了捕获这些异常并生成dump文件,必须要把系统拦截的那一层给禁止掉
1. 禁止系统弹出崩溃窗口,该窗口提示非常渣,对开发者和用户都不友好
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
可以模仿腾讯的QQ程序,专门开发一个对用户界面友好Bug Report的程序,
在程序崩溃时转存储dump文件时,运行该程序提示用户有用的信息。
2. 注册异常捕获函数
- SetUnhandledExceptionFilter(unhandledException);
当异常发生时,系统会跳进我们的unhandleException回调中
在该回调函数中,我们可以弹出Bug Report这样的子进程,并存储异常dump文件
3. 拦截C Runtime的异常处理
- _set_invalid_parameter_handler(invalidParameter);
- _set_purecall_handler(pureVirtualCall);
- signal(SIGABRT, sigAbortHandler);
- _set_abort_behavior(, );
这些异常处理只是简单的调用unhandleException函数
4. 开启系统的程序崩溃请求
Vista之后,微软加了一个特性
程序崩溃时,默认不交给程序崩溃处理
而是使用一个莫名其妙的机制,不让程序进入崩溃环节
搞得用户懵逼,开发者也让代码无法进入崩溃异常处理
- void EnableCrashingOnCrashes()
- {
- typedef BOOL(WINAPI *tGetPolicy)(LPDWORD lpFlags);
- typedef BOOL(WINAPI *tSetPolicy)(DWORD dwFlags);
- const DWORD EXCEPTION_SWALLOWING = 0x1;
- HMODULE kernel32 = LoadLibraryA("kernel32.dll");
- tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32,
- "GetProcessUserModeExceptionPolicy");
- tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32,
- "SetProcessUserModeExceptionPolicy");
- if (pGetPolicy && pSetPolicy)
- {
- DWORD dwFlags;
- if (pGetPolicy(&dwFlags))
- {
- // Turn off the filter
- pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
- }
- }
- }
5. 断了系统SetUnhandledExceptionFilter的后路
C Runtime等异常,运行时库会调用SetUnhandledExceptionFilter向系统注册一个NULL
从而使得我们之前注册的回调失效
真是无语(ˉ▽ˉ;)...
在这里,需要hook掉SetUnhandledExceptionFilter,在我们注册完回调之后,让它默认不做任何处理
用到Windows核心编程这本书里面,Jeffrey Richter开发的CAPIHook这个模块
- void PreventSetUnhandledExceptionFilter()
- {
- CAPIHook apiHook("kernel32.dll",
- "SetUnhandledExceptionFilter",
- (PROC)ExceptionFilterHookProc);
- }
其中ExceptionFilterHookProc这个函数是个空函数,无需做多余操作,直接renturn null即可
6. 完整流程
- void setExceptionHandlers()
- {
- if (!IsDebuggerPresent() && !g_isHandlerSet)
- {
- g_isHandlerSet = true;
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
- SetUnhandledExceptionFilter(unhandledException);
- _set_invalid_parameter_handler(invalidParameter);
- _set_purecall_handler(pureVirtualCall);
- signal(SIGABRT, sigAbortHandler);
- _set_abort_behavior(, );
- EnableCrashingOnCrashes();
- PreventSetUnhandledExceptionFilter();
- }
- }
在VS或者Windbg中调试时,我们就没有必要生成dump文件了
IsDebuggerPresent这个系统API会帮助我们判断我们是否在调试环境中
总结
即使看起来这么简单的一个功能,也是需要挺多细节处理的。
Windows 程序 dump 崩溃调试的更多相关文章
- 编写的windows程序,崩溃时产生crash dump文件的办法
一.引言 dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件便成了我们查找错误的最后一根救命的稻草.windows程序 ...
- windows下dump文件调试
dump调试:在系统中异常或者崩溃的时候,来生成dump文件,然后用调试器来调试.这样就可以在生产环境中的dmp文件,拷贝到自己的开发机器上,调试就可以找到错误的位置,配合程序调试符号pdb文件,直接 ...
- [转]让程序在崩溃时体面的退出之Dump文件
原文地址:http://blog.csdn.net/starlee/article/details/6630816 在我的那篇<让程序在崩溃时体面的退出之CallStack>中提供了一个在 ...
- 让程序在崩溃时体面的退出之Dump文件
在我的那篇<让程序在崩溃时体面的退出之CallStack>中提供了一个在程序崩溃时得到CallStack的方法.但是要想得到CallStack,必须有pdb文件的支持.但 ...
- 自定义VS程序异常处理及调试Dump文件(一)
自定义VS程序异常处理及调试Dump文件(一) 1. Dump文件 1. Dump文件介绍 Dump文件(Dump File),也叫转储文件,以.DMP为文件后缀.dump文件是进程在内存中的镜像文件 ...
- [转]让程序在崩溃时体面的退出之SEH+Dump文件
原文地址:http://blog.csdn.net/starlee/article/details/6649605 在我上篇文章<让程序在崩溃时体面的退出之SEH>中讲解了SEH中try/ ...
- vc/vs开发的应用程序添加dump崩溃日志<转>
原贴地址:https://blog.csdn.net/wangkui1331/article/details/78029940 vc/vs开发的应用程序出现崩溃的时候,由于没有任何记录,导致开发人员很 ...
- 程序异常崩溃后用windbg辅助调试解决的经验 以及 堆栈问题调试经验
1,程序异常崩溃后用windbg辅助调试解决的经验 状况:我的程序调用别人的库做 文件写入工作. 在这一过程中出现异常,程序崩溃. 经反复检查,认为自己的程序没有错,但无法判断在别人库里哪里有错. ...
- 使用Windows事件查看器调试崩溃
本文讨论如何使用Windows事件查看器获取实际崩溃的模块以及代码中崩溃的位置.示例代码是用C++编写的,以生成不同类型的崩溃,例如访问冲突和堆栈溢出. 简介 我经常听同事和QA那里听说,一个特定的崩 ...
随机推荐
- charles抓取https中出现unknow
http正常抓包,https则出现unknown 1.安装证书 Help->SSL Proxying->Install Charles Root Certificate 但是!!!装完并没 ...
- bzoj2049: [Sdoi2008]Cave 洞穴勘测 lct裸题
题意:三种操作一种摧毁一条边,一种链接一条边,一种查询两个点是否联通 题解:lct的link和cut即可 /********************************************** ...
- 数论练习(6)——hdu A/B(逆元gcd)
A/B Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Collections中的各种方法
一.各种方法介绍 Counter 统计个数 elements most_common subtract defaultdict 字典默认值 ChainMap 合并多个映射对象(字典) Ord ...
- @pathVariable的作用
//url中的id 可通过@pathVariable绑定到函数的参数中
- ansible入门01
1.批量操作 1.操作系统选型与安装: 1.安装在实体机上: 批量安装: PXE(预引导执行环境):需要网卡上有DHCP客户端去加载bootloadder cobbler: kickstack: 2. ...
- DateTime和字符串转换问题
DateTime和string之间的相互转换经常碰到,可就这么简单的一个转换其中也有些需要注意的地方. static void Main(string[] args) { string format ...
- 二叉树的前序、中序、后序遍历 python
话不多说,直接上代码 class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None cl ...
- web前端开发常用的几种图片格式及其使用规范
首先,在正式说图片格式之前,咱们先说一些额外的东西. 矢量图与位图 矢量图是通过组成图形的一些基本元素,如点.线.面,边框,填充色等信息通过计算的方式来显示图形的.一般来说矢量图表示的是几何图形,文件 ...
- HDU 1198
http://acm.hdu.edu.cn/showproblem.php?pid=1198 裸并查集,主要工作在根据题目给出关系构图 #include <iostream> #inclu ...