Prolific Usage of MiniDumpWriteDump (Automating Crash Dump Analysis Part 0)

As a precursor to a series on programmatically querying crash dump files, I wanted to first talk about the MiniDumpWriteDump function.

 

You don't necessarily need to wait for your application to crash in order to generate a memory dump. As soon as you detect something bad happening, you can call MiniDumpWriteDump yourself and generate a crash dump file on the fly. If your application likes to eat exceptions or ignore error codes, or important asserts fire, or special test cases fail, then this is a great place to start collecting failure data for offline analysis.

 

And to make it super easy for you, I've created a helper function which will generate a filename based on the computer's name along with the date and time, then invoke the crash dump generator.

 

#include <dbghelp.h>

 

HRESULT GenerateCrashDump(MINIDUMP_TYPE flags, EXCEPTION_POINTERS *seh=NULL)

    {

    HRESULT error = S_OK;

 

    // get the time

    SYSTEMTIME sysTime = {0};

    GetSystemTime(&sysTime);

 

    // get the computer name

    char compName[MAX_COMPUTERNAME_LENGTH + 1] = {0};

    DWORD compNameLen = ARRAYSIZE(compName);

    GetComputerNameA(compName, &compNameLen);

 

    // build the filename: APPNAME_COMPUTERNAME_DATE_TIME.DMP

    char path[MAX_PATH] = {0};

    sprintf_s(path, ARRAYSIZE(path),

        "c:\\myapp_%s_%04u-%02u-%02u_%02u-%02u-%02u.dmp",

    compName, sysTime.wYear, sysTime.wMonth, sysTime.wDay,

        sysTime.wHour, sysTime.wMinute, sysTime.wSecond);

 

    // open the file

    HANDLE hFile = CreateFileA(path,

        GENERIC_READ|GENERIC_WRITE,

        FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,

        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

 

    if(hFile == INVALID_HANDLE_VALUE)

        {

        error = GetLastError();

        error = HRESULT_FROM_WIN32(error);

        return error;

        }

 

    // get the process information

    HANDLE hProc = GetCurrentProcess();

    DWORD procID = GetProcessId(hProc);

 

    // if we have SEH info, package it up

    MINIDUMP_EXCEPTION_INFORMATION sehInfo = {0};

    MINIDUMP_EXCEPTION_INFORMATION *sehPtr = NULL;

    if(seh)

        {

        sehInfo.ThreadId = GetCurrentThreadId();

        sehInfo.ExceptionPointers = seh;

        sehInfo.ClientPointers = FALSE;

        sehPtr = &sehInfo;

        }

 

    // generate the crash dump

    BOOL result = MiniDumpWriteDump(hProc, procID, hFile,

        flags, sehPtr, NULL, NULL);

 

    if(!result)

        {

        error = (HRESULT)GetLastError(); // already an HRESULT

        }

 

    // close the file

    CloseHandle(hFile);

 

    return error;

    }

 

Sample call:

    GenerateCrashDump((MINIDUMP_TYPE)

        (MiniDumpNormal |

        MiniDumpWithHandleData |

        MiniDumpWithUnloadedModules),

        NULL);

 

If you happen to have OS exception information available (via __try/__except), then you will definitely want to pass in the EXCEPTION_POINTERS information. This will embed important and detailed information about the exception into the crash dump.

And if you want to get really fancy, you can embed additional (custom) information via the 2nd to last parameter to MiniDumpWriteDump. For example, if your application is consuming external documents or information, it can be very handy to have this information (or metadata about it) accessible when diagnosing crash dumps after the fact.