Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to have crash dumps generated when processes crash?

In Windows environments (XP and Win 7):

  • What is the best way to automatically have a crash dump generated when processes crash on the system?
  • Can an installer (MSI) package do this?
like image 670
CJ7 Avatar asked Nov 27 '13 08:11

CJ7


1 Answers

Below explanation is based on another answer, but the logic is mine (without attribution need, as said on my profile);

Having your own dump generation framework which automatically creates a process dump when any Unhandled exception is encountered, would avoid clients having to install WinDbg.

At the application start up use SetUnhandledExceptionFilter(...) Win32 API to register a callback (i.e. application level exception-handler). Now the registered callback function is called whenever there is any exception which is not handled. You may then create the process dump using MiniDumpWriteDump(...) API from DbgHelp.dll.

C++ Sample (unicode-enabled)

header-file

#ifndef CRASH_REPORTER_H
#define CRASH_REPORTER_H

//Exclude rarely used content from the Windows headers.
#ifndef WIN32_LEAN_AND_MEAN
#    define WIN32_LEAN_AND_MEAN
#    include <windows.h>
#    undef WIN32_LEAN_AND_MEAN
#else
#    include <windows.h>
#endif
#include <tchar.h>
#include <DbgHelp.h>

class CrashReporter {
public:
    inline CrashReporter() { Register(); }
    inline ~CrashReporter() { Unregister(); }

    inline static void Register() {
        if(m_lastExceptionFilter != NULL) {
            fprintf(stdout, "CrashReporter: is already registered\n");
            fflush(stdout);
        }
        SetErrorMode(SEM_FAILCRITICALERRORS);
        //ensures UnHandledExceptionFilter is called before App dies.
        m_lastExceptionFilter = SetUnhandledExceptionFilter(UnHandledExceptionFilter);
    }
    inline static void Unregister() {
        SetUnhandledExceptionFilter(m_lastExceptionFilter);
    }

private:
    static LPTOP_LEVEL_EXCEPTION_FILTER m_lastExceptionFilter;
    static LONG WINAPI UnHandledExceptionFilter(_EXCEPTION_POINTERS *);
};


#endif // CRASH_REPORTER_H

source-file

#include "crash-report.h"

#include <stdio.h>

LPTOP_LEVEL_EXCEPTION_FILTER CrashReporter::m_lastExceptionFilter = NULL;

typedef BOOL (WINAPI *MiniDumpWriteDumpFunc)(HANDLE hProcess, DWORD ProcessId
        , HANDLE hFile
        , MINIDUMP_TYPE DumpType
        , const MINIDUMP_EXCEPTION_INFORMATION *ExceptionInfo
        , const MINIDUMP_USER_STREAM_INFORMATION *UserStreamInfo
        , const MINIDUMP_CALLBACK_INFORMATION *Callback
    );

LONG WINAPI CrashReporter::UnHandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtr)
{
    //we load DbgHelp.dll dynamically, to support Windows 2000
    HMODULE hModule = ::LoadLibraryA("DbgHelp.dll");
    if (hModule) {
        MiniDumpWriteDumpFunc dumpFunc = reinterpret_cast<MiniDumpWriteDumpFunc>(
                    ::GetProcAddress(hModule, "MiniDumpWriteDump")
                );
        if (dumpFunc) {
            //fetch system time for dump-file name
            SYSTEMTIME  SystemTime;
            ::GetLocalTime(&SystemTime);
            //choose proper path for dump-file
            wchar_t dumpFilePath[MAX_PATH] = {0};
            _snwprintf_s(dumpFilePath, MAX_PATH, L"crash_%04d-%d-%02d_%d-%02d-%02d.dmp"
                    , SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay
                    , SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond
                );
            //create and open the dump-file
            HANDLE hFile = ::CreateFileW( dumpFilePath, GENERIC_WRITE
                    , FILE_SHARE_WRITE
                    , NULL
                    , CREATE_ALWAYS
                    , FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN
                    , NULL
                );

            if (hFile != INVALID_HANDLE_VALUE) {
                _MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
                exceptionInfo.ThreadId          = GetCurrentThreadId();
                exceptionInfo.ExceptionPointers = exceptionPtr;
                exceptionInfo.ClientPointers    = NULL;
                //at last write crash-dump to file
                bool ok = dumpFunc(::GetCurrentProcess(), ::GetCurrentProcessId()
                        , hFile, MiniDumpNormal
                        , &exceptionInfo, NULL, NULL
                    );
                //dump-data is written, and we can close the file
                CloseHandle(hFile);
                if (ok) {
                    //Return from UnhandledExceptionFilter and execute the associated exception handler.
                    //  This usually results in process termination.
                    return EXCEPTION_EXECUTE_HANDLER;
                }
            }
        }
    }
    //Proceed with normal execution of UnhandledExceptionFilter.
    //  That means obeying the SetErrorMode flags,
    //  or invoking the Application Error pop-up message box.
    return EXCEPTION_CONTINUE_SEARCH;
}

usage

#include "3rdParty/crash-report.h"

int main(int argc, char *argv[])
{
    CrashReporter crashReporter;
    (void)crashReporter; //prevents unused warnings

    // [application main loop should be here]

    return 0;
}
like image 179
Top-Master Avatar answered Nov 15 '22 23:11

Top-Master