环境
Clion :2019.3.6
Qt :5.9.6(vc++2015)
编译工具:vs2015 update3
崩溃日志收集
自行百度,会查到很多,一下代码仅供参考(来自https://blog.csdn.net/weixin_45571586/article/details/128697309)
#ifndef OUTPUTDUMP_H //避免同一个文件只会被包含一次#define OUTPUTDUMP_H//#pragma once //避免同一个文件只会被包含一次#include"ccrashstack.h"#include #include #include #include #pragma comment(lib, "dbghelp.lib")//使用注释方式引入库dbghelp.lib或编译目录。/*------------------生成dump文件------------------------*/LONG crashHandler(EXCEPTION_POINTERS *pException){QString curDataTime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");QString dumpName = curDataTime + ".dmp";HANDLE dumpFile = CreateFile((LPCWSTR)QString("./" + dumpName).utf16(),GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);if(dumpFile != INVALID_HANDLE_VALUE){MINIDUMP_EXCEPTION_INFORMATION dumpInfo;dumpInfo.ExceptionPointers = pException;dumpInfo.ThreadId = GetCurrentThreadId();dumpInfo.ClientPointers = TRUE;MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),dumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL);CloseHandle(dumpFile);}else{qDebug() << "dumpFile not vaild";}return EXCEPTION_EXECUTE_HANDLER;}//防止CRT(C runtime)函数报错可能捕捉不到void DisableSetUnhandledExceptionFilter(){void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"), "SetUnhandledExceptionFilter");if(addr){unsigned char code[16];int size = 0;code[size++] = 0x33;code[size++] = 0xC0;code[size++] = 0xC2;code[size++] = 0x04;code[size++] = 0x00;DWORD dwOldFlag, dwTempFlag;VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);}}#endif // OUTPUTDUMP_H
#ifndef OUTPUTLOG_H#define OUTPUTLOG_H//避免同一个文件不会被包含多次 条件编译 满足一定条件下才会被编译//#pragma once //避免同一个文件不会被包含多次#include #include #include #include #include #include"ccrashstack.h"/*---------------打日志文件----------------------*/void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg){static QMutex mutex;mutex.lock();QString text;switch(type){case QtDebugMsg:text = QString("Debug:");break;case QtWarningMsg:text = QString("Warning:");break;case QtCriticalMsg:text = QString("Critical:");break;case QtFatalMsg:text = QString("Fatal:");}QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line);QString current_date_time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");QString current_date = QString("(%1)").arg(current_date_time);QString message = QString("%1 \r\n%2 %3 \r\n%4").arg(current_date).arg(text).arg(context_info).arg(msg);//判断文件夹是否存在,不存在新建QString aFile = QDir::currentPath() + "/LogFile";QDir dir(aFile);if(!dir.exists()){dir.mkdir(aFile);//只创建一级子目录,即必须保证上级目录存在}QString current_time = QDateTime::currentDateTime().toString("yyyyMMdd");QFile file(aFile+"/log"+current_time+".txt");file.open(QIODevice::WriteOnly | QIODevice::Append);QTextStream text_stream(&file);text_stream << message << "\r\n \r\n";file.flush();file.close();mutex.unlock();}#endif // OUTPUTLOG_H
#include "mainwindow.h"#include #include"outputDump.h" //生成dump头文件#include"outputLog.h"//生成日志头文件int main(int argc, char *argv[]){/*-------1、注冊异常捕获函数 生成.dmp文件--------*/SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)crashHandler);DisableSetUnhandledExceptionFilter();QApplication a(argc, argv);/*-------2、注册MessageHandler 生成日志文件--------*/qInstallMessageHandler(outputMessage);MainWindow w;w.show();return a.exec();}
编译输出PDB文件
WinDbg
分析崩溃日志非关键在于,崩溃日志(dmp)文件一定要与pdb文件匹配,否则很难分析到有用信息
将崩溃日志拖入WinDbg中,设置pdb路径
输入:.ecxr 命令
输入:kn 命令
可以看到崩溃时,函数调用栈的信息了,通过上下文分析可以定位到崩溃具体出现的位置。
如果在开发环境中,有时可以定位到源码,非常方便。