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

稱馴我發表於2020-11-14

  最近一段時間,新上線的軟體在外場偶爾會出現異常崩潰的情況。由於試用範圍比較分散,很難一一前往現場定位問題。而傳統的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定位是到彙編程式碼行,看起來比較麻煩。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69920910/viewspace-2734140/,如需轉載,請註明出處,否則將追究法律責任。

相關文章