• Qt 生成dump文件及windbg调试(进阶版)


    一、异常捕获和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文件的调试。博主也是在成长中的菜鸟,文字如有错误,欢迎指正,大家共同探讨。

  • 相关阅读:
    点餐网站学习(EF+MVC)SEO站内结构
    点餐网站学习(EF+MVC)EF工具,自动创建模型并建立数据库映射关系
    个性化定制cms介绍
    EasyUI Munubutton 二级菜单
    程序员也是文艺青年
    EasyUI combobox加入请选择 [.net后台代码]
    LVS配置记录
    查询MYSQL库表使用空间
    python django 数据库操作
    Nginx修改版本信息或隐藏版本号
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/16550995.html
Copyright © 2020-2023  润新知