【鸿蒙OH实战开发】APP性能监控之CppCrash故障定位


📚往期笔录记录✏️:

✏️ 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?

✏️ 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~

✏️ 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?

✏️ 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?

✏️ 记录一场鸿蒙开发岗位面试经历~

✏️ 持续更新中……


简介

CppCrash是C/C++运行时崩溃,包括空指针异常、数组越界异常、栈溢出异常等。HarmonyOS系统针对这一类故障,基于系统级DFX能力,能够进行检测并生成故障日志,生成在/data/log/faultlog/faultlogger系统目录下,在DevEcoStudio中的Faultlog工具栏也能进行汇总显示。

CppCrash故障日志

日志格式和日志获取

CppCrash日志格式可参考 《日志格式》 。CppCrash故障根据报错场景可以分为运行态CppCrash故障和开发态CppCrash故障。

在开发态下,DevEco Studio会收集CppCrash、App Freeze、JS Crash、System Freeze、ASan的崩溃日志到FaultLog下,开发者可以通过FaultLog的CppCrash日志、ASAN日志定位问题的具体原因。此外,开发者可以自行获取/data/log/faultlog/faultlogger下的日志再进行分析。

在运行态下,开发者需要提前开通崩溃服务,收集运行状态下的CppCrash,具体步骤如下所示:

  1. 开发者需要在 AGC 提前创建项目和应用,详细创建步骤可以参考创建项目与应用。
  2. 在AGC上开通崩溃服务,详细的操作步骤可以参考开通HarmonyOS应用的服务。
  3. 添加配置文件,将配置文件添加到工程目录并集成AGC插件,AGC插件可以自动将您在AGC上的应用信息加载到开发环境,详情可参考添加配置文件。
  4. 添加配置文件后,需要在DevEco Studio项目中配置SDK依赖,详情可参考集成SDK。
  5. 配置完成后,需要测试崩溃服务是否正常运行,详情可以参考测试崩溃实现。
  6. 具体的崩溃日志,可以在“AGC->我的项目->崩溃”中找到详细日志,进而分析异常报错问题。

crash信号分类

进程崩溃基于Linux信号机制,目前主要支持对以下崩溃异常信号的处理:

表1 当前系统支持的崩溃异常信号表

信号值 信号 解释 触发原因
4 SIGILL 非法指令 执行了非法指令、格式错误、未知或特权指令,通常是因为可执行文件本身出现错误,或者试图执行数据段,堆栈溢出时也有可能产生这个信号。
5 SIGTRAP 断点或陷阱异常 由断点指令或其它trap指令产生。
6 SIGABRT abort发出的信号 调用abort函数生成的信号。
7 SIGBUS 非法内存访问 非法地址,包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。
8 SIGFPE 浮点异常 在发生致命的算术运算错误时发出,不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。
11 SIGSEGV 无效内存访问 试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据。
16 SIGSTKFLT 栈溢出 堆栈溢出。
31 SIGSYS 系统调用异常 非法的系统调用(Seccomp 限制)

CppCrash故障定位

辅助工具介绍

(1)反编译addr2line

Linux下addr2line命令用于将程序指令地址转换为所对应的函数名、以及函数所在的源文件名和行号。在问题定位时,可以使用llvm-addr2line.exe来替换addr2line,其对应的路径在"SDK安装路径\版本路径\base\native\llvm\bin"下,使用时可以参考以下命令。其中,libentry.so是报错的动态链接库,0000000000001c14是报错的内存地址。

llvm-addr2line.exe -a -C -i -f -e xxx\...\libentry.so 0000000000001c14

表2 参数说明

参数 功能描述
-C 去除名称修饰
-f 在反汇编结果中显示函数名
-a 显示内存地址
-i 解开内联函数
-e 指定待还原的so的路径

(2)反汇编objdump

