天天看點

Qt崩潰生成記憶體鏡像,windows下生成dump檔案,linux下生成core檔案

本文介紹QT程式在崩潰時生成記憶體鏡像檔案,windows下生成的叫dump檔案,linux下生成的叫core檔案。

linux環境生成core檔案

linux環境下崩潰生成的是core檔案,系統預設不生成;

ulimit -c,傳回0既是不生成core檔案;

ulimit -c unlimited,設定目前終端生成不限制大小的core檔案;

設定整個系統自動生成core檔案,編輯/root/.bash_profile檔案,在其中加入ulitmit -S -c unlimited,執行source /root/.bash_profile立即生效;

在qt的pro檔案添加如下内容

QMAKE_CC += -g
QMAKE_CXX += -g
QMAKE_LINK += -g
           

若qt程式崩潰,自動在可執行程式目錄生成core檔案;

core檔案檢視

gdb ./testdump //gdb打開可執行檔案

core-file core //打開core檔案

bt //檢視崩潰時的堆棧資訊

如下圖,程式是在mainwindow.cpp的第13行崩潰的。

Qt崩潰生成記憶體鏡像,windows下生成dump檔案,linux下生成core檔案

windows環境生成dump檔案

項目中添加mdump.h和mdump.cpp,在main函數中執行個體化MiniDumper dump即可;

程式崩潰時自動在可執行程式目錄生成*.dump檔案,使用vs打開,點選使用本機進行調試,即可打開代碼,中斷在崩潰的位置。

mdump.h

#ifndef MDUMP1_H
#define MDUMP1_H

#include <Windows.h>
#include <DbgHelp.h>

// based on dbghelp.h
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
                                    CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
                                    CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
                                    CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
                                    );

#define MAX_WARNING_MESSAGE_PATH 1024

class MiniDumper
{
private:
    static LPCWSTR m_szAppName;

    static LPWSTR m_szAppVersion;

    static LPWSTR m_szAppBuildNumber;

    static WCHAR m_szMessageText[MAX_WARNING_MESSAGE_PATH];

    static LPWSTR m_szDumpFilePath;

    static LONG WINAPI TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo );

public:
    MiniDumper( );
    ~MiniDumper();
    static void SetVersion(LPCWSTR szVersion);
    static void SetBuildNumber(LPCWSTR szBuildNumber);
    static void SetDumpFilePath(LPCWSTR szFilePath);
    static int SetWarningMessage(LPCWSTR szMessageText)
    {
        if(szMessageText)
        {
            int iLen = wcslen(szMessageText);
            if(iLen < MAX_WARNING_MESSAGE_PATH - MAX_PATH)
            {
                wcscpy(m_szMessageText,szMessageText);
                return 0;
            }
        }
        return 1;
    }
};


#endif

           

mdump.cpp

#include <Windows.h>
#include "mdump.h"
#include <QtDebug>
#include <QFile>

LPCWSTR MiniDumper::m_szAppName;

LPWSTR MiniDumper::m_szAppVersion;

LPWSTR MiniDumper::m_szAppBuildNumber;

WCHAR MiniDumper::m_szMessageText[MAX_WARNING_MESSAGE_PATH];

LPWSTR MiniDumper::m_szDumpFilePath;

#define DEFAULT_ENGLISH_MESSAGE_TEXT L"%s experienced an unknown error and had to exit. \nHowever, some error information has been saved in %s. \nPlease, email this file to <[email protected]> if you would like to help us debug the problem."

#define MAX_DUMP_FILE_NUMBER 9999


//static int DUMP_TYPE_MINI = MiniDumpWithUnloadedModules;

//static int DUMP_TYPE_MIDD = MiniDumpWithUnloadedModules | MiniDumpWithIndirectlyReferencedMemory;

static int DUMP_TYPE_FULL = MiniDumpNormal | MiniDumpWithFullMemory | MiniDumpWithDataSegs | MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithProcessThreadData;

//static int DUMP_TYPE_FULL = MiniDumpNormal;
//預設值是隻有 MiniDumpNormal 檔案比較小
//如果把所有的選項都加上, 檔案很大, 本機調試也沒關系


MiniDumper::MiniDumper()
{
    // if this assert fires then you have two instances of MiniDumper
    // which is not allowed
    Q_ASSERT( m_szAppName==NULL );

    m_szAppName =  wcsdup(L"iLadarDataCollect");
    m_szAppVersion = wcsdup( L"CrashDump");
    m_szAppBuildNumber = wcsdup( L"0000");

    wcscpy(m_szMessageText,DEFAULT_ENGLISH_MESSAGE_TEXT);


    m_szDumpFilePath = NULL;
    ::SetUnhandledExceptionFilter( TopLevelFilter );
}

MiniDumper::~MiniDumper()
{
}

void MiniDumper::SetVersion(LPCWSTR szVersion)
{
    if(szVersion)
    {
        free(m_szAppVersion);
        m_szAppVersion = wcsdup(szVersion);
    }
}

void MiniDumper::SetBuildNumber(LPCWSTR szBuildNumber)
{
    if(szBuildNumber)
    {
        free(m_szAppBuildNumber);
        m_szAppBuildNumber = wcsdup(szBuildNumber);
    }
}

void MiniDumper::SetDumpFilePath(LPCWSTR szFilePath)
{
    free(m_szDumpFilePath);
    m_szDumpFilePath = NULL;
    if(szFilePath != NULL)
    {
        m_szDumpFilePath = wcsdup(szFilePath);
    }
}

