windows下qt程序意外崩溃,生成dump文件的方法
2019-08-04 10:53:01 颖妹子 阅读数 120更多
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/weixin_38621214/article/details/98448657
程序运行一段时间之后,意外退出,没有提示任何出错信息,这种情况可能是内存泄漏,但是没有提示错误信息,很难定位到具体代码。我们可以生成dump文件,定位出错位置。
在工程中添加代码:
MiniDumper.h
#ifndef MINIDUMP_H
#define MINIDUMP_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
MiniDumper.cpp
#include <Windows.h>
#include "MiniDumper.h"
#include <QtDebug>
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 <hassan_deldar@yahoo.com> 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);
//PrintError(_T("%s"), csOutMessage);
//MessageBoxW( NULL, csOutMessage, m_szAppName , MB_OK );
qDebug() << "Dump Crash file ...";
}
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.cpp中添加如下代码:
MiniDumper dump;
程序意外退出时,在debug或者release下生成dump文件,如下图所示:
双击dmp文件,用vs打开。点击下图中红色箭头指向的“使用 仅限本机进行调试”,即可定位到出错的地方。