C++记录程序崩溃时的dumpfile

来源:互联网 发布:mac两个窗口 编辑:程序博客网 时间:2024/06/04 20:07
新上线的软件在外场偶尔会出现异常崩溃的情况。由于试用范围比较分散,很难一一前往现场定位问题。而传统的log日志方法,在崩溃的情况下,并不能比较准确的表示出问题位置,这使得软件调试进程缓慢。

  后在公司前辈的指点下,我们想到了使用window自带的dumpfile来记录崩溃时刻的堆栈信息,这样配合log日志记录,能够快速的定位出问题点。大大提高了系统调试效率。

  经过一段时间的调试,现在项目已相对稳定了。想记录下此方法,以待后续类似情况下使用。

  1.//使所有版本都可以捕获到异常

  2.void DisableSetUnhandledExceptionFilter()

  3.{

  4.    void *addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")), "SetUnhandledExceptionFilter");

  5.6.    if (addr)

  7.    {

  8.        unsigned char code[16];

  9.        int size = 0;

  10.        code[size++] = 0x33;

  11.        code[size++] = 0xC0;

  12.        code[size++] = 0xC2;

  13.        code[size++] = 0x04;

  14.        code[size++] = 0x00;

  15.16.        DWORD dwOldFlag, dwTempFlag;

  17.        VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);

  18.        WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);

  19.        VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);

  20.    }

  21.}

  22.23.//程序未捕获的异常处理函数

  24.LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo)

  25.{

  26.    ::AfxMessageBox("ExceptionFilter");

  27.28.    HANDLE hFile = ::CreateFile( _T("C:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  29.    if( hFile != INVALID_HANDLE_VALUE)

  30.    {

  31.        MINIDUMP_EXCEPTION_INFORMATION einfo;

  32.        einfo.ThreadId = ::GetCurrentThreadId();

  33.        einfo.ExceptionPointers = ExceptionInfo;

  34.        einfo.ClientPointers = FALSE;

  35.36.        ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &einfo, NULL, NULL);

  37.        ::CloseHandle(hFile);

  38.    }

  39.40.    return 0;

  41.}

  42.43.//把当前时刻的线程栈记录到DUMP文件中

  44.int RecordCurStack()

  45.{

  46.    HANDLE hFile = ::CreateFile( _T("C:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  47.    if( hFile != INVALID_HANDLE_VALUE)

  48.    {

  49.        ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory  ,NULL, NULL, NULL);

  50.51.        ::CloseHandle(hFile);

  52.        return 1;

  53.    }

  54.55.    return 0;

  56.}

  57.58.59.bool bCreateDumpThrd = true;

  60.//循环检测线程

  61.//查看到有ADTV2_TEMP.TXT文件,则记录下当前时刻的堆栈

  62.void CreateDumpThrd(void* pv)

  63.{

  64.    HANDLE hFile;

  65.    string strPath = FileAssist::GetExePath() + "\\ADTV2_TEMP.TXT";

  66.    while(bCreateDumpThrd)

  67.    {

  68.        //每5秒检测一次

  69.        Sleep(5000);

  70.        hFile = CreateFileA(strPath.c_str(),    // file to open

  71.            GENERIC_READ,          // open for reading

  72.            FILE_SHARE_READ,       // share for reading

  73.            NULL,                  // default security

  74.            OPEN_EXISTING,         // existing file only

  75.            FILE_ATTRIBUTE_NORMAL, // normal file

  76.            NULL);                 // no attr. template

  77.78.        if (hFile != INVALID_HANDLE_VALUE)

  79.        {

  80.            //防止多次记录当前堆栈信息,删除文件

  81.            ::CloseHandle(hFile);

  82.            ::DeleteFile(strPath.c_str());

  83.            RecordCurStack();

  84.        }

  85.    }

  86.}

  然后在程序入口将异常处理接口声明即可。

  1.//调试信息

  2.::SetUnhandledExceptionFilter(ExceptionFilter); //设置异常处理函数

  3.DisableSetUnhandledExceptionFilter();           //获取未处理的异常

  这样,在程序异常时,就可以在C盘根目录下记录一个dumpfile.dmp的文件。这个文件会比较大,一般有100多M,其中信息比log形式的日志丰富很多,包括了异常时的堆栈调用关系以及各对象的值。,在VS中可以直接打开。如果保留了和当时编译软件一致的代码备份的话,可以直接使用VS的debug功能定位到问题代码行,否则,debug定位是到汇编代码行,看起来比较麻烦。

 

今天尝试集成了CrashRpt,感觉还不错,功能很完善,集成也很容易。http://code.google.com/p/crashrpt/

下载以后解压缩,虽然有现成的Dll,EXE,但是还是建议自己编译,因为这个CrashRpt需要和你程序共享一样的vc runtime dll,否则某些异常截获不到。
编译很简单,有现成的VC 工程,支持 2005, 2008,就是需要WTL支持下载 WTL 80, http://sourceforge.net/projects/wtl/但是有一个小问题,如果你用VC Express版本的话,那么是没有ATL的,如果你装的Windows Plarform SDK是2008的话,那么就彻底杯具了,也没有ATL(在这个开源的大时代,微软连ATL这破东西都不舍得开放),解决方法是安装 2003版本的SDK,如果你能找到的话,或者找别人copy一份ATL ,就在SDK\include\atl目录下。http://www.cppblog.com/Files/stevenyao/atl.7z   我自己打包了一份ATL,希望微软不要告我。。。

然后,http://crashrpt.sourceforge.net/docs/html/simple_example.html 到这里抄个例子

info.pszEmailTo = _T("myapp_support@hotmail.com"); //改成你自己的email
随便写个什么程序,自己弄个crash出来,注意,需要把下列文件复制到你的程序的exe目录
CrashRpt.dll
CrashSender.exe
dbghelp.dll
crashrpt_lang.ini
好了,测试下吧,应该会提示程序崩溃,是否发送crash log的对话框。如果发送,那么会在email里收到一个zip文件,和一个zip的md5校验码。
这个zip文件里包含有crashdump.dmp 和 crashrpt.xml, xml只是些信息,dmp是Crash dump可以用vc直接打开,如果你有源代码和所有符号表,那么就能还原当时崩溃的现场。 

 

原创粉丝点击