## 带崩溃转储功能的VX5 Release 编译发行、dump收集、问题分析 由于VX5相比VX4在稳定性上有些许差异,目前VX5在用户端仍然可能存在崩溃问题,作为兜底方案,我们引入了崩溃转储功能。 崩溃转储功能是工程化的软件项目中几乎必有的一个功能,它可以在软件崩溃时,将当前程序的函数调用栈、寄存器状态、内存状态等保存到dump上,开发人员依据dump文件结合程序日志可以快速定位到崩溃的位置。 带崩溃转储的发行版发布、dump收集、问题分析,步骤是:使用带-g编译标记编译release版本、生成带调试符号的可执行文件、分离调试符号生成符号调试表和不带调试符号的发行版可执行程序、将发行版可执行程序发布给用户上机运行、运行过程中触发崩溃、收集dump文件、将dump与之前分离的调试信息表以及发行版可执行程序放在一起,使用 addr2line 等工具封装为脚本将dump中的需要观察的调用栈地址、程序地址等转换为包含源码位置等的信息,最后进行源码分析并修复。 ## 项目先决条件 在进行此方式编译发行前,可能需要检查以下先决条件,虽然这些已经在最新 VX5_V6.7.1 和 韩国VX5 项目中默认配置。 1. QtUI.pro 中需包含如下配置: ``` pro CONFIG += qt warn_on debug_and_release # 启用警告和调试信息 QMAKE_CXXFLAGS += -g # 启用 -g 编译标记 #QMAKE_POST_LINK += ulimit -c unlimited LIBS += -ldl # 链接 dl 库,用于获取当前程序的基址 # ... 其他内容 # 包含 dump转储功能的头文件和源文件 HEADERS += dump.h SOURCES += dump.cpp ``` 2. `main.cpp` 中需包含 `dump.h` 文件,并在 `QApplication app` 后第一时间调用 `installSignalHandler()` 函数,用于安装信号处理函数。 ```cpp QApplication a(argc, argv); gAppNameStr = QString::fromUtf8(argv[0]); installSignalHandlers(); // 这里安装信号处理函数 ``` 3. `dump.cpp` `dump.h` 已添加至最新的标准VX5、韩国VX5项目中。 4. 用于分离调试符号的脚本 `strip_debug.sh` 已添加至项目源码目录中。 5. 用于分析dump文件的脚本 `resolve_dump.sh` 已添加至项目源码目录中。 ## 编译发行 1. 使用QtCreator IDE 一键release编译,或使用VScode 配置命令行,编译release版本的带调试符号的、满足项目需求的可执行文件,得到`QtUI`。 ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface$ ls ../arm_build/QtUI* -lh -rwxrwxrwx 1 root root 55M 7月 1 10:22 ../arm_build/QtUI ``` 可以看到`QtUI`的大小为55M,说明包含了调试符号,但是因为携带了调试符号,运行时可能会占用更多内存,且不利于用户发行更新,同时还包含了源码信息,存在泄漏风险。为此我们需要将调试符号分离出来,生成符号调试表和不带调试符号的发行版可执行程序。 2. 使用之前编译`QtUI`时使用的交叉编译工具链中的 `objcopy` 工具,将`QtUI`的调试符号分离出来,对于 `InkjetUbuntu-T1` 虚拟机,已经包含了 `objcopy` 工具。 使用命令行分离:进入QtUI所在目录,按如下命令进行操作: ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --only-keep-debug QtUI QtUI.dbg # 分离调试符号生成符号调试表 inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --strip-debug QtUI QtUI # 移除调试符号 inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ aarch64-linux-gnu-objcopy --add-gnu-debuglink=QtUI.dbg QtUI # 关联调试符号文件和发行程序 inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ls ./QtUI* -lh -rwxrwxrwx 1 root root 6.7M 7月 1 10:43 ./QtUI -rwxrwxrwx 1 root root 48M 7月 1 10:43 ./QtUI.dbg ``` 注意输出结果,一个大小为6.7M的`QtUI`,该文件与平常不带`-g`编译出来的`QtUI`一致,用于用户发布;一个大小为48M的`QtUI.dbg`,存放调试符号信息,用于内部保留日后分析dump文件,两个文件进行了关联,因此两个文件在内部必须成对存放,不可缺一。 第二种方法:使用`strip_debug.sh`脚本分离调试符号 进入QtUI所在目录,按如下命令进行操作: ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./strip_debug.sh ``` 或者指定QtUI路径: ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./strip_debug.sh QtUI ``` 两种方式都可以生成`QtUI`和`QtUI.dbg`两个文件,此时将 `QtUI` 附上更新说明发布。将 `QtUI.dbg` `QtUI` 打包上传SVN仓库内部存放。 ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ls ./QtUI_V6.7.1_韩国_2026年7月* -lh -rwxrwxrwx 1 root root 23M 7月 1 11:11 ./QtUI_V6.7.1_韩国_2026年7月1日11_11_08.zip ``` 注意明确标准编译时间,避免与用户端软件编译时间不一致导致的dump文件时间错误。 将携带`QtUI.dbg`的`QtUI_V6.7.1_韩国_2026年7月1日11_11_08.zip`上传至 `https://pc-20181215fqqf/svn/src/QTUI软件版本/VX5` 仓库。 然后仅将 `QtUI`与发行说明打包按正常流程发布。 ## 收集dump文件 当用户端或产线测试发生崩溃,dump文件会被收集到`/home/plg/loginfo`目录下。 ```shell cat@lubancat:/home/plg/loginfo$ ls /home/plg/loginfo/dumpfile_2026_07_01_11_33_07.txt -lh -rw-r--r-- 1 root root 3.1K 7月 1 11:33 /home/plg/loginfo/dumpfile_2026_07_01_11_33_07.txt ``` 使用 `QtUI` 的日志导出功能,可将所有 dump 文件导出至U盘,dump 文件格式为 `dumpfile_YYYY_MM_DD_HH_MM_SS.txt`,按照崩溃时间记录。 拿到的dump文件可能如下 ```txt Stack trace info: Base address: 0x557162e000 /home/plg/QtUI(+0x6b29c) [0x557169929c] ??:? /home/plg/QtUI(+0x6b96c) [0x557169996c] ??:? linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9d72458c] ??:0 ...... 省略更多.... ``` 注意dump文件中缺失了源码信息,需要结合之前的`QtUI.dbg`文件进行分析。 ## 分析dump文件 由于之前对编译好的`QtUI`进行了调试符号分离,因此崩溃捕获到的dump信息与普通不带`-g`编译的`QtUI`崩溃捕获的dump一样,会缺少调试符号。 因此我们将该dump文件与之前内部保存的 `QtUI` `QtUI.dbg` 放在一起,进行一点处理就可以获得完整的调试源码信息。 执行脚本`resolve_dump.sh`,即可获得完整的dump信息。 ```shell inkjet@ubuntu:/mnt/hgfs/share/bSpec/arm_build$ ./resolve_dump.sh ./dumpfile_2026_07_01_11_33_07.txt Base address: 0x557162e000 QtUI 路径: /mnt/hgfs/share/bSpec/arm_build/QtUI QtUI.dbg: /mnt/hgfs/share/bSpec/arm_build/QtUI.dbg 输出文件: ./dumpfile_2026_07_01_11_33_07_resolved.txt 正在解析 dump 文件: ./dumpfile_2026_07_01_11_33_07.txt ========================================= Stack trace info: Base address: 0x557162e000 /home/plg/QtUI(+0x6b29c) [0x557169929c] createStackTraceFile(char const*, char const*) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/dump.cpp:54 /home/plg/QtUI(+0x6b96c) [0x557169996c] signalHandler(int) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/dump.cpp:96 (discriminator 9) linux-vdso.so.1(__kernel_rt_sigreturn+0) [0x7f9d72458c] ??:0 /opt/Qt/lib/libQt5Widgets.so.5(_ZNK7QWidget11windowTitleEv+0xc) [0x7f9d1ad56c] ??:0 /home/plg/QtUI(+0x189f30) [0x55717b7f30] SetNumDlg::on_btn_confirm_clicked() at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/setnumdlg.cpp:39 /home/plg/QtUI(+0x1b14d0) [0x55717df4d0] SetNumDlg::qt_metacall(QMetaObject::Call, int, void**) at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/tmp/moc_setnumdlg.cpp:147 ...... 省略更多.... ``` 注意输出结果 ``` text SetNumDlg::on_btn_confirm_clicked() at /mnt/hgfs/share/bSpec/800X600_New_SystemProject-_NewInterface/../arm_build/../800X600_New_SystemProject-_NewInterface/setnumdlg.cpp:39 ``` 说明崩溃位于`setnumdlg.cpp`文件的`39`行。同时`resolve_dump.sh`脚本会生成`dumpfile_2026_07_01_11_33_07_resolved.txt`文件。