LONG MiniDumper::TopLevelFilter( struct _EXCEPTION_POINTERS *pExceptionInfo )
{

    LONG retval = EXCEPTION_CONTINUE_SEARCH;
    HWND hParent = NULL;						// find a better value for your app

    // firstly see if dbghelp.dll is around and has the function we need
    // look next to the EXE first, as the one in System32 might be old
    // (e.g. Windows 2000)
    HMODULE hDll = NULL;
    WCHAR szDbgHelpPath[_MAX_PATH];

    if (GetModuleFileName( NULL, szDbgHelpPath, _MAX_PATH ))
    {
        WCHAR *pSlash = wcsrchr( szDbgHelpPath, L'\\');
        if (pSlash)
        {
            wcscpy( pSlash+1, L"DBGHELP.DLL" );
            hDll = ::LoadLibrary( szDbgHelpPath );
        }
    }

    if (hDll==NULL)
    {
        // load any version we can
        hDll = ::LoadLibrary( L"DBGHELP.DLL");
    }

    LPCWSTR szResult = NULL;

    if (hDll)
    {
        MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress( hDll, "MiniDumpWriteDump" );
        if (pDump)
        {
            WCHAR szDumpPath[_MAX_PATH];
            WCHAR szDumpRootPath[_MAX_PATH];
            WCHAR szScratch[_MAX_PATH];

            // work out a good place for the dump file

            if(m_szDumpFilePath == NULL)
            {
                if (GetModuleFileName(NULL, szDbgHelpPath, _MAX_PATH))
                {
                    WCHAR *pSlash = wcsrchr(szDbgHelpPath, L'\\');
                    if (pSlash)
                    {
                        wcscpy(pSlash + 1, L"");
                        wcscpy(szDumpPath, szDbgHelpPath);
                    }
                }
                else if (!GetTempPath( _MAX_PATH, szDumpPath ))
                    wcscpy( szDumpPath, L"c:\\temp\\" );
            }
            else
            {
                wcscpy( szDumpPath, m_szDumpFilePath );
            }
            wcscpy( szDumpRootPath, szDumpPath);

            //PrintDebug(L"[MiniDumper] Mini Dump file:[%s]",szDumpPath);

            // ask the user if they want to save a dump file
            //if (::MessageBox( NULL, _T("Something bad happened in your program, would you like to save a diagnostic file?"), m_szAppName, MB_YESNO )==IDYES)
            {
                HANDLE hFile = INVALID_HANDLE_VALUE;
                int i = 1;
                WCHAR szFileNumber[_MAX_PATH];
                while(hFile == INVALID_HANDLE_VALUE)
                {
                    swprintf(szFileNumber, sizeof(szFileNumber), L"_%04d",i);
                    wcscpy( szDumpPath, szDumpRootPath);
                    wcscat( szDumpPath, m_szAppName );
                    wcscat( szDumpPath, L"_" );
                    wcscat( szDumpPath, m_szAppVersion);
                    wcscat( szDumpPath, L"_" );
                    wcscat( szDumpPath, m_szAppBuildNumber);
                    wcscat( szDumpPath, szFileNumber);
                    wcscat( szDumpPath, L".dmp" );
                    hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW,
                                            FILE_ATTRIBUTE_NORMAL, NULL );
                    i++;
                    if(i > MAX_DUMP_FILE_NUMBER)
                    {
                        hFile = CreateFile( szDumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,
                                            FILE_ATTRIBUTE_NORMAL, NULL );
                        break;
                    }
                }
                // create the file

                if (hFile!=INVALID_HANDLE_VALUE)
                {
                    _MINIDUMP_EXCEPTION_INFORMATION ExInfo;

                    ExInfo.ThreadId = GetCurrentThreadId();
                    ExInfo.ExceptionPointers = pExceptionInfo;
                    ExInfo.ClientPointers = NULL;

                    // write the dump
                    BOOL bOK = pDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, (MINIDUMP_TYPE)DUMP_TYPE_FULL, &ExInfo, NULL, NULL );
                    if (bOK)
                    {
                        swprintf( szScratch, sizeof(szScratch), L"Saved dump file to '%s'", szDumpPath );
                        szResult = szScratch;
                        retval = EXCEPTION_EXECUTE_HANDLER;
                    }
                    else
                    {
                        swprintf( szScratch, sizeof(szScratch),L"Failed to save dump file to '%s' (error %d)", szDumpPath, GetLastError() );
                        szResult = szScratch;
                    }
                    CloseHandle(hFile);

                    WCHAR csOutMessage[MAX_WARNING_MESSAGE_PATH];
                    swprintf(csOutMessage, sizeof(csOutMessage), m_szMessageText, m_szAppName, szDumpPath);

                    qDebug() << "Dump Crash file ...";
                    qDebug()<<"["<<__FILE__<<"]"<<__LINE__<<__FUNCTION__<<"崩潰了 ";
                }
                else
                {
                    swprintf( szScratch, sizeof(szScratch),L"Failed to create dump file '%s' (error %d)", szDumpPath, GetLastError() );
                    szResult = szScratch;
                }
            }

        }
        else
        {
            szResult = L"DBGHELP.DLL too old";
        }
    }
    else
    {
        szResult = L"DBGHELP.DLL not found";
    }

    if (szResult)
    {
        //PrintDebug(_T("[MiniDumper] Mini Dump result:[%s]"),szResult);
    }

    return retval;
}

           

main函數

#include "mdump.h"
MiniDumper dump;
           

繼續閱讀