Window端Qt Create dmp的生成与解析
生成
.pro 中的配置
在 pro中加入以下内容,否在在 release下 无法生成pdb
QMAKE_LFLAGS_RELEASE = /INCREMENTAL:NO /DEBUG
#加入调试信息
QMAKE_CFLAGS_RELEASE += -g
QMAKE_CXXFLAGS_RELEASE += -g
#禁止优化
QMAKE_CFLAGS_RELEASE -= -O2
QMAKE_CXXFLAGS_RELEASE -= -O2
#release在最后link时默认有"-s”参数,表示"Omit all symbol information from the output file",因此要去掉该参数
QMAKE_LFLAGS_RELEASE = -mthreads #-Wl
LIBS += -lDbgHelp
在main 函数 添加如下代码
头文件
#ifdef Q_OS_WIN
#include <windows.h>
#include <dbghelp.h>
#endif
dmp文件的存儲方法
static LONG WINAPI exceptionCallback(struct _EXCEPTION_POINTERS* exceptionInfo)
{
QCoreApplication *app = QApplication::instance();
QString savePath = app->applicationDirPath() + "dump/";
qDebug()<<"save path :"<<savePath;
QDir dir(savePath);
if (!dir.exists() && !dir.mkpath(savePath)) {
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
savePath.append("assit_");
savePath.append(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
savePath.append(".dmp");
HANDLE dump = CreateFileW(savePath.toStdWString().c_str(), GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == dump) {
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
MINIDUMP_EXCEPTION_INFORMATION miniDumpExceptionInfo;
miniDumpExceptionInfo.ExceptionPointers = exceptionInfo;
miniDumpExceptionInfo.ThreadId = GetCurrentThreadId();
miniDumpExceptionInfo.ClientPointers = TRUE;
DWORD idProcess = GetCurrentProcessId();
MiniDumpWriteDump(GetCurrentProcess(), idProcess, dump,
MiniDumpNormal, &miniDumpExceptionInfo, NULL, NULL);
CloseHandle(dump);
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
mian中調用
#ifdef Q_OS_WIN
SetUnhandledExceptionFilter(exceptionCallback);
#endif
測試方法
void crash() { volatile int* a = (int*)(NULL); *a = 1; }
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#ifdef Q_OS_WIN
SetUnhandledExceptionFilter(exceptionCallback);
#endif
MainWindow w;
w.show();
crash();
return a.exec();
}
完整代碼
#include "mainwindow.h"
#include <QApplication>
#include <QDir>
#include <qdebug.h>
#include <QDateTime>
#include <QFile>
#include <qglobal.h>
#ifdef Q_OS_WIN
#include <windows.h>
#include <dbghelp.h>
#endif
#ifdef Q_OS_WIN
static LONG WINAPI exceptionCallback(struct _EXCEPTION_POINTERS* exceptionInfo)
{
QCoreApplication *app = QApplication::instance();
QString savePath = app->applicationDirPath() + "dump/";
qDebug()<<"save path :"<<savePath;
QDir dir(savePath);
if (!dir.exists() && !dir.mkpath(savePath)) {
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
savePath.append("assit_");
savePath.append(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
savePath.append(".dmp");
HANDLE dump = CreateFileW(savePath.toStdWString().c_str(), GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == dump) {
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
MINIDUMP_EXCEPTION_INFORMATION miniDumpExceptionInfo;
miniDumpExceptionInfo.ExceptionPointers = exceptionInfo;
miniDumpExceptionInfo.ThreadId = GetCurrentThreadId();
miniDumpExceptionInfo.ClientPointers = TRUE;
DWORD idProcess = GetCurrentProcessId();
MiniDumpWriteDump(GetCurrentProcess(), idProcess, dump,
MiniDumpNormal, &miniDumpExceptionInfo, NULL, NULL);
CloseHandle(dump);
app->exit(E_UNEXPECTED);
return EXCEPTION_EXECUTE_HANDLER;
}
#endif
void crash() { volatile int* a = (int*)(NULL); *a = 1; }
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#ifdef Q_OS_WIN
SetUnhandledExceptionFilter(exceptionCallback);
#endif
MainWindow w;
w.show();
crash();
return a.exec();
}
運行之後,我們發現編譯生成的目錄結構如下 可以看到在debugdump 目錄下生成了.dmp
│ .qmake.stash
│ contents.txt
│ list.bat
│ Makefile
│ Makefile.Debug
│ Makefile.Release
│ ui_mainwindow.h
│
├─debug
│ Demo.exe
│ main.o
│ mainwindow.o
│ moc_mainwindow.cpp
│ moc_mainwindow.o
│ moc_predefs.h
│
├─debugdump
│ assit_20200408095624048.dmp
│
└─release
解析
在Window工具目錄下會有如下文件:
D:/Project/DumTools/
| cv2pdb.exe
| dbg_amd64.msi
生成pdb
將編譯運行的程序以及dmp文件拷貝到該文件目錄下,打開終端輸入下入命令
./CV2pdb.exe Demo.exe
之後則會在該目錄下生成pdb,我們會發現文件結構如下:
D:/Project/DumTools/
| assit_20200408100730098.dmp
| cv2pdb.exe
| dbg_amd64.msi
| Demo.exe
| Demo.pdb
安裝windbg.exe
直接點擊該目錄下的dbg_amd64.msi 安裝完成之後,在所按章的目錄下會有一個 windbg.exe 程序。 打開該程序並完成以下配置
依次完成如下配置
打開File 需要完成 Symbol File Path 、Source File Path、Image File Path 的配置
1、Symbol File Path :這裏就是加載pdb文件的路徑,我們直接使用
D:/Project/DumTools/
2、 Source File Path: 加载程序代码 存放的路径(注意切回發佈版本的代碼)
D:/Project/Demo/
3、Image File Path: 加載exe 存放的路徑
D:/Project/DumTools/
4、選擇Open Crash Dump 導入生成的dmp文件
5、 输入命令 !analyze -v ,等待几秒后会打印出错误信息
最終完整的解析信息如下:
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [D:\tiertime_window\window\assit_20200408100730098.dmp]
User Mini Dump File: Only registers, stack and portions of memory are available
WARNING: Minidump contains unknown stream type 0x15
WARNING: Minidump contains unknown stream type 0x16
Symbol search path is: D:\tiertime_window\window
Executable search path is: D:\tiertime_window\window
Windows 7 Version 18362 MP (4 procs) Free x64
Product: WinNt, suite: SingleUserTS
Machine Name:
Debug session time: Wed Apr 8 10:07:30.000 2020 (UTC + 8:00)
System Uptime: not available
Process Uptime: 0 days 0:00:07.000
................................................................
..........................
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(4e04.49f0): Access violation - code c0000005 (first/second chance not available)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
ntdll!ZwGetContextThread+0x14:
00007ffa`2a1dde54 c3 ret
0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for kernel32.dll -
***** OS symbols are WRONG. Please fix symbols to do analysis.
*************************************************************************
*** ***
*** ***
*** Your debugger is not using the correct symbols ***
*** ***
*** In order for this command to work properly, your symbol path ***
*** must point to .pdb files that have full type information. ***
*** ***
*** Certain .pdb files (such as the public OS symbols) do not ***
*** contain the required information. Contact the group that ***
*** provided you with these symbols if you need this command to ***
*** work. ***
*** ***
*** Type referenced: nt!IMAGE_NT_HEADERS32 ***
*** ***
*************************************************************************
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ole32.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for Qt5Core.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for combase.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for SogouPY.ime -
Failed calling InternetOpenUrl, GLE=12029
FAULTING_IP:
Demo!crash+14 [..\Demo\main.cpp @ 56]
00000000`0040191b c70001000000 mov dword ptr [rax],1
EXCEPTION_RECORD: ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000000000040191b (Demo!crash+0x0000000000000014)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 0000000000000001
Parameter[1]: 0000000000000000
Attempt to write to address 0000000000000000
PROCESS_NAME: Demo.exe
ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
MODULE_NAME: Demo
FAULTING_MODULE: 00007ffa2a140000 ntdll
DEBUG_FLR_IMAGE_TIMESTAMP: 5e8d31d9
ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%p
EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%p
EXCEPTION_PARAMETER1: 0000000000000001
EXCEPTION_PARAMETER2: 0000000000000000
WRITE_ADDRESS: 0000000000000000
FOLLOWUP_IP:
Demo!crash+14 [..\Demo\main.cpp @ 56]
00000000`0040191b c70001000000 mov dword ptr [rax],1
MOD_LIST: <ANALYSIS/>
FAULTING_THREAD: 00000000000049f0
BUGCHECK_STR: APPLICATION_FAULT_NULL_POINTER_WRITE_WRONG_SYMBOLS
PRIMARY_PROBLEM_CLASS: NULL_POINTER_WRITE
DEFAULT_BUCKET_ID: NULL_POINTER_WRITE
LAST_CONTROL_TRANSFER: from 0000000000401994 to 000000000040191b
STACK_TEXT:
00000000`0073fce0 00000000`00401994 : 00000000`0073fd20 00000000`00000000 ffffffff`00000056 00000000`00070000 : Demo!crash+0x14 [..\Demo\main.cpp @ 56]
00000000`0073fd00 00000000`00403550 : 00000000`00000001 00000000`001c6f60 00000000`02c02490 00000000`00000056 : Demo!qMain+0x6c [..\Demo\main.cpp @ 72]
00000000`0073fd90 00000000`004013c7 : 00000000`00000000 00000000`00000056 00000000`00409970 00000000`00000000 : Demo!GLOBAL__sub_I.00101__ZN10MainWindow18qt_static_metacallEP7QObjectN11QMetaObject4CallEiPPv+0x18da
00000000`0073fe30 00000000`004014cb : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : Demo!public_all+0x3c7
00000000`0073ff00 00007ffa`29347bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : Demo!public_all+0x4cb
00000000`0073ff30 00007ffa`2a1aced1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14
00000000`0073ff60 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21
STACK_COMMAND: ~0s; .ecxr ; kb
FAULTING_SOURCE_CODE:
52: }
53: #endif
54:
55:
> 56:
57: void crash() { volatile int* a = (int*)(NULL); *a = 1; }
58:
59: int main(int argc, char *argv[])
60: {
61: QApplication a(argc, argv);
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: demo!crash+14
FOLLOWUP_NAME: MachineOwner
IMAGE_NAME: Demo.exe
BUCKET_ID: WRONG_SYMBOLS
FAILURE_BUCKET_ID: NULL_POINTER_WRITE_c0000005_Demo.exe!crash
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/Demo_exe/0_0_0_0/5e8d31d9/Demo_exe/0_0_0_0/5e8d31d9/c0000005/0000191b.htm?Retriage=1
Followup: MachineOwner
---------
可以看到 具體的崩潰代碼行 以及具體的方法。