如何捕捉程序异常/crash 并生成 dump 文件

时间:2022-09-18 22:36:28

前面介绍如如何用WinDBG 生成crash dump 《WinDBG 技巧:如何生成Dump 文件(.dump 命令)》,但是用户机器上通常不安装WinDBG, 而且多数用户也不知道怎么使用WinDBG。 所以最好是自己程序里面能够捕捉exception/crash,并且生成crash dump,然后通过网络传回到自己服务器。

捕捉exception 可以用API 函数SetUnhandledExceptionFilter。生成crash dump 可以用DbgHelp.dll 里面的MiniDumpWriteDump函数。

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter( __in LPTOP_LEVEL_EXCEPTION_FILTERlpTopLevelExceptionFilter );

BOOL WINAPI MiniDumpWriteDump( __in HANDLEhProcess, __in DWORDProcessId, __in HANDLEhFile, __in MINIDUMP_TYPEDumpType, __in PMINIDUMP_EXCEPTION_INFORMATIONExceptionParam, __in PMINIDUMP_USER_STREAM_INFORMATIONUserStreamParam, __in PMINIDUMP_CALLBACK_INFORMATIONCallbackParam );

代码示例:

[cpp]view plaincopyprint?

  1. #include <dbghelp.h> 
  2. #include <shellapi.h> 
  3. #include <shlobj.h> 
  4.  
  5.  
  6. // 自定义的exectpion filter 
  7. LONG WINAPI MyUnhandledExceptionFilter(struct_EXCEPTION_POINTERS *pExceptionPointers) 
  8.  
  9.     SetErrorMode( SEM_NOGPFAULTERRORBOX ); 
  10.  
  11.     //收集信息 
  12.      CStringW strBuild; 
  13.     strBuild.Format(L"Build: %s %s", __DATE__, __TIME__); 
  14.     CStringW strError; 
  15.     HMODULE hModule; 
  16.    WCHAR szModuleName[MAX_PATH] = L""
  17.     GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule); 
  18.     GetModuleFileName(hModule, szModuleName, ARRAYSIZE(szModuleName)); 
  19.     strError.AppenedFormat(L"%s %d , %d ,%d.", szModuleName,pExceptionPointers->ExceptionRecord->ExceptionCode, pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress); 
  20.  
  21.     //生成 mini crash dump 
  22.    BOOL bMiniDumpSuccessful; 
  23.     WCHAR szPath[MAX_PATH];  
  24.    WCHAR szFileName[MAX_PATH];  
  25.     WCHAR* szAppName = L"AppName"
  26.    WCHAR* szVersion = L"v1.0"
  27.     DWORD dwBufferSize = MAX_PATH; 
  28.    HANDLE hDumpFile; 
  29.     SYSTEMTIME stLocalTime; 
  30.     MINIDUMP_EXCEPTION_INFORMATION ExpParam; 
  31.     GetLocalTime( &stLocalTime ); 
  32.     GetTempPath( dwBufferSize, szPath ); 
  33.     StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName ); 
  34.     CreateDirectory( szFileName, NULL ); 
  35.     StringCchPrintf( szFileName, MAX_PATH, L"%s%s//%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",  
  36.                szPath, szAppName, szVersion,  
  37.                stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,  
  38.                stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,  
  39.                GetCurrentProcessId(), GetCurrentThreadId()); 
  40.     hDumpFile = CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE,  
  41.                 FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); 
  42.  
  43.     MINIDUMP_USER_STREAM UserStream[2]; 
  44.     MINIDUMP_USER_STREAM_INFORMATION UserInfo; 
  45.     UserInfo.UserStreamCount = 1; 
  46.     UserInfo.UserStreamArray = UserStream; 
  47.     UserStream[0].Type = CommentStreamW; 
  48.     UserStream[0].BufferSize = strBuild.GetLength()*sizeof(WCHAR); 
  49.     UserStream[0].Buffer = strBuild.GetBuffer(); 
  50.     UserStream[1].Type = CommentStreamW; 
  51.     UserStream[1].BufferSize = strError.GetLength()*sizeof(WCHAR); 
  52.     UserStream[1].Buffer = strError.GetBuffer(); 
  53.  
  54.     ExpParam.ThreadId = GetCurrentThreadId(); 
  55.     ExpParam.ExceptionPointers = pExceptionPointers; 
  56.     ExpParam.ClientPointers = TRUE; 
  57.      
  58.     MINIDUMP_TYPE MiniDumpWithDataSegs = MiniDumpNormal  
  59.             | MiniDumpWithHandleData  
  60.             | MiniDumpWithUnloadedModules  
  61.             | MiniDumpWithIndirectlyReferencedMemory  
  62.             | MiniDumpScanMemory  
  63.             | MiniDumpWithProcessThreadData  
  64.             | MiniDumpWithThreadInfo; 
  65.     bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),  
  66.                     hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL); 
  67.   // 上传mini dump 到自己服务器(略) 
  68.   ... 
  69.  
  70.  return EXCEPTION_CONTINUE_SEARCH;//或者 EXCEPTION_EXECUTE_HANDLER 关闭程序 
  71.   
  72. int _tmain() 
  73.   // 设置 execption filter 
  74.   SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); 
  75.   .... 
  76.  return 0; 
  77. }