objdump可以用来显示二进制文件的信息,它可以进行反汇编用于观察内存异常。在问题定位时,可以使用llvm-objdump.exe来替换objdump,其对应的路径在"SDK安装路径\版本路径\base\native\llvm\bin"下,使用时可以参考以下命令。其中,libentry.so是需要反汇编的动态链接库,text.txt用于存储反汇编的代码。

llvm-objdump.exe -S -d xxx\...\libentry.so > text.txt

**表3 **参数说明

选项 功能说明
-C 将低级符号名称解码(解映射)为用户级名称。除了删除系统预置的任何初始下划线外,这还使C++函数名可读。不同的编译器有不同的篡改样式。可选的 demangling 样式参数可用于为编译器选择适当的 demangling style 。
-d 显示 objfile 中机器指令的汇编助记符。此选项仅反汇编那些预期包含指令的部分。
-D 像 -d 一样,但反汇编所有部分的内容,而不仅仅是那些预期包含指令的部分。
-F 在反汇编 sections 时,无论何时显示符号,都要显示要转储的数据区域的文件偏移量。如果跳过了零,那么当反汇编恢复时,告诉用户跳过了多少个零,以及反汇编恢复位置的文件偏移量。转储节时,显示转储开始位置的文件偏移量。0000000000000665 (File Offset: 0x665): so 共享库的某个反汇编函数入口000000000040052d (File Offset: 0x52d): 可执行文件的某个反汇编函数入口
-l 用与显示的目标代码或重定位相对应的文件名和源行号标记显示(使用调试信息)
-S 如果可能的话(有调试信息),显示混合了反汇编的源代码。

(3)ASan

ASan(Address-Sanitizer)是内存检测的工具,用于发现内存飞踩第一现场,DevEco Studio已集成ASan为开发者提供面向C/C++的地址越界检测能力。ASan可以解决一些踩内存导致的异常crash的补充手段,对于一些明显不可能crash的场景可以尝试开启ASan。

CppCrash故障定位方法

CppCrash常用故障定位分为本地环境定位和系统环境定位,其主要的定位思路类似,详细的定位方法如下所示:

(1)找出问题必现条件,复现问题场景;

(2)先开多线程检测配置,排查多线程安全问题;

先打开多线程检测配置,确认问题是否属于多线程安全问题,若打开多线程检测配置之后还是报当前错误栈,则进行下一步排查。打开开关的hdc指令为:

hdc shell param set persist.ark.properties 0x107c 
hdc shell reboot

说明
persist.ark.properties的默认值为0x105c(即关闭状态)。

(3)根据信号和错误码初步推断crash原因。如下图所示,错误原因为SIGSEGV(SEGV_ACCERR),说明是xmlparser崩溃相关原因。

(4)根据堆栈信息找出报错的栈顶函数。

如下图所示,在开发态发生CppCrash时,在本地环境的DevEco Studio中,Native栈帧和JS栈帧可以通过蓝色链接直接跳转到对应的代码行。

在运行态下,开发者可以找到报错的日志,根据对应的报错日志使用llvm_addr2line解析出栈帧的对应的代码行号。案例如下所示。

说明
使用addr2line后,如果得出的行号看起来不是很正确,可以考虑对地址进行微调(如减1),或者考虑关闭一些编译优化,已知使用LTO(Link Time Optimization)的二进制可能无法正确获得行号。

(5)若无法定位出具体原因,可以使用llvm-objdump反汇编代码,再进一步进行分析。

分析反汇编可参考以下步骤:

  1. 执行反汇编命令,找到报错的汇编代码;
  2. 追踪汇编代码中,寄存器数据的来源,确定导致程序出错的那部分代码。
  3. 结合报错信息和寄存器数据,推断程序报错的原因。
  4. 根据对报错原因的分析,进行代码修正或优化,以解决程序出错的问题。

(6)如果有理论上不应该发生堆栈报错,可以考虑开启ASan,再根据ASan定位分析具体原因。

如下所示,发生crash后&#

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值