1. 程式人生 > >程式異常崩潰捕捉-dmp檔案及Windbg分析

程式異常崩潰捕捉-dmp檔案及Windbg分析

#include <dbghelp.h>  
    #include <shellapi.h>  
    #include <shlobj.h>  
      
      
    // 自定義的exectpion filter  
    LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *pExceptionPointers)  
    {  
      
        SetErrorMode( SEM_NOGPFAULTERRORBOX );  
      
        //收集資訊  
         CStringW strBuild;  
        strBuild.Format(L"Build: %s %s", __DATE__, __TIME__);  
        CStringW strError;  
        HMODULE hModule;  
        WCHAR szModuleName[MAX_PATH] = L"";  
        GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)pExceptionPointers->ExceptionRecord->ExceptionAddress, &hModule);  
        GetModuleFileName(hModule, szModuleName, ARRAYSIZE(szModuleName));  
        strError.AppenedFormat(L"%s %d , %d ,%d.", szModuleName,pExceptionPointers->ExceptionRecord->ExceptionCode,       pExceptionPointers->ExceptionRecord->ExceptionFlags, pExceptionPointers->ExceptionRecord->ExceptionAddress);  
      
        //生成 mini crash dump  
        BOOL bMiniDumpSuccessful;  
        WCHAR szPath[MAX_PATH];   
        WCHAR szFileName[MAX_PATH];   
        WCHAR* szAppName = L"AppName";  
        WCHAR* szVersion = L"v1.0";  
        DWORD dwBufferSize = MAX_PATH;  
        HANDLE hDumpFile;  
        SYSTEMTIME stLocalTime;  
        MINIDUMP_EXCEPTION_INFORMATION ExpParam;  
        GetLocalTime( &stLocalTime );  
        GetTempPath( dwBufferSize, szPath );  
        StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );  
        CreateDirectory( szFileName, NULL );  
        StringCchPrintf( szFileName, MAX_PATH, L"%s%s//%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",   
                   szPath, szAppName, szVersion,   
                   stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,   
                   stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,   
                   GetCurrentProcessId(), GetCurrentThreadId());  
        hDumpFile = CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE,   
                    FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);  
      
        MINIDUMP_USER_STREAM UserStream[2];  
        MINIDUMP_USER_STREAM_INFORMATION UserInfo;  
        UserInfo.UserStreamCount = 1;  
        UserInfo.UserStreamArray = UserStream;  
        UserStream[0].Type = CommentStreamW;  
        UserStream[0].BufferSize = strBuild.GetLength()*sizeof(WCHAR);  
        UserStream[0].Buffer = strBuild.GetBuffer();  
        UserStream[1].Type = CommentStreamW;  
        UserStream[1].BufferSize = strError.GetLength()*sizeof(WCHAR);  
        UserStream[1].Buffer = strError.GetBuffer();  
      
        ExpParam.ThreadId = GetCurrentThreadId();  
        ExpParam.ExceptionPointers = pExceptionPointers;  
        ExpParam.ClientPointers = TRUE;  
          
        MINIDUMP_TYPE MiniDumpWithDataSegs = MiniDumpNormal   
                | MiniDumpWithHandleData   
                | MiniDumpWithUnloadedModules   
                | MiniDumpWithIndirectlyReferencedMemory   
                | MiniDumpScanMemory   
                | MiniDumpWithProcessThreadData   
                | MiniDumpWithThreadInfo;  
        bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),   
                        hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);  
      // 上傳mini dump 到自己伺服器(略)  
      ...  
      
      return EXCEPTION_CONTINUE_SEARCH; //或者 EXCEPTION_EXECUTE_HANDLER 關閉程式  
    }  
       
    int _tmain()  
    {  
      // 設定 execption filter  
      SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);  
      ....  
      return 0;  
    }
 

在程式異常生成dmp檔案後,我們需要使用該檔案對應的pdb檔案來定位程式崩潰的原始檔:

