前言客户现场跑的程序有可能存在长时间运行挂掉的情况而无法复现的话无法更好的查找问题原因。所以研究了一下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
企业数字化 ERP 产品动态
相关推荐
改造mapus过程中学习到JavaScript语言技巧 好多方法要求是对象,而对于数组,则不适用。 1.判断对象是否为空function isEmptyObj(obj) {return Object.keys(obj).length 0
}
console.log(对象是否为空:, isEmptyObj({}))2.Object.keys用法要求是对象,不能是数组 3.async和a… · 2026/11/2 9:40:39
JVM 之 JIT CICompilerCount · 2026/9/27 19:14:48
Elasticsearch构建RAG系统:提升AI生成准确性的实战方案 1. 项目概述RAG(Retrieval-Augmented Generation)是当前AI领域最热门的技术方向之一,它通过将检索系统与生成模型相结合,显著提升了生成式AI的准确性和事实性。而Elasticsearch作为企业级搜索引擎的标杆,其强大的全文检… · 2026/10/25 20:27:28
Hermes Agent与自动驾驶仿真平台集成:CARLA与LGSVL Simulator完整指南 Hermes Agent与自动驾驶仿真平台集成:CARLA与LGSVL Simulator完整指南
Hermes Agent是一款功能强大的开源AI代理工具,能够自主执行各类任务并不断学习成长。本文将详细介绍如何将Hermes Agent与主流自动驾驶仿真平台CARLA和LGSVL Simulator进行集成&… · 2026/11/4 19:19:41
Hermes Agent与区块链智能合约测试框架:Truffle与Hardhat全解析 Hermes Agent与区块链智能合约测试框架:Truffle与Hardhat全解析
在区块链开发领域,智能合约的安全性与可靠性至关重要。Hermes Agent作为一款强大的AI驱动开发工具,能够与主流智能合约测试框架无缝集成,显著提升开发效率与代码质… · 2026/11/4 19:19:41
优化Hermes Agent的网络连接:TCP优化与连接复用实用指南 优化Hermes Agent的网络连接:TCP优化与连接复用实用指南
Hermes Agent作为一款强大的AI代理工具,其网络通信效率直接影响整体性能。本文将详细介绍如何通过TCP优化和连接复用技术提升Hermes Agent的网络连接稳定性与响应速度,帮助用户获得更… · 2026/11/4 19:19:41
Hermes Agent性能监控告警集成:Slack、Email与PagerDuty全攻略 Hermes Agent性能监控告警集成:Slack、Email与PagerDuty全攻略
Hermes Agent 是一款功能强大的开源智能代理框架,支持多平台集成与自动化任务处理。本文将详细介绍如何为 Hermes Agent 配置性能监控告警系统,实现 Slack 实时通知、Email 详细… · 2026/11/4 19:19:41
优化Hermes Agent的存储性能:RAID级别与存储协议选择 优化Hermes Agent的存储性能:RAID级别与存储协议选择
在处理大规模数据和高并发任务时,Hermes Agent的存储性能直接影响整体运行效率。本文将详细介绍如何通过选择合适的RAID级别和存储协议,显著提升Hermes Agent的存储吞吐量、数据可靠性和响… · 2026/11/4 19:19:41
Hermes Agent与脑机接口康复系统集成:运动功能恢复辅助终极指南 Hermes Agent与脑机接口康复系统集成:运动功能恢复辅助终极指南
Hermes Agent作为一款强大的AI代理框架,正通过创新方式与脑机接口(BCI)康复系统集成,为运动功能障碍患者提供个性化的恢复辅助方案。本文将详细介绍这一… · 2026/11/4 19:18:41
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38
AI辅助技术栈评估:提升研发决策效率60% 1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17
从生成Token到直接决策:Jev如何重塑AI Agent工程实践 1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17
32G统一内存跑大模型:内存账、TPS实测与端云分流 想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38