C++記錄程序崩潰時的dumpfile

   最近一段時間,新上線的軟件在外場偶爾會出現異常崩潰的狀況。因爲試用範圍比較分散,很難一一前往現場定位問題。而傳統的log日誌方法,在崩潰的狀況下,並不能比較準確的表示出問題位置,這使得軟件調試進程緩慢。ide

   後在公司前輩的指點下,咱們想到了使用window自帶的dumpfile來記錄崩潰時刻的堆棧信息,這樣配合log日誌記錄,可以快速的定位出問題點。大大提升了系統調試效率。函數

   通過一段時間的調試,如今項目已相對穩定了。想記錄下此方法,以待後續相似狀況下使用。spa

  
  
  
  
  1. //使全部版本均可以捕獲到異常 
  2. void DisableSetUnhandledExceptionFilter() 
  3.     void *addr = (void*)GetProcAddress(LoadLibrary(_T("kernel32.dll")), "SetUnhandledExceptionFilter"); 
  4.  
  5.     if (addr)  
  6.     { 
  7.         unsigned char code[16]; 
  8.         int size = 0; 
  9.         code[size++] = 0x33; 
  10.         code[size++] = 0xC0; 
  11.         code[size++] = 0xC2; 
  12.         code[size++] = 0x04; 
  13.         code[size++] = 0x00; 
  14.  
  15.         DWORD dwOldFlag, dwTempFlag; 
  16.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag); 
  17.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL); 
  18.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag); 
  19.     } 
  20.  
  21. //程序未捕獲的異常處理函數 
  22. LONG WINAPI ExceptionFilter(struct _EXCEPTION_POINTERS *ExceptionInfo) 
  23.     ::AfxMessageBox("ExceptionFilter"); 
  24.  
  25.     HANDLE hFile = ::CreateFile( _T("C:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
  26.     if( hFile != INVALID_HANDLE_VALUE) 
  27.     { 
  28.         MINIDUMP_EXCEPTION_INFORMATION einfo; 
  29.         einfo.ThreadId = ::GetCurrentThreadId(); 
  30.         einfo.ExceptionPointers = ExceptionInfo; 
  31.         einfo.ClientPointers = FALSE; 
  32.  
  33.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &einfo, NULL, NULL); 
  34.         ::CloseHandle(hFile); 
  35.     } 
  36.  
  37.     return 0; 
  38.  
  39. //把當前時刻的線程棧記錄到DUMP文件中 
  40. int RecordCurStack() 
  41.     HANDLE hFile = ::CreateFile( _T("C:\\dumpfile.dmp"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
  42.     if( hFile != INVALID_HANDLE_VALUE) 
  43.     { 
  44.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpWithFullMemory  ,NULL, NULL, NULL); 
  45.  
  46.         ::CloseHandle(hFile); 
  47.         return 1; 
  48.     } 
  49.  
  50.     return 0; 
  51.  
  52.  
  53. bool bCreateDumpThrd = true
  54. //循環檢測線程 
  55. //查看到有ADTV2_TEMP.TXT文件,則記錄下當前時刻的堆棧 
  56. void CreateDumpThrd(void* pv) 
  57.     HANDLE hFile;  
  58.     string strPath = FileAssist::GetExePath() + "\\ADTV2_TEMP.TXT"
  59.     while(bCreateDumpThrd) 
  60.     { 
  61.         //每5秒檢測一次 
  62.         Sleep(5000); 
  63.         hFile = CreateFileA(strPath.c_str(),    // file to open 
  64.             GENERIC_READ,          // open for reading 
  65.             FILE_SHARE_READ,       // share for reading 
  66.             NULL,                  // default security 
  67.             OPEN_EXISTING,         // existing file only 
  68.             FILE_ATTRIBUTE_NORMAL, // normal file 
  69.             NULL);                 // no attr. template 
  70.  
  71.         if (hFile != INVALID_HANDLE_VALUE)  
  72.         {  
  73.             //防止屢次記錄當前堆棧信息,刪除文件 
  74.             ::CloseHandle(hFile); 
  75.             ::DeleteFile(strPath.c_str()); 
  76.             RecordCurStack(); 
  77.         } 
  78.     } 

而後在程序入口將異常處理接口聲明便可。線程

  
  
  
  
  1. //調試信息 
  2. ::SetUnhandledExceptionFilter(ExceptionFilter); //設置異常處理函數 
  3. DisableSetUnhandledExceptionFilter();           //獲取未處理的異常 

這樣,在程序異常時,就能夠在C盤根目錄下記錄一個dumpfile.dmp的文件。這個文件會比較大,通常有100多M,其中信息比log形式的日誌豐富不少,包括了異常時的堆棧調用關係以及各對象的值。,在VS中能夠直接打開。若是保留了和當時編譯軟件一致的代碼備份的話,能夠直接使用VS的debug功能定位到問題代碼行,不然,debug定位是到彙編代碼行,看起來比較麻煩。debug

相關文章
相關標籤/搜索