Files
VX5_KRO_GearPump/doc/VX5 Release编译发行.md
2026-07-02 14:32:38 +08:00

144 lines
8.2 KiB
Markdown

## 带崩溃转储功能的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`文件。