一、异常捕获和dump文件生成
还是简单的说一下吧,各位不了解的也可以看看本人的另一篇博客。也可以直接参考如下:
main.cpp
1 #include "mainwindow.h"
2 #include <QApplication>
3 #include <Windows.h>
4 #include "Login/logindlg.h"
5 #include <DbgHelp.h>
6 #include <tchar.h>
7 #include <qt_windows.h>
8 #pragma comment(lib, "user32.lib")
9 #pragma comment(lib, "dbghelp.lib")
10
11
12 void GetExceptionDescription(DWORD errCode,QString& err)
13 {
14 #if 0
15
16
17 #else
18 // errCode = 0xc0000005;
19 LPTSTR lpMsgBuf = NULL;
20 HMODULE Hand = LoadLibrary(TEXT("ntdll.dll"));
21 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
22 FORMAT_MESSAGE_IGNORE_INSERTS/*FORMAT_MESSAGE_FROM_SYSTEM*/|
23 FORMAT_MESSAGE_FROM_HMODULE,
24 Hand,
25 errCode,
26 MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
27 (LPTSTR)&lpMsgBuf,
28 0,NULL);
29 err = QString::fromWCharArray( lpMsgBuf );
30 qDebug()<<err;
31 LocalFree(lpMsgBuf);
32 #endif
33 }
34
35
36 LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException){//程式异常捕获
37 /*
38 ***保存数据代码***
39 */
40 //创建 Dump 文件
41 qDebug()<<"触发异常!";
42 QString createPath = QCoreApplication::applicationDirPath()+"/Dumps";
43 QDir dir;
44 dir.mkpath(createPath);
45 createPath=QString("%1/dump_%2.dmp").arg(createPath).arg(QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss_zzz"));
46 std::wstring wlpstr = createPath.toStdWString();
47 LPCWSTR lpcwStr = wlpstr.c_str();
48
49 HANDLE hDumpFile = CreateFile(lpcwStr,
50 GENERIC_WRITE,
51 0,
52 NULL,
53 CREATE_ALWAYS,
54 FILE_ATTRIBUTE_NORMAL,
55 NULL);
56 if( hDumpFile != INVALID_HANDLE_VALUE){
57 //Dump信息
58 MINIDUMP_EXCEPTION_INFORMATION dumpInfo;
59 dumpInfo.ExceptionPointers = pException;
60 dumpInfo.ThreadId = GetCurrentThreadId();
61 dumpInfo.ClientPointers = FALSE;
62 //写入Dump文件内容
63 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);
64 }
65 //这里弹出一个错误对话框并退出程序
66 EXCEPTION_RECORD* record = pException->ExceptionRecord;
67 QString errCode(QString::number(record->ExceptionCode,16)),errAdr(QString::number((UINT)((UINT_PTR)record->ExceptionAddress),16));;
68 QString errstr;
69 GetExceptionDescription(record->ExceptionCode,errstr);
70 if(record->NumberParameters>0){
71 if(record->ExceptionInformation[0]==0){
72 errstr+="\r\n访问冲突,线程试图读取不可访问的数据";
73 }else if(record->ExceptionInformation[0]==1){
74 errstr+="\r\n访问冲突,线程尝试写入不可访问的地址";
75 }
76 }
77 QMessageBox::critical(NULL,"程式崩溃","<FONT size=4><div><b>程式崩溃</b><br/></div>"+
78 QString("<div>错误代码:%1</div><div>错误地址:%2</div><div>具体原因:%3</div></FONT>").arg(errCode).arg(errAdr).arg(errstr),
79 QMessageBox::Ok);
80 return EXCEPTION_EXECUTE_HANDLER;
81 }
82
83 int main(int argc, char *argv[])
84 {
85 QApplication a(argc, argv);
86 SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler);//注冊异常捕获函数
87 //唯一性检测
88 QSharedMemory singleton(a.applicationName());
89 if(!singleton.create(1)) { //已经存在的
90 QMessageBox::critical(nullptr, QObject::tr("错误"),
91 QObject::tr("程序已经在运行,请先关闭!"));
92 return -1;
93 }
94 LoginDlg pLdlg;
95 MainWindow w;
96 QObject::connect(&pLdlg,&LoginDlg::sig_sendCurrentLoginUser,&w,&MainWindow::slot_setCurrentLoginUser);
97 if(pLdlg.exec()==QDialog::Accepted){
98 w.show();
99 #if 0
100 return a.exec();
101 #else
102 int ret = a.exec();
103 if (ret == 773) {
104 singleton.detach();
105 QProcess::startDetached(qApp->applicationFilePath(), QStringList());
106 return 0;
107 }
108 return ret;
109 #endif
110 }else{
111 return -1;
112 }
113 }
根据异常代码获取错误描述的函数,自定义的。
1 void GetExceptionDescription(DWORD errCode,QString& err)
异常捕获回调函数,windows系统固定参数的,关于EXCEPTION_POINTERS 异常结果,可以查看MSDN官方文档,有详细的介绍。
1 LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException)
里面用到了唯一性检测(只能打开一个exe程序),以及自动重启的相关代码,需要的可以参考(白嫖…)
二、调试
1.安装Windbg Preview
目前已知该软件唯一安装途径好像只有微软商店,反正博主是从微软商店下载的
2.调试
先手动制造一个异常吧,就0x0000005常见的吧,内存访问冲突,或者你弄一个除0的也可以,然后会在程序当前目录的Dump文件夹下生成一个异常的mini dump文件,如下图:
异常文件:
打开刚才安装的windbg preview,设置一下符号缓存文件路径,以及你自己程序的pdb文件路径,友情提示,Qt在release模式下生成pdb文件需要在pro文件增加如下配置:
1 QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO
2 QMAKE_LFLAGS_RELEASE += $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO
好了,继续我们的调试,配置如下
配置完成之后,将刚才生成的pdb文件拖入command窗口,然后点击自动分析:
此时会处于BUSY状态,从微软服务器下载各种符号文件,等他完成。
之后,可以看到调用堆栈信息,以及错误代码。094(除0错误),因为之前赋值为0了,==改成=了。
1 if(mGridLines=0) mGridLines=1;
2 if(mGridColumns=0) mGridColumns=1;
所以后续调用就出现除0的问题,可以直接看到红色框内,源码第61行有问题,感觉比windows自带的windbg强大太多了。
另外还有个问题,就是通过FormatMessage获取错误码对应的描述的时候,访问冲突会出现如下描述:“0x%p 指令引用了 0x%p 内存。该内存不能为 %s。\r\n”,占位符的参数是否需要通过FormatMessage的最后一个参数va_list传递进去,或者说有其他的方案,能完整显示出具体指令和内存地址,目前还没有解决,虚心请教各位大佬,不胜感激。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了windbg preview的使用以及异常捕获dump文件的调试。博主也是在成长中的菜鸟,文字如有错误,欢迎指正,大家共同探讨。