Qt Mingw 创建dump 并查找crash 出错行

发布时间:2026/7/26 19:06:40
Qt Mingw 创建dump 并查找crash 出错行 前言客户现场跑的程序有可能存在长时间运行挂掉的情况而无法复现的话无法更好的查找问题原因。所以研究了一下window下程序程序调试crash的方法。该本是介绍qt mingw 的。1. 在PRO文件中加入调试信息可能导致exe增大LIBS -lDbgHelp QMAKE_CXXFLAGS_RELEASE -g QMAKE_CFLAGS_RELEASE -g QMAKE_LFLAGS_RELEASE -mthreads -Wl, #其中最后的逗号注意添加如果不添加可能编译不过 #禁止优化 QMAKE_CFLAGS_RELEASE - -O2 QMAKE_CXXFLAGS_RELEASE - -O22、dump生成类的.h文件/** * projectName * file ccrashstack * brief 记录崩溃日志 * date 2022-08-08 */ #ifndef CCRASHSTACK_H #define CCRASHSTACK_H #include windows.h #include QString class CCrashStack { private: PEXCEPTION_POINTERS m_pException; private: QString GetModuleByRetAddr(PBYTE Ret_Addr, PBYTE Module_Addr); QString GetCallStack(PEXCEPTION_POINTERS pException); QString GetVersionStr(); bool GetHardwareInaformation(QString graphics_card, QString sound_deivce); public: CCrashStack(PEXCEPTION_POINTERS pException); QString GetExceptionInfo(); }; #endif // CCRASHSTACK_H3、记录崩溃日志类的.cpp文件#include ccrashstack.h #include tlhelp32.h #include stdio.h #define _WIN32_DCOM #include comdef.h #include wbemidl.h //#includebase/constants.h #include qdebug.h CCrashStack::CCrashStack(PEXCEPTION_POINTERS pException) { m_pException pException; } QString CCrashStack::GetModuleByRetAddr(PBYTE Ret_Addr, PBYTE Module_Addr) { MODULEENTRY32 M {sizeof(M)}; HANDLE hSnapshot; wchar_t Module_Name[MAX_PATH] {0}; hSnapshot CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); if ((hSnapshot ! INVALID_HANDLE_VALUE) Module32First(hSnapshot, M)) { do { if (DWORD(Ret_Addr - M.modBaseAddr) M.modBaseSize) { lstrcpyn(Module_Name, M.szExePath, MAX_PATH); Module_Addr M.modBaseAddr; break; } } while (Module32Next(hSnapshot, M)); } CloseHandle(hSnapshot); QString sRet QString::fromWCharArray(Module_Name); return sRet; } QString CCrashStack::GetCallStack(PEXCEPTION_POINTERS pException) { PBYTE Module_Addr_1; char bufer[256]{0}; QString sRet; typedef struct STACK { STACK *Ebp; PBYTE Ret_Addr; DWORD Param[0]; } STACK, *PSTACK; STACK Stack {0, 0}; PSTACK Ebp; if (pException) //fake frame for exception address { Stack.Ebp (PSTACK)pException-ContextRecord-Rbp; Stack.Ret_Addr (PBYTE)pException-ExceptionRecord-ExceptionAddress; Ebp Stack; } else { Ebp (PSTACK)pException - 1; //frame addr of Get_Call_Stack() // Skip frame of Get_Call_Stack(). if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) Ebp Ebp-Ebp; //caller ebp } // Break trace on wrong stack frame. for (; !IsBadReadPtr(Ebp, sizeof(PSTACK)) !IsBadCodePtr(FARPROC(Ebp-Ret_Addr)); Ebp Ebp-Ebp) { // If module with Ebp-Ret_Addr found. memset(bufer,0, sizeof(0)); sprintf(bufer, \n%08X , (Ebp-Ret_Addr)); sRet.append(bufer); QString moduleName this-GetModuleByRetAddr(Ebp-Ret_Addr, Module_Addr_1) ; if (moduleName.length() 0) { sRet.append(moduleName); } } return sRet; } //Get_Call_Stack QString CCrashStack::GetVersionStr() { OSVERSIONINFOEX V {sizeof(OSVERSIONINFOEX)}; //EX for NT 5.0 and later if (!GetVersionEx((POSVERSIONINFO)V)) { ZeroMemory(V, sizeof(V)); V.dwOSVersionInfoSize sizeof(OSVERSIONINFO); GetVersionEx((POSVERSIONINFO)V); } if (V.dwPlatformId ! VER_PLATFORM_WIN32_NT) V.dwBuildNumber LOWORD(V.dwBuildNumber); //for 9x HIWORD(dwBuildNumber) 0x04xx QString sRet; sRet.append(QString(Windows: %1.%2.%3, SP %4.%5, Product Type %6\n) .arg(V.dwMajorVersion).arg(V.dwMinorVersion).arg(V.dwBuildNumber) .arg(V.wServicePackMajor).arg(V.wServicePackMinor).arg(V.wProductType)); return sRet; } QString CCrashStack::GetExceptionInfo() { WCHAR Module_Name[MAX_PATH]; PBYTE Module_Addr; QString sRet; char buffer[512]{0}; QString sTmp GetVersionStr(); sRet.append(sTmp); sRet.append(Process: ); GetModuleFileName(NULL, Module_Name, MAX_PATH); sRet.append(QString::fromWCharArray(Module_Name)); sRet.append(\n); // If exception occurred. if (m_pException) { EXCEPTION_RECORD E *m_pException-ExceptionRecord; CONTEXT C *m_pException-ContextRecord; memset(buffer, 0, sizeof(buffer)); sprintf(buffer, Exception Addr: %08X , E.ExceptionAddress); sRet.append(buffer); // If module with E.ExceptionAddress found - save its path and date. QString module GetModuleByRetAddr((PBYTE)E.ExceptionAddress, Module_Addr); if (module.length() 0) { sRet.append( Module: ); sRet.append(module); } memset(buffer, 0, sizeof(buffer)); sprintf(buffer, \nException Code: %08X\n, (int)E.ExceptionCode); sRet.append(buffer); if (E.ExceptionCode EXCEPTION_ACCESS_VIOLATION) { // Access violation type - Write/Read. memset(buffer, 0, sizeof(buffer)); sprintf(buffer,%s Address: %08X\n, (E.ExceptionInformation[0]) ? Write : Read, (int)E.ExceptionInformation[1]); sRet.append(buffer); } sRet.append(Instruction: ); for (int i 0; i 16; i) { memset(buffer, 0, sizeof(buffer)); sprintf(buffer, %02X, PBYTE(E.ExceptionAddress)[i]); sRet.append(buffer); } sRet.append(\nRegisters: ); memset(buffer, 0, sizeof(buffer)); sprintf(buffer, \nRAX: %08X RBX: %08X RCX: %08X RDX: %08X, (unsigned int)C.Rax,(unsigned int) C.Rbx, (unsigned int)C.Rcx, (unsigned int)C.Rdx); sRet.append(buffer); memset(buffer, 0, sizeof(buffer)); sprintf(buffer, \nRSI: %08X RDI: %08X RSP: %08X RBP: %08X, (unsigned int)C.Rsi, (unsigned int)C.Rdi, (unsigned int)C.Rsp, (unsigned int)C.Rbp); sRet.append(buffer); memset(buffer, 0, sizeof(buffer)); sprintf(buffer, \nRIP: %08X RFlags: %08X, (unsigned int)C.Rip,(unsigned int) C.EFlags); sRet.append(buffer); } //if (pException) sRet.append(\nCall Stack:); QString sCallstack this-GetCallStack(m_pException); sRet.append(sCallstack); return sRet; } #if 0 bool CCrashStack::GetHardwareInaformation(QString graphics_card, QString sound_deivce) { HRESULT hres; // Initialize COM. hres CoInitializeEx(0, COINIT_APARTMENTTHREADED); if (FAILED(hres)) { qDebug() Failed to initialize COM library. Error code 0x hex hres endl; return false; } // Initialize hres CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if ((hres ! RPC_E_TOO_LATE) FAILED(hres)) { qDebug() Failed to initialize security. Error code 0x hex hres endl; CoUninitialize(); return false; } // Obtain the initial locator to Windows Management // on a particular host computer. IWbemLocator *pLoc 0; hres CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)pLoc); if (FAILED(hres)) { qDebug() Failed to create IWbemLocator object. Error code 0x hex hres endl; CoUninitialize(); return false; } IWbemServices *pSvc 0; // Connect to the root\cimv2 namespace with the // current user and obtain pointer pSvc // to make IWbemServices calls. hres pLoc-ConnectServer(_bstr_t(LROOT\\CIMV2), NULL, NULL, 0, NULL, 0, 0, pSvc); if (FAILED(hres)) { qDebug() Could not connect. Error code 0x hex hres endl; pLoc-Release(); CoUninitialize(); return false; } // Set the IWbemServices proxy so that impersonation // of the user (client) occurs. hres CoSetProxyBlanket( pSvc, // the proxy to set RPC_C_AUTHN_WINNT, // authentication service RPC_C_AUTHZ_NONE, // authorization service NULL, // Server principal name RPC_C_AUTHN_LEVEL_CALL, // authentication level RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level NULL, // client identity EOAC_NONE // proxy capabilities ); if (FAILED(hres)) { qDebug() Could not set proxy blanket. Error code 0x hex hres endl; pSvc-Release(); pLoc-Release(); CoUninitialize(); return false; } // Use the IWbemServices pointer to make requests of WMI. // Make requests here: IEnumWbemClassObject* pEnumerator_graphics NULL; IEnumWbemClassObject* pEnumerator_sound NULL; BSTR wql SysAllocString(LWQL); BSTR sql_graphics SysAllocString(LSELECT * FROM Win32_VideoController); BSTR sql_sound SysAllocString(LSELECT * FROM Win32_SoundDevice); HRESULT hres_graphics; HRESULT hres_sound; hres_graphics pSvc-ExecQuery(wql, sql_graphics, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, pEnumerator_graphics); hres_sound pSvc-ExecQuery(wql, sql_sound, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, pEnumerator_sound); if (FAILED(hres_graphics) || FAILED(hres_sound)) { qDebug() Query for processes failed. Error code 0x hex hres_graphics endl; qDebug() Query for processes failed. Error code 0x hex hres_sound endl; pSvc-Release(); pLoc-Release(); CoUninitialize(); return ; } else { IWbemClassObject *pclsObj_graphics; ULONG uReturnGraphics 0; IWbemClassObject *pclsObj_sound; ULONG uReturnSound 0; while (pEnumerator_graphics) { hres_graphics pEnumerator_graphics-Next(WBEM_INFINITE, 1, pclsObj_graphics, uReturnGraphics); if (0 uReturnGraphics) { break; } VARIANT description_vtProp; VARIANT driver_version_vtProp; VARIANT status_vtProp; // Get the value of the Name property hres_graphics pclsObj_graphics-Get(LDescription, 0, description_vtProp, 0, 0); QString description((QChar*) description_vtProp.bstrVal, wcslen(description_vtProp.bstrVal)); hres_graphics pclsObj_graphics-Get(LDriverVersion, 0, driver_version_vtProp, 0, 0); QString driver_version((QChar*) driver_version_vtProp.bstrVal, wcslen(driver_version_vtProp.bstrVal)); hres_graphics pclsObj_graphics-Get(LStatus, 0, status_vtProp, 0, 0); QString status((QChar*) status_vtProp.bstrVal, wcslen(status_vtProp.bstrVal)); graphics_card.append(description).append( ).append(driver_version).append( ).append(status).append( \n); VariantClear(description_vtProp); VariantClear(driver_version_vtProp); VariantClear(status_vtProp); } while (pEnumerator_sound) { hres_sound pEnumerator_sound-Next(WBEM_INFINITE, 1, pclsObj_sound, uReturnSound); if (0 uReturnSound) { break; } VARIANT description_vtProp; VARIANT status_vtProp; // Get the value of the Name property hres_sound pclsObj_sound-Get(LDescription, 0, description_vtProp, 0, 0); QString description((QChar*) description_vtProp.bstrVal, wcslen(description_vtProp.bstrVal)); hres_sound pclsObj_sound-Get(LStatus, 0, status_vtProp, 0, 0); QString status((QChar*) status_vtProp.bstrVal, wcslen(status_vtProp.bstrVal)); sound_deivce.append(description).append( ).append(status).append( \n); VariantClear(description_vtProp); VariantClear(status_vtProp); } } // Cleanup pSvc-Release(); pLoc-Release(); CoUninitialize(); return true; } #endif4、引用记录崩溃类的main.cpp#include mainwindow.h #include QApplication #include QtCore/QCoreApplication #include QtCore/QDebug #include windows.h #include signal.h #include dbghelp.h #include QDateTime #include QDir #include ccrashstack.h #ifdef Q_OS_WIN long __stdcall callback(_EXCEPTION_POINTERS* excp) { CCrashStack crashStack(excp); QString sCrashInfo crashStack.GetExceptionInfo(); QString file_path QApplication::applicationDirPath(); QDir *folder_path new QDir(); bool exist folder_path-exists(file_path.append(/Dumplog )); if(!exist) { folder_path-mkdir(file_path); } delete folder_path; folder_path nullptr; QDateTime dateTime QDateTime::currentDateTime(); QString baseFileName /crash dateTime.toString(yyyyMMddhhmmss) .log; QString sFileName file_path baseFileName; QFile file(sFileName); if (file.open(QIODevice::WriteOnly|QIODevice::Truncate)) { file.write(sCrashInfo.toUtf8()); file.close(); } return EXCEPTION_EXECUTE_HANDLER; } #endif int main(int argc, char *argv[]) { // 设置异常处理函数 #ifdef Q_OS_WIN SetUnhandledExceptionFilter(callback); #endif QApplication a(argc, argv); MainWindow w; w.show(); qDebug() Before crash.; //模拟崩溃 int *p nullptr; *p 0; qDebug() After crash.; return a.exec(); }5、查看产生的崩溃log例如Windows: 6.2.9200, SP 0.0, Product Type 1 Process: E:\build-testwe-Desktop_Qt_5_12_12_MinGW_64_bit-Debug\debug\testwe.exe Exception Addr: 00402776 Module: E:\build-testwe-Desktop_Qt_5_12_12_MinGW_64_bit-Debug\debug\testwe.exe Exception Code: C0000005 Write Address: 00000000 Instruction: C7 00 00 00 00 00 48 8D 45 30 4C 8D 0D 19 9B 00 Registers: RAX: 00000000 RBX: 1F606AE0 RCX: 1F600000 RDX: 1F600000 RSI: 00000001 RDI: 1F606B00 RSP: 0079FC90 RBP: 0079FD10 RIP: 00402776 RFlags: 00010202 Call Stack: 00402776 E:\build-testwe-Desktop_Qt_5_12_12_MinGW_64_bit-Debug\debug\testwe.exe 0040C268 E:\build-testwe-Desktop_Qt_5_12_12_MinGW_64_bit-Debug\debug\testwe.exe在QT安装路径下找到分析工具addr2line.exe

相关新闻