管理员
|
阅读:3423回复:0
[C++技术]C++记录程序崩溃时的dumpfile
楼主#
更多
发布于:2012-09-23 13:18
 | |  |  | 最近一段时间,新上线的软件在外场偶尔会出现异常崩溃的情况。由于试用范围比较分散,很难一一前往现场定位问题。而传统的log日志方法,在崩溃的情况下,并不能比较准确的表示出问题位置,这使得软件调试进程缓慢。 后在公司前辈的指点下,我们想到了使用window自带的dumpfile来记录崩溃时刻的堆栈信息,这样配合log日志记录,能够快速的定位出问题点。大大提高了系统调试效率。 经过一段时间的调试,现在项目已相对稳定了。想记录下此方法,以待后续类似情况下使用。 //使所有版本都可以捕获到异常 void DisableSetUnhandledExceptionFilter() { void *addr = (void*)GetProcaddress(LoadLibrary(_T("kernel32.dll")), "SetUnhandledExceptionFilter"); if (addr) { unsigned char code[16]; int size = 0; code[size++] = 0x33; code[size++] = 0xC0; code[size++] = 0xC2; code[size++] = 0x04; code[size++] = 0x00; DWORD dwOldFlag, dwTempFlag; VirtualProtect(addr, size, PAGE_READWRITE, ;dwOldFlag); WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL); VirtualProtect(addr, size, dwOldFlag, ;dwTempFlag); } } //程序未捕获的异常处理函数 LONG WINAPI ExceptionFilter(struct _EXCEPTION_POinterS *ExceptionInfo) { ::AfxMessageBox("ExceptionFilter"); HANDLE hFile = ::CreateFile( _T("C:\\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 = ExceptionInfo; einfo.ClientPointers = FALSE; ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, ;einfo, NULL, NULL); ::CloseHandle(hFile); } return 0; } //把当前时刻的线程栈记录到DUMP文件中 int RecordCurStack() { HANDLE hFile = ::CreateFile( _T("C:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( hFile != INVALID_HANDLE_VALUE) { ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory ,NULL, NULL, NULL); ::CloseHandle(hFile); return 1; } return 0; } bool bCreateDumpThrd = true; //循环检测线程 //查看到有ADTV2_TEMP.TXT文件,则记录下当前时刻的堆栈 void CreateDumpThrd(void* pv) { HANDLE hFile; string strPath = FileAssist::GetExePath() + "\\ADTV2_TEMP.TXT"; while(bCreateDumpThrd) { //每5秒检测一次 Sleep(5000); hFile = CreateFileA(strPath.c_str(), // file to open GENERIC_READ, // open for reading FILE_SHARE_READ, // share for reading NULL, // default security OPEN_EXISTING, // existing file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (hFile != INVALID_HANDLE_VALUE) { //防止多次记录当前堆栈信息,删除文件 ::CloseHandle(hFile); ::DeleteFile(strPath.c_str()); RecordCurStack(); } } } 然后在程序入口将异常处理接口声明即可。 //调试信息 ::SetUnhandledExceptionFilter(ExceptionFilter); //设置异常处理函数 DisableSetUnhandledExceptionFilter(); //获取未处理的异常 这样,在程序异常时,就可以在C盘根目录下记录一个dumpfile.dmp的文件。这个文件会比较大,一般有100多M,其中信息比log形式的日志丰富很多,包括了异常时的堆栈调用关系以及各对象的值。,在VS中可以直接打开。如果保留了和当时编译软件一致的代码备份的话,可以直接使用VS的debug功能定位到问题代码行,否则,debug定位是到汇编代码行,看起来比较麻烦。
| |  | |  |
|