MFC程序RELEASE版本輸出DUMP定位在代碼行

有時給客戶使用Release版本時,會偶爾出現崩潰的問題,這樣很不好定位。但通過程序輸出的dump文件可以定位到代碼。

客戶那邊出現崩潰時,只需要把.dmp文件拷貝過來,然後放在工程.map和.pdb同級目錄,然後用VS打開即可。具體過程如下:

1.在工程屬性的release中設置如下,目的是產生DEBUG信息需要的.map和.pdb文件

2.在工程中添加dump.h頭文件,

#pragma once  
#include <windows.h>  
#include <DbgHelp.h>  
#include <stdlib.h>  
#pragma comment(lib, "dbghelp.lib")  
  
#ifndef _M_IX86  
#error "The following code only works for x86!"  
#endif  
  
inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
{  
    if(pModuleName == 0)  
    {  
        return FALSE;  
    }  
  
    WCHAR szFileName[_MAX_FNAME] = L"";  
    _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
  
    if(wcsicmp(szFileName, L"ntdll") == 0)  
        return TRUE;  
  
    return FALSE;  
}  
  
inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,  
                                      const PMINIDUMP_CALLBACK_INPUT   pInput,  
                                      PMINIDUMP_CALLBACK_OUTPUT        pOutput)  
{  
    if(pInput == 0 || pOutput == 0)  
        return FALSE;  
  
    switch(pInput->CallbackType)  
    {  
    case ModuleCallback:  
        if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)  
            if(!IsDataSectionNeeded(pInput->Module.FullPath))  
                pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);  
    case IncludeModuleCallback:  
    case IncludeThreadCallback:  
    case ThreadCallback:  
    case ThreadExCallback:  
        return TRUE;  
    default:;  
    }  
  
    return FALSE;  
} 

inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
{  
    HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
        FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
  
    if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
    {  
        MINIDUMP_EXCEPTION_INFORMATION mdei;  
        mdei.ThreadId           = GetCurrentThreadId();  
        mdei.ExceptionPointers  = pep;  
        mdei.ClientPointers     = NULL;  
  
        MINIDUMP_CALLBACK_INFORMATION mci;  
        mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
        mci.CallbackParam       = 0;  
  
        ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
  
        CloseHandle(hFile);  
    }  
}  
  
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
{  
    CreateMiniDump(pExceptionInfo, "dtcd8100Test.dmp");  
  
    return EXCEPTION_EXECUTE_HANDLER;  
}  
  
// 此函數一旦成功調用,之後對 SetUnhandledExceptionFilter 的調用將無效  
void DisableSetUnhandledExceptionFilter()  
{  
    void* addr = (void*)GetProcAddress(LoadLibrary("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);  
    }  
}  
  
void InitMinDump()  
{  
    //註冊異常處理函數  
    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);  
  
    //使SetUnhandledExceptionFilter  
    DisableSetUnhandledExceptionFilter();  
}  

3.在MFC工程的入口InitInstance中調用InitMinDump()即可。

4.程序崩潰後會在EXE同級目錄下生成一個.dmp的文件,將它放在.pdb,.map同目錄下。然後將.dmp文件拖動到VS中即可

5.然後點擊紅框即可跳轉到代碼行。(注意產生的dmp文件時代碼要和分析時的一致)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章