当进程崩溃时,生成崩溃转储的最佳方法是什么?

13
Windows 环境下(XPWin 7):
  • 当进程在系统上崩溃时,最好的自动生成崩溃转储的方法是什么?
  • 一个安装程序 (MSI) 包可以做到这一点吗?

这是一个全局设置。单个程序的安装程序绝对不应更改全局设置。如果您的程序需要崩溃转储,请将逻辑放入程序中。 - MSalters
3个回答

17

在Windows上自动转储任何/特定进程的最佳方法之一是配置注册表中一组条目。我在64位Windows 7上尝试了以下内容。

打开notepad.exe,粘贴以下内容并将其保存为“EnableDump.reg”。您可以随意命名。

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps]
"DumpFolder"=hex(2):44,00,3a,00,5c,00,64,00,75,00,6d,00,70,00,00,00
"DumpCount"=dword:00000010
"DumpType"=dword:00000002
"CustomDumpFlags"=dword:00000000

双击 "EnableDump.reg" 并选择 '是'。 我已经将转储文件夹设置为 'd:\dump'。 您可以将其更改为任何您想要的文件夹。

尝试执行一个崩溃的应用程序,Windows 将显示错误对话框。 选择 '关闭程序' 选项。 之后,您将在配置的文件夹中看到转储文件。 转储文件的名称将是.exe..dmp。

有关详细信息,您可以参考下面的链接。

http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx


只需在XP上尝试一下。您可以编写一个C++控制台应用程序并粘贴以下代码。int main( void ) { char pp; char tpp; strncpy( pp, tpp, 5000 ); return 0; }运行该应用程序,它将崩溃。关闭Windows错误对话框。检查配置的文件夹以获取转储文件。 - MNS
根据微软文档,它仅适用于以下平台:Windows Server 2008和Windows Vista with Service Pack 1 (SP1)。 - MNS
是的,除以零将会起作用,只要你为除以零取消浮点异常屏蔽。默认情况下,运行时库将屏蔽所有浮点异常。 - MNS
似乎在Windows 7 Enterprise 64位上无法正常工作。 - Igor Meszaros
1
@IgorMesaros:在 Windows 7 专业版 64 位上运行良好。据我所知,在此情况下,企业版并没有任何区别。 - MNS
DumpType设置为0(自定义dump)时,似乎只使用CustomDumpFlags。如果使用DumpType 2(完整dump),则不需要设置CustomDumpFlags - Ivan Chau

4
以下解释基于另一个答案,但逻辑是我的(无需归属,如我个人资料中所说);
拥有自己的转储生成框架,当遇到任何未处理的异常时自动创建进程转储,可以避免客户安装WinDbg。
在应用程序启动时使用SetUnhandledExceptionFilter(...) Win32 API注册回调(即应用程序级别的异常处理程序)。现在每当有任何未处理的异常时都会调用已注册的回调函数。然后,您可以使用DbgHelp.dll中的MiniDumpWriteDump(...) API创建进程转储。
C++示例(启用unicode)
头文件
#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

源文件

#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;
}

使用方法

#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;
}

2

Windows XP: 以下步骤可启用自动崩溃转储:

1) Open a command prompt, running as administrator
2) Run drwtsn32 -i. This will install Doctor Watson as the default debugger when something crashes
3) Click Ok
4) From the command prompt, run drwtsn32
5) Set the Crash Dump path to your favorite directory, or leave the default.
6) Set the Crash Dump Type to mini. Note that under some circumstances, we may ask you for a full crash dump.
7) Make sure the Dump All Thread Contexts and Create Crash Dump File options are selected.
8) Click Ok
9) If a user.dmp file already exists in the Crash Dump path, delete it.

Windows 7操作系统:位置位于:

C:\Users[Current User when app crashed]\AppData\Local\Microsoft\Windows\WER\ReportArchive

这个配置可以应用于MSI安装包吗? - CJ7
在什么情况下?您是想让程序输出错误信息吗? - Chelseawillrecover
是的,我希望崩溃时生成崩溃转储。这可能是一个MSI安装程序可以应用的注册表更改。 - CJ7
你是指所有崩溃的进程还是你开发的一个进程/程序? - Chelseawillrecover
我想为我的程序生成崩溃转储。 - CJ7
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接