Window端Qt Create dmp的生成与解析

 2020-04-08 

资源下载

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
---------

可以看到 具體的崩潰代碼行 以及具體的方法。