生成dump文件

dump文件生成

#pragma once

#define _CRT_SECURE_NO_WARNINGS

#include <windows.h>
#include <Dbghelp.h>
#include <iostream>
#include <vector>
#include <tchar.h>

using namespace std;


#pragma comment(lib, "Dbghelp.lib")


///
// Function declarations
//

LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);

BOOL PreventSetUnhandledExceptionFilter();

LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException);

void RunCrashHandler();

void CreateDump(
    LPCTSTR             lpstrDumpFilePathName,
    EXCEPTION_POINTERS* pep
);

BOOL CALLBACK MyMiniDumpCallback(
    PVOID                            pParam,
    const PMINIDUMP_CALLBACK_INPUT   pInput,
    PMINIDUMP_CALLBACK_OUTPUT        pOutput
);


///
// Minidump creation function
//

void CreateDump(LPCTSTR lpstrDumpFilePathName, EXCEPTION_POINTERS* pep)
{
    // Open the file

    HANDLE hFile = CreateFile(lpstrDumpFilePathName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
    {
        // Create the minidump

        MINIDUMP_EXCEPTION_INFORMATION mdei;

        mdei.ThreadId = GetCurrentThreadId();
        mdei.ExceptionPointers = pep;
        mdei.ClientPointers = FALSE;

        MINIDUMP_CALLBACK_INFORMATION mci;

        mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MyMiniDumpCallback;
        mci.CallbackParam = 0;

        MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);

        BOOL rv = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
            hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);

        if (!rv)
            _tprintf(_T("MiniDumpWriteDump failed. Error: %u \n"), GetLastError());
        else
            _tprintf(_T("Dump created.\n"));

        // Close the file

        CloseHandle(hFile);

    }
    else
    {
        _tprintf(_T("CreateFile failed. Error: %u \n"), GetLastError());
    }

}


///
// Custom minidump callback
//

BOOL CALLBACK MyMiniDumpCallback(
    PVOID                            pParam,
    const PMINIDUMP_CALLBACK_INPUT   pInput,
    PMINIDUMP_CALLBACK_OUTPUT        pOutput
)
{
    BOOL bRet = FALSE;


    // Check parameters

    if (pInput == 0)
        return FALSE;

    if (pOutput == 0)
        return FALSE;


    // Process the callbacks

    switch (pInput->CallbackType)
    {
    case IncludeModuleCallback:
    {
        // Include the module into the dump
        bRet = TRUE;
    }
    break;

    case IncludeThreadCallback:
    {
        // Include the thread into the dump
        bRet = TRUE;
    }
    break;

    case ModuleCallback:
    {
        // Does the module have ModuleReferencedByMemory flag set ?

        if (!(pOutput->ModuleWriteFlags & ModuleReferencedByMemory))
        {
            // No, it does not - exclude it

            wprintf(L"Excluding module: %s \n", pInput->Module.FullPath);

            pOutput->ModuleWriteFlags &= (~ModuleWriteModule);
        }

        bRet = TRUE;
    }
    break;

    case ThreadCallback:
    {
        // Include all thread information into the minidump
        bRet = TRUE;
    }
    break;

    case ThreadExCallback:
    {
        // Include this information
        bRet = TRUE;
    }
    break;

    case MemoryCallback:
    {
        // We do not include any information here -> return FALSE
        bRet = FALSE;
    }
    break;

    case CancelCallback:
        break;
    }

    return bRet;

}


LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
{
    return NULL;
}


BOOL PreventSetUnhandledExceptionFilter()
{
    HMODULE hKernel32 = LoadLibrary(_T("kernel32.dll"));
    if (hKernel32 == NULL)
        return FALSE;


    void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");

    if (pOrgEntry == NULL)
        return FALSE;


    unsigned char newJump[100];
    DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
    dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far


    void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
    DWORD dwNewEntryAddr = (DWORD)pNewFunc;
    DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;


    newJump[0] = 0xE9;  // JMP absolute
    memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
    SIZE_T bytesWritten;
    BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
    return bRet;
}


LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException)
{
    TCHAR szMbsFile[MAX_PATH] = { 0 };
    ::GetModuleFileName(NULL, szMbsFile, MAX_PATH);
    TCHAR* pFind = _tcsrchr(szMbsFile, '\\');
    if (pFind)
    {
        *(pFind + 1) = 0;
        _tcscat_s(szMbsFile, _T("CrashDump.dmp"));
        CreateDump(szMbsFile, pException);
    }


    // TODO: MiniDumpWriteDump
    FatalAppExit(-1, _T("Fatal Error"));
    return EXCEPTION_CONTINUE_SEARCH;
}


void RunCrashHandler()
{
    SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);
    PreventSetUnhandledExceptionFilter();
}

int main( int argc, char* argv[] )
{
    RunCrashHandler();

    int a = 0;
    int b = 10 / a;

    return 0;
}

注意事项

  • 1、需要配置debug选项:
    • 在C/C++选项->常规->调试信息格式(设置为程序数据库(/Zi))
    • 在连接器选项—>调试->生成调试信息(设置为是)
    • 在C/C++选项->优化禁用
  • 2、 可执行文件(exe)必须找到dbghelp.dll,才能生成Dump文件。这个DLL可以从调试工具包中找到。
  • 3、.exe、.pdb、.dump、dbghelp.dll 这四个文件需要放在同一目录下才能调试,dump文件必须与pdb文件匹配。双击dump文件时,VS就可以自动关联到出错代码位置。
  • 4、为了获取更多更深入的调试信息,需要把程序优化开关设置成禁用。

SetUnhandledExceptionFilter()

MSDN链接:https://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx
捕获异常的函数是SetUnhandledExceptionFilter(),该函数用于设置顶级异常函数,当程序中有异常发生并且没有被各个堆栈捕获时,最后将进入该函数设置的异常处理函数。

MiniDumpWriteDump()

MSDN链接:https://msdn.microsoft.com/en-us/library/ms680360(VS.85).aspx
dump文件的信息收集很大程度上取决于 MiniDumpWriteDump 函数中的 MINIDUMP_TYPE 参数的设置以及 MiniDumpCallback 的设置。

MINIDUMP_TYPE参数说明

MSDN链接:https://msdn.microsoft.com/en-us/library/ms680519(v=vs.85).aspx

MiniDumpCallback函数说明

MSDN链接:https://msdn.microsoft.com/en-us/library/ms680358(v=vs.85).aspx

参数比较

根据不同参数的设置可以产生不同的dump文件:

NameMINIDUMP_TYPEDump文件大小备注
TinyDumpMiniDumpNormal2KB去掉了所有线程和模块的信息,只包含异常发生的地址、异常时刻的线程上下文、异常代码。调试器甚至无法加载它.
MiniDumpMiniDumpWithIndirectlyReferencedMemory
MiniDumpScanMemory
50KB它比mindump的标准方式(MiniDumpNormal + no MiniDumpCallback))包含了更多的信息量。它允许查看栈上的引用的数据。但是,这个minidump还缺少一些重要的信息。例如,我们看不到全局标量的值,不能查看堆和TLS中分配的数据(除非他们被线程栈引用了)。
MidiDumpMiniDumpWithPrivateReadWriteMemory
MiniDumpWithDataSegs
MiniDumpWithHandleData
MiniDumpWithFullMemoryInfo
MiniDumpWithThreadInfo
MiniDumpWithUnloadedModules
2MB我们可以得到应用程序的几乎所有信息,包括全局变量的值、堆和TLS的内容、PEB、TEB。我们甚至可以得到句柄信息以及虚拟内存布局。这是一个非常有用的dump,并且不是很大。
MaxDumpMiniDumpWithFullMemory
MiniDumpWithFullMemoryInfo
MiniDumpWithHandleData
MiniDumpWithThreadInfo
MiniDumpWithUnloadedModules
40MB它给了我们在一个mindump中包含所有信息的可能。

更多信息

debuginfo.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值