軟體除錯
Windows下Qt使用dump定位崩潰位置(1)
目錄
- 軟體除錯
- Windows下Qt使用dump定位崩潰位置(1)
- 1、Qt崩潰定位方法
- 2、 什麼是dump檔案
- 3、使用vs除錯dmp
- 4、下載Windows符號表
- 5、下載Qt符號表
- 6、主要程式碼
- 7、原始碼
更多精彩內容 |
---|
👉個人內容分類彙總 👈 |
👉C++軟體除錯、異常定位 👈 |
本文說的方法只適合Windows下MSVC編譯器(不支援MinGW),如果需要跨平臺可以👉看這一篇
1、Qt崩潰定位方法
方法1: 透過日誌系統儲存程式執行日誌資訊,在程式崩潰後透過日誌資訊可分析出程式進行了哪些操作;
方法2:
- 日誌資訊並不是萬能的,有些情況下日誌資訊不一定能分析出崩潰問題,這時就需要藉助dump檔案進行分析;
- 當程式遇到未處理的異常導致程式崩潰,如果在異常發生之前呼叫了SetUnhandledExceptionFilter() 函式,異常交給函式處理。因而,在程式開始處增加SetUnhandledExceptionFilter()函式,並在函式中利用適當的方法生成Dump檔案,儲存崩潰位置資訊。
2、 什麼是dump檔案
- Dump檔案通常是指程式或系統崩潰時,將記憶體中的資料轉儲並儲存到磁碟檔案中的一種檔案格式。Dump檔案包含了程式崩潰時的記憶體狀態、暫存器狀態、執行緒狀態等資訊,可以幫助開發人員診斷和解決故障。
- Dump檔案一般是以二進位制格式儲存在磁碟上,其內容包含了程式或系統崩潰時記憶體中的所有資料,包括程式碼、資料、棧、堆等。Dump檔案的大小通常很大,可能達到幾百MB或幾GB,因此在進行分析和除錯時需要使用專門的工具和技術。
- 在Windows系統中,dump檔案一般使用Windows的除錯工具WinDbg來分析。WinDbg可以讀取dump檔案,並提供除錯命令和分析工具,幫助開發人員進行故障診斷和除錯。除了WinDbg,還有其他的除錯工具和分析工具可以讀取和分析dump檔案,例如Visual Studio的偵錯程式、QtCreator和第三方工具如IDA Pro等。
3、使用vs除錯dmp
-
開啟vs,選擇繼續但無需程式碼
-
將dmp檔案直接拖如vs中
-
點選1️⃣【設定符號路徑】,進行如下設定;
- 如果是第一次除錯需要勾選Microsoft符號伺服器2️⃣:會從網路下載除錯使用的符號檔案,然後將符號檔案下載到5️⃣位置,以後就不需要勾選符號伺服器了;
- 點選“+”號3️⃣新增【TestCrashHandler.pdb】6️⃣檔案所在路徑4️⃣
-
點選 使用僅限本機進行除錯
-
成功定位到崩潰位置
4、下載Windows符號表
如果勾選了Microsoft符號伺服器或者NuGet.org伺服器則可將window符號表下載到下列路徑中,在離線環境中也可進行除錯。
5、下載Qt符號表
這種方法可以選擇下載部分除錯符號表,體積比較小。
-
選擇系統環境https://download.qt.io/online/qtsdkrepository/
-
選擇desktop
-
選擇安裝的qt版本,我的時5.14.2
-
選擇除錯編譯器版本,我的是msvc2017-64
-
下載需要除錯的模組的符號表
6、主要程式碼
-
預設情況下只有Debug可用生成可用的dmp檔案,Release對程式的編譯進行了最佳化,並且不生成PDB符號檔案,所以無法進行除錯,如果想要Release可用除錯,需要在Pro檔案進行下列設定
# 在Release生成用於除錯dump的資訊,包括【禁用release編譯最佳化】、【生成PDB符號表】,但是這些設定會降低程式效能,和debug差不多 CONFIG(release, debug|release) { QMAKE_CXXFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE += -O0 QMAKE_CXXFLAGS_RELEASE += /Zi QMAKE_LFLAGS_RELEASE += /DEBUG /OPT:REF /OPT:ICF # 生成 PDB符號檔案,功能和下一行一樣,但是最好用這一行,顯示指定編譯選項 # QMAKE_LFLAGS_RELEASE += $$QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO # 列印變數引數值 message(QMAKE_CXXFLAGS_RELEASE變數值:$$QMAKE_CXXFLAGS_RELEASE) message(QMAKE_LFLAGS_RELEASE變數值:$$QMAKE_LFLAGS_RELEASE) }
-
main.cpp
#include "crashhandler.h" #include <QMessageBox> #include <QDateTime> #include <qglobal.h> #ifdef _MSC_VER #include <Windows.h> // Windows.h必須放在DbgHelp.h前,否則編譯會報錯 #include <DbgHelp.h> #endif //MSVC編譯器 #ifdef _MSC_VER #if defined(_MSC_VER) && (_MSC_VER >= 1600) #pragma execution_character_set("utf-8") #endif /** * @brief 應用程式崩潰處理程式 * @param pException * @return EXCEPTION_EXECUTE_HANDLER equ 1 表示我已經處理了異常,可以優雅地結束了 * EXCEPTION_CONTINUE_SEARCH equ 0 表示我不處理,其他人來吧,於是windows呼叫預設的處理程式顯示一個錯誤框,並結束(qt中會導致視窗卡死一段時間) * EXCEPTION_CONTINUE_EXECUTION equ -1 表示錯誤已經被修復,請從異常發生處繼續執行 */ LONG ApplicationCrashHandler(EXCEPTION_POINTERS *pException){//程式異常捕獲 //建立 Dump 檔案 QString strPath = QString("%1.dmp").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss")); #ifdef UNICODE LPCWSTR filePath = reinterpret_cast<LPCWSTR>(strPath.utf16()); #else LPCSTR filePath = reinterpret_cast<LPCSTR>(strPath.toStdString().data()); #endif // !UNICODE HANDLE hDumpFile = CreateFile(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( hDumpFile != INVALID_HANDLE_VALUE){ //Dump資訊 MINIDUMP_EXCEPTION_INFORMATION dumpInfo; dumpInfo.ExceptionPointers = pException; dumpInfo.ThreadId = GetCurrentThreadId(); dumpInfo.ClientPointers = TRUE; //寫入Dump檔案內容 MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL); } //這裡彈出一個錯誤對話方塊並退出程式 EXCEPTION_RECORD* record = pException->ExceptionRecord; QString errCode(QString::number((quint64)record->ExceptionCode, 16)); QString errAdr(QString::number((uint)record->ExceptionAddress, 16)); QMessageBox::critical(nullptr, "程式崩潰","<FONT size=4><div><b>對於發生的錯誤,表示誠摯的歉意</b><br/></div>"+ QString("<div>錯誤程式碼:%1</div><div>錯誤地址:%2</div></FONT>").arg(errCode).arg(errAdr), QMessageBox::Ok); return EXCEPTION_EXECUTE_HANDLER; } #endif void CrashHandler::initCrashHandler() { #ifdef _MSC_VER SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)ApplicationCrashHandler); // 使用win API註冊異常處理函式 #endif }
7、原始碼
gitee
github