windows生成dump文件

2019-05-25 16:01:28 浏览数 (2)

windows下程序有时突然崩溃了,偶发性的崩溃很难找。于是就需要保存崩溃时的dump信息了。

下面是关于如何生成dmp文件的代码。

头文件

代码语言:javascript复制
#pragma once
#include <windows.h>
#include <DbgHelp.h>
#include <stdlib.h>
#include <string>
#pragma comment(lib, "dbghelp.lib")


namespace FrameworkMiniDump
{
    std::wstring GetTimeNowString();
    std::string WStringToString(const std::wstring& str);
    std::wstring StringToWString(const std::string& str);
    std::string getexepath();
    inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName);

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

    inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName);
    LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
    void DisableSetUnhandledExceptionFilter();// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效
    void InitMinDump();
}

源文件:

代码语言:javascript复制
#include "MiniDump.h"
#include <iostream>
#include <ctime>
#include <string>

namespace FrameworkMiniDump
{
    std::wstring GetTimeNowString()
    {
        time_t rawtime;
        struct tm * timeinfo;
        wchar_t buffer[80];

        time(&rawtime);
        timeinfo = localtime(&rawtime);

        //wcsftime(buffer, sizeof(buffer), L"%d-%m-%Y %H:%M:%S", timeinfo);
        wcsftime(buffer, sizeof(buffer), L"%d-%m-%Y-%H-%M-%S", timeinfo);
        std::wstring str(buffer);
        return str;
    }


    std::wstring StringToWString(const std::string& str)
    {
#if defined(WIN32)
        size_t sz = str.length();
        int nd = MultiByteToWideChar(CP_ACP, 0, &str[0], sz, NULL, 0);
        std::wstring ret(nd, 0);
        int w = MultiByteToWideChar(CP_ACP, 0, &str[0], sz, &ret[0], nd);
        if (str.length() != sz) {

            throw std::exception("StringToWString Err");
        }
        return ret;
#else
        const char* p = str.c_str();
        size_t len = str.length();
        size_t sz = len * sizeof(wchar_t);
        wchar_t* tp = new wchar_t[sz];
        size_t w = mbstowcs(tp, p, sz);
        if (w != len) {
            delete[] tp;
            throw std::exception("StringToWString Err");
        }
        std::wstring ret(tp);
        delete[] tp;
        return ret;
#endif
    }

    std::string WStringToString(const std::wstring& str)
    {
        size_t sz = str.length();
#if defined(WIN32)
        int nd = WideCharToMultiByte(CP_ACP, 0, &str[0], sz, NULL, 0, NULL, NULL);
        std::string ret(nd, 0);
        int w = WideCharToMultiByte(CP_ACP, 0, &str[0], sz, &ret[0], nd, NULL, NULL);
        /*if (ret.length() != sz) {
            throw std::exception("WStringToString Err");
        }*/
        return ret;
#else
        const wchar_t* p = str.c_str();
        char* tp = new char[sz];
        size_t w = wcstombs(tp, p, sz);
        if (w != sz) {
            delete[] tp;

            throw std::exception("WStringToString Err");
        }
        std::string ret(tp);
        delete[] tp;
        return ret;
#endif
    }

    std::string getexepath()
    {
        wchar_t result[MAX_PATH];

        std::wstring wstr = std::wstring(result, GetModuleFileName(NULL, result, MAX_PATH));
        return WStringToString(wstr);
    }


    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, std::wstring(L"ntdll").c_str()) == 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)
    {
        std::string exename = "Dmp";
        std::wstring wexename = StringToWString(exename);;
        std::wstring filename = wexename   L"-"   GetTimeNowString()   L".dmp";
        CreateMiniDump(pExceptionInfo, filename.c_str());

        return EXCEPTION_EXECUTE_HANDLER;
    }

    // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效
    void DisableSetUnhandledExceptionFilter()
    {
        void* addr = (void*)GetProcAddress(LoadLibrary(L"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();
    }
}

使用:

代码语言:javascript复制
int main()
{
  ......
    FrameworkMiniDump::InitMinDump(); 
  ......  
}

调用一下InitMinDump就可以了,这里面会注册一个回调,崩溃时会保存的dmp文件。

注意:需要在debug模式。保存下来的dmp文件,需要结合pdb文件和源代码才能定位到哪里崩溃了。具体的我也不懂。

0 人点赞