Qt_vc++崩溃日志分析

环境

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 <shlobj.h>
#include <QDebug>
#include <DbgHelp.h>
#include <QDateTime>
#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 <QDir>
#include <QFile>
#include <QMutex>
#include <QTextStream>
#include <QTime>

#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 <QApplication>
#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 命令

在这里插入图片描述

可以看到崩溃时,函数调用栈的信息了,通过上下文分析可以定位到崩溃具体出现的位置。

如果在开发环境中,有时可以定位到源码,非常方便。

相关推荐

  1. Android 收集崩溃(crash)日志并输出到本地

    2024-03-15 02:26:03       66 阅读
  2. 查看 iOS 系统的日志崩溃日志

    2024-03-15 02:26:03       55 阅读
  3. 如何获取iOS手机上的APP崩溃日志

    2024-03-15 02:26:03       36 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-15 02:26:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-15 02:26:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-15 02:26:03       87 阅读
  4. Python语言-面向对象

    2024-03-15 02:26:03       96 阅读

热门阅读

  1. UE4游戏传奇4SDK之角色类型跟门票类型检测

    2024-03-15 02:26:03       41 阅读
  2. 突破编程_C++_设计模式(模板方法模式)

    2024-03-15 02:26:03       31 阅读
  3. 大脑和人工智能克服遗忘

    2024-03-15 02:26:03       36 阅读
  4. Flask学习(二):flask模板渲染

    2024-03-15 02:26:03       44 阅读
  5. docker部署keepalived(搭建keepalived)

    2024-03-15 02:26:03       34 阅读
  6. 日常开发有用到临时表吗?

    2024-03-15 02:26:03       41 阅读
  7. uView Calendar 日历

    2024-03-15 02:26:03       33 阅读
  8. react native使用TS实现路由

    2024-03-15 02:26:03       37 阅读
  9. 洛谷 B3625 迷宫寻路

    2024-03-15 02:26:03       39 阅读
  10. 修复Jenkins fossa扫描的时候报错的问题

    2024-03-15 02:26:03       45 阅读
  11. 24计算机考研调剂 | 浙江工商大学【官方】

    2024-03-15 02:26:03       44 阅读