资源下载
Window端Qt Create dmp的生成与解析
生成
.pro 中的配置
在 pro中加入以下内容,否在在 release下 无法生成pdb
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 函数 添加如下代码
头文件
1 2 3 4 | #ifdef Q_OS_WIN #include <windows.h> #include <dbghelp.h> #endif |
dmp文件的存儲方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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中調用
1 2 3 | #ifdef Q_OS_WIN SetUnhandledExceptionFilter(exceptionCallback); #endif |
測試方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(); } |
完整代碼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #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工具目錄下會有如下文件:
1 2 3 | D:/Project/DumTools/ | cv2pdb.exe | dbg_amd64.msi |
生成pdb
將編譯運行的程序以及dmp文件拷貝到該文件目錄下,打開終端輸入下入命令
1 | ./CV2pdb.exe Demo.exe |
之後則會在該目錄下生成pdb,我們會發現文件結構如下:
1 2 3 4 5 6 | 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文件的路徑,我們直接使用
1 | D:/Project/DumTools/ |
2、 Source File Path: 加载程序代码 存放的路径(注意切回發佈版本的代碼)
1 | D:/Project/Demo/ |
3、Image File Path: 加載exe 存放的路徑
1 | D:/Project/DumTools/ |
4、選擇Open Crash Dump 導入生成的dmp文件
5、 输入命令 !analyze -v ,等待几秒后会打印出错误信息
最終完整的解析信息如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | 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 --------- |
可以看到 具體的崩潰代碼行 以及具體的方法。