建立PDB檔案基本上是這幾個選項,a)在project setting的C++屬性中,選擇生成program database,或者直接手動加入/Zi選項,如果有/Z7,把它替換成/Zi。b)在link選項中選擇Generate debug info,或者直接加入/debug選項,另外注意/pdb應該是類似/PDB:".\Release/yourproj.pdb"這樣的,如果不是手動修改。

有的人會擔心包含debug資訊以後檔案變大,修改link中這兩個選項/OPT:REF和/OPT:ICF會減小最終生成的檔案大小。在這裡借用一下John Robbins的截圖。

image



windbg 除錯崩潰
1、程式崩潰發生過程
這是一個對檔案進行處理的模組,而處理模組在處理之前,需查詢被處理的檔案是否值得處理。這個任務執行過程中發生了崩潰,問題就發生在查詢模組。
2、提取dump檔案
3、分析dump:
1)啟動windbg,file--open crash dump 配置符號庫,reload完成 。
2)使用命令 :.ecxr獲得程序崩潰時暫存器的內容
0:021> .ecxr (意指恢復崩潰時所有暫存器的內容,包括堆疊等)
eax=0532d414 ebx=00000fec ecx=000003fb edx=00000000 esi=0532c428 edi=00000000
eip=750f53ea esp=0490f22c ebp=0490f234 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
msvcr80!memmove+0x5a:
750f53ea f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:002b:00000000=???????? ds:002b:0532c428=00000000

3)使用命令:k 顯示堆疊
0:021> k (.ecxr不能直接顯示堆疊,需使用k顯示堆疊)
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
0490f234 03ba4806 msvcr80!memmove+0x5a(kxewfsys呼叫memmove,memmove是個字串操作函式,能把字串的一部分複製到另一部分,這裡出問題,可能是複製時傳遞的指標有問題,或者字串的大小有問題)
0490f25c 03ba2547 kxewfsys!__ovfl_get+0xa6 (呼叫memmove之前內部的一些處理)
0490f27c 03ba4a74 kxewfsys!__bt_cmp+0x77
0490f2a8 03ba2679 kxewfsys!__bt_search+0x74
0490f2c4 03ba1409 kxewfsys!__bt_get+0x49
0490f2d8 03ba7448 kxewfsys!IKBDBImpl::Get+0x19
0490f2f8 03ba750d kxewfsys!CFdbFileInfo::Search+0x28 [e:eingsoft_eubauilduild_srckicekice_kxewhitesrckxewfssysfdbfileinfo.cpp @ 483]
0490f338 03ba9c63 kxewfsys!CFdbFileInfo::QueryFileInfo+0x4d [e:eingsoft_eubauilduild_srckicekice_kxewhitesrckxewfssysfdbfileinfo.cpp @ 546]
0490f380 028210d1 kxewfsys!CFdbManager::QueryFileInfo+0xa3 [e:eingsoft_eubauilduild_srckicekice_kxewhitesrckxewfssysfdbmanager.cpp @ 370] (kxewfsys 是處理查詢模組)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for kspfeng.dll -
0490f390 03b1323c kxewhite!kxe_white_query_file_info+0x21 [e:eingsoft_eubauilduild_srckicekice_kxewhitesrckxewfssdkkxewfs.cpp @ 103] (將檔案提交進行查詢.)
0490f45c 03b13442 kspfeng!KSEGetAddonEntries+0x21fbc (kspfeng.dll是檔案處理模組用到的公共功能的封裝檔案)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ksecore.dll -
0490f498 03abcaa4 kspfeng!KSEGetAddonEntries+0x221c2
0490f4c8 03b07fd5 ksecore+0x1caa4
0490f52c 03b1c52b kspfeng!KSEGetAddonEntries+0x16d55
0490f860 5019dd7c kspfeng!KSEGetAddonEntries+0x2b2ab
0490f864 01c95695 0x5019dd7c
0490f868 1a77217c 0x1c95695
0490f86c 01c95693 0x1a77217c
0490f870 1a7982dc 0x1c95693
0490f874 01c95693 0x1a7982dc
4、總結崩潰原因
查詢模組,對檔案路徑的處理存在bug。