调试Release发布版程序的Crash错误(五)

来源:互联网 发布:轻量级c语言ide 编辑:程序博客网 时间:2024/04/30 12:58

当我们把自己的release版本程序发布出去以后,一般都是在用户的机器上运行。这种情况下,对于第四种方案,因为需要pdb文件才能够正确生成堆栈调用的函数行号及代码行号,因此方案四只适用于本地release版的调试,否则只能生成不完整的堆栈信息。对于前三种方案,其实只需要用户告知崩溃地址,然后在本地查找crash地址就可以了,但是定位crash的过程非常不方便,如果crash的情况比较多,前三种方案都不合适。而且,前三种方案均不能生成堆栈调用信息,对于debug的作用有限。

   下面我们就来看一个更加完善的解决方案。

 

   方案五:SetUnhandledExceptionFilter +Minidump

   SetUnhandleExceptionFilter函数我们已经介绍过了,本方案的思路还是要利用我们自己的异常处理函数,来生成minidump文件。

   1、Minidump概念

   minidump(小存储器转储)可以理解为一个dump文件,里面记录了能够帮助调试crash的最小有用信息。实际上,如果你在 系统属性-> 高级 -> 启动和故障恢复 -> 设置-> 写入调试信息 中选择“小内存转储(64KB)”的话,当系统意外停止时都会在C:/Windows/Minidump/路径下生成一个.dmp后缀的文件,这个文件就是minidump文件,只不过这个是内核态的minidump。

   我们要生成的是用户态的minidump,文件中包含了程序运行的模块信息、线程信息、堆栈调用信息等。而且为了符合其mini的特性,dump文件是压缩过的。

   2、生成minidump文件

   生成minidump文件的API函数是MiniDumpWriteDump,该函数需要dbghelp.lib支持,其原型如下:

    BOOLWINAPI MiniDumpWriteDump(
     __in         HANDLE hProcess,
     __in         DWORD ProcessId,
     __in         HANDLE hFile,
     __in         MINIDUMP_TYPE DumpType,
     __in         PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
     __in         PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
     __in         PMINIDUMP_CALLBACK_INFORMATION CallbackParam
    );

   在我们的异常处理函数中加入以下代码:

   HANDLE hFile = ::CreateFile(_T("E://dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL);
    if( hFile != INVALID_HANDLE_VALUE)
    {
        MINIDUMP_EXCEPTION_INFORMATION einfo;
        einfo.ThreadId = ::GetCurrentThreadId();
        einfo.ExceptionPointers = pExInfo;
        einfo.ClientPointers = FALSE;

       ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(),hFile, MiniDumpNormal, &einfo, NULL, NULL);
       ::CloseHandle(hFile);
    }

   其中,pExInfo变量为异常处理函数PEXCEPTION_POINTERS类型的参数。具体请参考MSDN。

   3、调试minidump

    调试dump文件首先需要pdb文件,因此我们build程序时需要设置Debug Infomation Format 为 “ProgramDatabase(/Zi)”。其次,我们还要确保所用的dump文件与源代码、exe、pdb文件版本是一致的,这要求我们必须维护好程序版本信息。

   调试minidump最方便的环境就是VS了,我们只要将.dmp、.exe、.pdb文件放在一个路径下,保证源代码文件的路径与编译时的路径一致就可以了,剩下的就是VS帮我们完成。双击.dmp文件或者在文件打开工程中选择“dumpfiles”,加载dump文件,然后按F5运行就能直接恢复crash时的现场了,你可以定位crash的代码,可以查看调用堆栈,可以查看线程和模块信息...一切都跟你设置断点调试一样,太强大了!看个截图吧。

调试Release发布版程序的Crash错误(五)

   需要注意的是,对于release版的程序来说,很多代码是经过编译器优化过的,因此定位的时候可能会有所偏差,大家可以考虑设置选项去掉代码优化。

   其他可以调试minidump的工具还有WinDbg等,大家可以查阅相关资料。

   本文主要参考了这篇文章:http://vicchina.51.net/research/other/seh/minidumps/intro.htm。

   下一篇,我们将给出一个调试release发布程序的完美解决方案,适合用户量较大的应用发布程序的调试。