【鸿蒙实战开发】分析CppCrash(进程崩溃)——日志规格与问题分析思路

16 篇文章 0 订阅
16 篇文章 0 订阅

一、进程崩溃检测能力

CppCrash进程崩溃检测基于操作系统信号机制,目前支持对以下崩溃信号的处理:
在这里插入图片描述
在这里插入图片描述

以上部分故障信号,根据具体的场景还有二级分类:

SIGILL是一个在Unix和类Unix操作系统中的信号,它表示非法指令异常。SIGILL信号通常由以下几种类型的问题场景引起:

1.ILL_ILLOPC:非法操作码异常。这种异常通常发生在执行不被CPU支持的指令时,或者在尝试执行特权指令时。

2.ILL_ILLOPN:非法操作数异常。这种异常通常发生在指令使用了不正确的操作数,或者是操作数的类型不正确时。

3.ILL_ILLADR:非法地址异常。这种异常通常发生在程序尝试访问无效的内存地址时,或者是在尝试执行未对齐的内存访问时。

4ILL_ILLTRP:非法陷阱异常。这种异常通常发生在程序尝试执行一个非法的陷阱指令时,或者是在尝试执行一个未定义的操作时。

5.ILL_PRVOPC:特权操作码异常。这种异常通常发生在普通用户尝试执行特权指令时。

6.ILL_PRVREG:特权寄存器异常。这种异常通常发生在普通用户尝试访问特权寄存器时。

7.ILL_COPROC:协处理器异常。这种异常通常发生在程序尝试使用未定义的协处理器指令时。

8.ILL_BADSTK:无效的堆栈异常。这种异常通常发生在程序尝试在无效的堆栈地址上执行操作时,或者是在堆栈溢出时。

SIGTRAP信号通常用于调试和跟踪程序的执行。下面是上面列出的四种SIGTRAP信号类别的问题场景介绍:

1.TRAP_BRKPT:这个信号是由软件断点引起的,当程序执行到设置的断点时会触发该信号。软件断点通常用于调试程序,可以在程序的关键位置设置断点,以便在调试时暂停程序的执行并检查变量值等信息。

2.TRAP_TRACE:这个信号是由单步执行引起的,当程序执行单个指令时会触发该信号。单步执行通常用于调试程序,可以逐步执行程序并检查每个指令的执行结果。

3.TRAP_BRANCH:这个信号是由分支指令引起的,当程序执行分支指令时会触发该信号。分支指令通常用于控制程序的执行流程,例如if语句和循环语句等。

4.TRAP_HWBKPT:这个信号是由硬件断点引起的,当程序执行到设置的硬件断点时会触发该信号。硬件断点通常用于调试程序,可以在程序的关键位置设置断点,以便在调试时暂停程序的执行并检查变量值等信息。与软件断点不同的是,硬件断点是由CPU硬件实现的,因此可以在程序执行过程中实时检测断点是否被触发。

SIGBUS是一种由操作系统向进程发送的信号,通常表示内存访问错误。其中,不同的信号类别表示不同的错误场景:

1.BUS_ADRALN:表示内存地址对齐错误。这种错误通常发生在尝试访问未对齐的内存地址时,例如尝试访问一个4字节整数的非偶数地址。
2.BUS_ADRERR:表示非法内存地址错误。这种错误通常发生在尝试访问不属于进程地址空间的内3.存地址时,例如尝试访问一个空指针。
4.BUS_OBJERR:表示对象访问错误。这种错误通常发生在尝试访问一个已经被删除或未初始化的对象时。
5.BUS_MCEERR_AR:表示硬件内存校验错误,发生在访问内存时检测到校验和错误。
6.BUS_MCEERR_AO:表示硬件内存校验错误,发生在访问内存时检测到地址和校验和错误。

SIGFPE是一个信号,它表示浮点异常或算术异常。下面是这些SIGFPE信号类别的问题场景:

1.FPE_INTDIV:整数除法错误。这个信号表示整数除法中的除数为零的情况。当一个程序尝试进行整数除法,但除数为零时,会发出这个信号。
2.FPE_INTOVF:整数溢出错误。这个信号表示整数除法中的除数为负数的情况。当一个程序尝试进行整数除法,但除数为负数时,会发出这个信号。
3.FPE_FLTDIV:浮点除法错误。这个信号表示浮点数除法中的除数为零的情况。当一个程序尝试进行浮点数除法,但除数为零时,会发出这个信号。
4.FPE_FLTOVF:浮点溢出错误。这个信号表示浮点数除法中的除数为负数的情况。当一个程序尝试进行浮点数除法,但除数为负数时,会发出这个信号。
5.FPE_FLTUND:浮点下溢错误。这个信号表示浮点数除法中的除数为零的情况。当一个程序尝试进行浮点数除法,但除数为零时,会发出这个信号。
6.FPE_FLTRES:浮点结果未定义错误。这个信号表示浮点数除法中的除数为正数的情况。当一个程序尝试进行浮点数除法,但除数为正数时,会发出这个信号。
7.FPE_FLTINV:无效浮点操作错误。这个信号表示浮点数除法中的除数为负数的情况。当一个程序尝试进行浮点数除法,但除数为负数时,会发出这个信号。
8.FPE_FLTSUB:浮点陷阱错误。这个信号表示浮点数除法中的除数为零的情况。当一个程序尝试进行浮点数除法,但除数为零时,会发出这个信号。
SIGSEGV是一种信号,它表示进程试图访问一个不属于它的内存地址,或者试图访问一个已被操作系统标记为不可访问的内存地址。SIGSEGV信号通常是由以下两种情况引起的:

1.SEGV_MAPERR:进程试图访问一个不存在的内存地址,或者试图访问一个没有映射到进程地址空间的内存地址。这种情况通常是由于程序中的指针错误或内存泄漏引起的。
2.SEGV_ACCERR:进程试图访问一个已被操作系统标记为不可访问的内存地址,例如只读内存或没有执行权限的内存。这种情况通常是由于程序中的缓冲区溢出或者试图修改只读内存等错误引起的。

信号还有通用分类,每个信号都有一个唯一的编号,用于在进程间传递信息或者通知进程发生了某些事件。下面是每个信号类别的场景介绍:

1.SI_USER:该信号是由用户空间的进程发送给另一个进程的,通常是通过 kill() 系统调用发送的。例如,当用户在终端中按下Ctrl+C时,会发送一个SIGINT信号给前台进程组中的所有进程。
2.SI_KERNEL:该信号是由内核发送给进程的,通常是由内核检测到某些错误或异常情况时发出的。例如,当进程访问无效的内存地址或者执行非法指令时,内核会发送一个SIGSEGV信号给进程。
3.SI_QUEUE:该信号是由sigqueue()系统调用发送的,可以携带一个附加的整数值和一个指针。通常用于进程间高级通信,例如传递数据或者通知进程某个事件已经发生。
4.SI_TIMER:该信号是由定时器发送的,通常用于定时任务或者周期性任务的执行。例如,当一个定时器到期时,内核会向进程发送一个SIGALRM信号。
5.SI_MESGQ:该信号是由消息队列发送的,通常用于进程间通信。例如,当一个进程向一个消息队列发送消息时,内核会向接收进程发送一个SIGIO信号。
6.SI_ASYNCIO:该信号是由异步I/O操作发送的,通常用于非阻塞I/O操作。例如,当一个文件描述符上的I/O操作完成时,内核会向进程发送一个SIGIO信号。
7.SI_SIGIO:该信号是由异步I/O操作发送的,通常用于非阻塞I/O操作。例如,当一个文件描述符上的I/O操作完成时,内核会向进程发送一个SIGIO信号。
8.SI_TKILL:该信号是由tkill()系统调用发送的,与kill()系统调用类似,但是可以指定发送信号的线程ID。通常用于多线程程序中,向指定线程发送信号。

2 问题定位步骤与思路

1. 崩溃日志获取

进程崩溃日志是一种故障日志,与应用无响应日志、JS应用崩溃等都由FaultLogger模块进行管理,可通过如下四种方式获取:

方式一:通过DevEco Studio获取日志
DevEco Studio会收集设备“/data/log/faultlog/faultlogger/”路径下的进程崩溃故障日志到FaultLog下,根据进程名和故障和时间分类显示。获取日志的方法参见:

FaultLog-故障分析-应用/服务调试-DevEco Studio使用指南-工具-HarmonyOS应用开发 (hwcloudtest.cn)

在这里插入图片描述

方式二:通过faultlogger接口获取
FaultLogger对外提供了面向应用的故障查询接口,可以查询应用自己的故障记录,以结构化的数据返回。接口的使用以及获取的故障信息规格详见@ohos.faultLogger (故障日志获取)

方式三:通过hiAppEvent接口订阅
hiAppEvent对外提供了故障订阅接口,可以订阅各类故障打点,详见@ohos.hiviewdfx.hiAppEvent(应用事件打点)。

方式四:设备ROOT模式下通过shell获取日志
1.进程崩溃后,系统会在设备“/data/log/faultlog/temp/”路径下的故障日志,其文件名格式为“cppcrash-进程PID-系统毫秒级时间戳”,日志内容包含进程崩溃调用栈,进程崩溃现场寄存器、栈内存、maps,进程文件句柄列表等信息。
在这里插入图片描述

2.CppCrash故障会同步在“/data/log/faultlog/faultlogger/”路径下生成一份完善日志,故障日志文件名格式为“cppcrash-进程名-进程UID-秒级时间”,日志内容较“/data/log/faultlog/temp”下日志,完善有设备名,系统版本,进程流水日志等信息。
在这里插入图片描述

CppCrash 日志规格
以下是一份DevEco Studio 在FaultLog工具中查询到的进程崩溃日志的核心内容,与设备“/data/log/faultlog/faultlogger”目录下生成的日志内容一致。

Generated by HiviewDFX@HarmonyOS
==================================================================
Device info:HarmonyOS 3.2     <- 设备信息
Build info:HarmonyOS 4.0.5.5  <- 版本信息
Fingerprint:5e6a663122524ea7c1772b0f16f23b50a2b5753c930ed681a721ac2e8c197645 <- 标识故障特征
Module name:crasher_c   <- 模块名
Version:1.0.0 <- 版本号
VersionCode:1000000 <- 版本代码
PreInstalled:No <- 是否预置
Foreground:Yes  <- 崩溃时刻应用是否在前台
Timestamp:2017-08-05 18:23:53.000 <- 故障发生时间戳
Pid:1369  <- 进程号
Uid:0  <- 用户ID
Reason:Signal:SIGSEGV(SEGV_MAPERR)@00000000 <- 故障原因
Fault thread Info:
Tid:1369 Name:crasher <- 故障线程号,线程名
# 00 pc 00007be6 /data/crasher_c(SegmentFaultException+1)(1a75896316b332b9e7469de9d5a3e4e4)  <- 调用栈
# 01 pc 000082c1 /data/crasher_c(ParseAndDoCrash+412)(1a75896316b332b9e7469de9d5a3e4e4)
# 02 pc 000083e1 /data/crasher_c(main+32)(1a75896316b332b9e7469de9d5a3e4e4)
# 03 pc 0006ef10 /system/lib/ld-musl-arm.so.1
# 04 pc 000038a0 /data/crasher_c(_start_c+84)(1a75896316b332b9e7469de9d5a3e4e4)
# 05 pc 00003844 /data/crasher_c(1a75896316b332b9e7469de9d5a3e4e4)
...
Registers:  <-  故障现场寄存器
r0:00000000 r1:008a262b r2:00000000 r3:00000000
r4:ff9b3e39 r5:00000002 r6:008a93c1 r7:f7872788
r8:f7777976 r9:f7872318 r10:f7872418
fp:ff9b39a8 ip:f777deea sp:ff9b3968 lr:008a92c5 pc:008a8be6
Other thread info: <- 其他线程信息
Tid:1370, Name:crasher <- 线程号,线程名
# 00 pc 00000000001aa2e0 /system/lib/ld-musl-aarch64.so.1(sleep+52) <- 调用栈
# 01 pc 0000000000005188 /data/crasher_c(abea41f851573f032e3e73a1e17d209d)
# 02 pc 000000000019f234 /system/lib/ld-musl-aarch64.so.1
# 03 pc 000000000009f8ac /system/lib/ld-musl-aarch64.so.1
...
Memory near registers:  <-  故障现场寄存器附近内存
r1(/data/crasher_c):
    008a2620 53697274
    008a2624 45534749
    ...
    008a269c 20202020
r4([stack]):
    ff9b3e30 68736172
    ff9b3e34 635f7265
    ...
    ff9b3eac 3d455a49
r6(/data/crasher_c):
    008a93b8 bf00bd80
    008a93bc ffff96d7
    ...
    008a9434 bd802000
r7(/system/lib/ld-musl-arm.so.1):
    f7872780 00000000
    f7872784 00000000
    ...
    f78727fc 00000000
r8(/system/lib/ld-musl-arm.so.1):
    f777796c 00646e65
    f7777970 255f7325
    ...
    f77779e8 6d20726f
r9(/system/lib/ld-musl-arm.so.1):
    f7872310 00000001
    f7872314 00000000
    ...
    f787238c 00000000
r10(/system/lib/ld-musl-arm.so.1):
    f7872410 00010000
    f7872414 00000000
    ...
    f787248c 00000000
fp([stack]):
    ff9b39a0 00000001
    ff9b39a4 f7872418
    ...
    ff9b3a1c ff9b3fd8
r12(/system/lib/ld-musl-arm.so.1):
    f777dee0 203e4425
    f777dee4 25207461
    ...
    f777df5c 75747372
sp([stack]):
    ff9b3960 ff9b39a8
    ff9b3964 008a91c1
    ...
    ff9b39dc 00000000
lr(/data/crasher_c):
    008a92bc e01cfc1b
    008a92c0 fc90f7ff
    ...
    008a9338 ffff9609
pc(/data/crasher_c):
    008a8bdc ffff9f07
    008a8be0 ffff9eb7
    ...
    008a8c58 edeaf000
FaultStack:  <- 崩溃线程栈的地址空间
    ...
    ff9b3964 008a91c1
sp0:ff9b3968 0a9b39d4 <-# 00栈顶
    ff9b396c f5275648
    ...
    ff9b4168 ffffffff

Maps:   <-  故障时进程maps
8a1000-8a4000 r--p 00000000 /data/crasher_c
8a4000-8aa000 r-xp 00002000 /data/crasher_c
8aa000-8ab000 r--p 00007000 /data/crasher_c
8ab000-8ac000 rw-p 00007000 /data/crasher_c
ada000-adb000 ---p 00000000 [heap]
adb000-adc000 rw-p 00000000 [heap]
...
f7759000-f77af000 r--p 00000000 /system/lib/ld-musl-arm.so.1
f77af000-f786f000 r-xp 00055000 /system/lib/ld-musl-arm.so.1
f786f000-f7871000 r--p 00114000 /system/lib/ld-musl-arm.so.1
f7871000-f7873000 rw-p 00115000 /system/lib/ld-musl-arm.so.1
f7873000-f787f000 rw-p 00000000 [anon:ld-musl-arm.so.1.bss]
ff993000-ff9b4000 rw-p 00000000 [stack]
ffff0000-ffff1000 r-xp 00000000 [vectors]

OpenFiles:   <-  故障时进程打开文件Fd信息
0->/dev/null native object of unknown type 0
1->/dev/null native object of unknown type 0
2->/dev/null native object of unknown type 0
3->socket:[20842] native object of unknown type 0
...
46->/dev/null FILE* 4155732440
47->/dev/mali0 native object of unknown type 0
48->/dev/null FILE* 4155732136
49->anon_inode:[eventfd] native object of unknown type 0

在ROOT版本中,通过Shell获取的“/data/log/faultlog/temp”获取到的日志内容格式如下:

Timestamp:2017-08-06 00:54:30.000   <- 故障发生时间
Pid:1369   <- 进程号
Uid:0  <- 用户ID
Process name:crasher   <- 进程名
Process life time:29s   <- 进程存活时间
Reason:Signal:SIGSEGV(SEGV_MAPERR)@00000000   <- 异常信息
Fault thread Info:
Tid:1369, Name:crasher  <- 异常线程号与线程名
# 00 pc 00007be6 /data/crasher_c(SegmentFaultException+1)(1a75896316b332b9e7469de9d5a3e4e4)  <- 调用栈
# 01 pc 000082c1 /data/crasher_c(ParseAndDoCrash+412)(1a75896316b332b9e7469de9d5a3e4e4)
# 02 pc 000083e1 /data/crasher_c(main+32)(1a75896316b332b9e7469de9d5a3e4e4)
# 03 pc 0006ef10 /system/lib/ld-musl-arm.so.1
# 04 pc 000038a0 /data/crasher_c(_start_c+84)(1a75896316b332b9e7469de9d5a3e4e4)
# 05 pc 00003844 /data/crasher_c(1a75896316b332b9e7469de9d5a3e4e4)
Registers:  <-  故障现场寄存器
r0:00000000 r1:008a262b r2:00000000 r3:00000000
r4:ff9b3e39 r5:00000002 r6:008a93c1 r7:f7872788
r8:f7777976 r9:f7872318 r10:f7872418
fp:ff9b39a8 ip:f777deea sp:ff9b3968 lr:008a92c5 pc:008a8be6
Other thread info: <- 其他线程信息
Tid:1370, Name:crasher <- 线程id,线程名
# 00 pc 00000000001aa2e0 /system/lib/ld-musl-aarch64.so.1(sleep+52) <- 调用栈
# 01 pc 0000000000005188 /data/crasher_c(abea41f851573f032e3e73a1e17d209d)
# 02 pc 000000000019f234 /system/lib/ld-musl-aarch64.so.1
# 03 pc 000000000009f8ac /system/lib/ld-musl-aarch64.so.1
Memory near registers:  <-  故障现场寄存器附近内存
r1(/data/crasher_c):
    008a2620 53697274
    008a2624 45534749
    ...
    008a269c 20202020
r4([stack]):
    ff9b3e30 68736172
    ff9b3e34 635f7265
    ...
    ff9b3eac 3d455a49
r6(/data/crasher_c):
    008a93b8 bf00bd80
    008a93bc ffff96d7
    ...
    008a9434 bd802000
r7(/system/lib/ld-musl-arm.so.1):
    f7872780 00000000
    f7872784 00000000
    ...
    f78727fc 00000000
r8(/system/lib/ld-musl-arm.so.1):
    f777796c 00646e65
    f7777970 255f7325
    ...
    f77779e8 6d20726f
r9(/system/lib/ld-musl-arm.so.1):
    f7872310 00000001
    f7872314 00000000
    ...
    f787238c 00000000
r10(/system/lib/ld-musl-arm.so.1):
    f7872410 00010000
    f7872414 00000000
    ...
    f787248c 00000000
fp([stack]):
    ff9b39a0 00000001
    ff9b39a4 f7872418
    ...
    ff9b3a1c ff9b3fd8
r12(/system/lib/ld-musl-arm.so.1):
    f777dee0 203e4425
    f777dee4 25207461
    ...
    f777df5c 75747372
sp([stack]):
    ff9b3960 ff9b39a8
    ff9b3964 008a91c1
    ...
    ff9b39dc 00000000
lr(/data/crasher_c):
    008a92bc e01cfc1b
    008a92c0 fc90f7ff
    ...
    008a9338 ffff9609
pc(/data/crasher_c):
    008a8bdc ffff9f07
    008a8be0 ffff9eb7
    ...
    008a8c58 edeaf000
FaultStack:   <- 崩溃线程的栈地址空间
    ...
    ff9b3964 008a91c1
sp0:ff9b3968 0a9b39d4 <- # 00栈顶
    ff9b396c f5275648
    ...
    ff9b4168 ffffffff

Maps:   <-  故障时进程maps
8a1000-8a4000 r--p 00000000 /data/crasher_c
8a4000-8aa000 r-xp 00002000 /data/crasher_c
8aa000-8ab000 r--p 00007000 /data/crasher_c
8ab000-8ac000 rw-p 00007000 /data/crasher_c
ada000-adb000 ---p 00000000 [heap]
adb000-adc000 rw-p 00000000 [heap]
...
f7759000-f77af000 r--p 00000000 /system/lib/ld-musl-arm.so.1
f77af000-f786f000 r-xp 00055000 /system/lib/ld-musl-arm.so.1
f786f000-f7871000 r--p 00114000 /system/lib/ld-musl-arm.so.1
f7871000-f7873000 rw-p 00115000 /system/lib/ld-musl-arm.so.1
f7873000-f787f000 rw-p 00000000 [anon:ld-musl-arm.so.1.bss]
ff993000-ff9b4000 rw-p 00000000 [stack]
ffff0000-ffff1000 r-xp 00000000 [vectors]

OpenFiles:   <-  故障时进程打开文件Fd信息
0->/dev/null native object of unknown type 0
1->/dev/null native object of unknown type 0
2->/dev/null native object of unknown type 0
3->socket:[20842] native object of unknown type 0
...
46->/dev/null FILE* 4155732440
47->/dev/mali0 native object of unknown type 0
48->/dev/null FILE* 4155732136
49->anon_inode:[eventfd] native object of unknown type 0

2. 基于崩溃栈定位行号

方式一:DevEco Studio 开发者环境下,支持调用栈直接跳转到对应行号
在应用开发场景,对于应用自身的动态库,生成的cppcrash堆栈可直接跳转到代码行处,支持Native栈帧和JS栈帧,无需开发者自行进行解行号操作。对于部分未能解析跳转到对应行号的栈帧,可参考方式二解析。
在这里插入图片描述

方式二:通过SDK llvm-addr2line 工具定位行号

  1. 获取符号表
    获取崩溃栈中so文件对应的带符号版本,保证与应用/系统内运行时的so文件版本一致

对于应用自身的动态库,经DevEco编译构建,生成在工程的 /build/default/intermediates/libs 目录下,默认是带符号的版本。可通过Linux file 命令查询二进制文件的 BuildID 以核对是否匹配。其中,BuildID 是用于标识二进制文件的唯一标识符,通常由编译器在编译时生成,not stripped 表示该动态库是包含符号表的。

$ file libbabel.so

libbabel.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=fdb1b5432b9ea4e2a3d29780c3abf30e2a22da9d, with debug_info, not stripped

说明:对于系统动态库符号表,随版本进行归档。

  1. 通过 llvm-addr2line 工具定位行号
    llvm-addr2line 工具归档在:[SDK DIR PATH]\OpenHarmony\11\native\llvm\bin 路径下。根据实际的SDK版本路径略有不同,开发者请自行识别或在路径下搜索。

例如有堆栈如下(有省略):

Generated by HiviewDFX@OpenHarmony

================================================================

Device info:OpenHarmony 3.2

Build info:OpenHarmony 5.0.0.22

Fingerprint:50577c0a1a1b5644ac030ba8f08c241cca0092026b59f29e7b142d5d4d5bb934

Module name:com.samples.recovery

Version:1.0.0

VersionCode:1000000

PreInstalled:No

Foreground:No

Timestamp:2017-08-05 17:03:40.000

Pid:2396

Uid:20010044

Process name:com.samples.recovery

Process life time:7s

Reason:Signal:SIGSEGV(SEGV_MAPERR)@0000000000  probably caused by NULL pointer dereference

Tid:2396, Name:amples.recovery

# 00 pc 00003510 /data/storage/el1/bundle/libs/arm/libentry.so(TriggerCrash(napi_env__*, napi_callback_info__*)+24)(446ff75d3f6a518172cc52e8f8055650b02b0e54)

# 01 pc 0002b0c5 /system/lib/platformsdk/libace_napi.z.so(panda::JSValueRef ArkNativeFunctionCallBack<true>(panda::JsiRuntimeCallInfo*)+448)(a84fbb767fd826946623779c608395bf)

# 02 pc 001e7597 /system/lib/platformsdk/libark_jsruntime.so(panda::ecmascript::EcmaInterpreter::RunInternal(panda::ecmascript::JSThread*, unsigned char const*, unsigned long long*)+14710)(106c552f6ce4420b9feac95e8b21b792)

# 03 pc 001e0439 /system/lib/platformsdk/libark_jsruntime.so(panda::ecmascript::EcmaInterpreter::Execute(panda::ecmascript::EcmaRuntimeCallInfo*)+984)(106c552f6ce4420b9feac95e8b21b792)

# 04 pc 0029ec97 /system/lib/platformsdk/libark_jsruntime.so(panda::ecmascript::JSFunction::Call(panda::ecmascript::EcmaRuntimeCallInfo*)+386)(106c552f6ce4420b9feac95e8b21b792)

# 05 pc 0034ab13 /system/lib/platformsdk/libark_jsruntime.so(panda::FunctionRef::Call(panda::ecmascript::EcmaVM const*, panda::Local<panda::JSValueRef>, panda::Local<panda::JSValueRef> const*, int)+762)(106c552f6ce4420b9feac95e8b21b792)

# 06 pc 01792e73 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::Framework::JsiFunction::Call(OHOS::Ace::Framework::JsiRef<OHOS::Ace::Framework::JsiValue>, int, OHOS::Ace::Framework::JsiRef<OHOS::Ace::Framework::JsiValue>*) const+282)(40e2c83c3608b7b0ebd1477c8d95f092)

# 07 pc 014bcb83 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::Framework::JsFunction::ExecuteJS(int, OHOS::Ace::Framework::JsiRef<OHOS::Ace::Framework::JsiValue>*)+250)(40e2c83c3608b7b0ebd1477c8d95f092)

# 08 pc 014b4f53 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::Framework::JsClickFunction::Execute(OHOS::Ace::GestureEvent&)+1282)(40e2c83c3608b7b0ebd1477c8d95f092)

# 09 pc 014def21 /system/lib/platformsdk/libace_compatible.z.so(40e2c83c3608b7b0ebd1477c8d95f092)

# 10 pc 0043f5cd /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::ClickRecognizer::SendCallbackMsg(std::__h::unique_ptr<std::__h::function<void (OHOS::Ace::GestureEvent&)>, std::__h::default_delete<std::__h::function<void (OHOS::Ace::GestureEvent&)>>> const&)+916)(40e2c83c3608b7b0ebd1477c8d95f092)

# 11 pc 0043f04b /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::ClickRecognizer::OnAccepted()+1794)(40e2c83c3608b7b0ebd1477c8d95f092)

# 12 pc 0044cddb /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::MultiFingersRecognizer::OnAccepted(unsigned int)+74)(40e2c83c3608b7b0ebd1477c8d95f092)

# 13 pc 00449955 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::GestureScope::AcceptGesture(OHOS::Ace::RefPtr<OHOS::Ace::GestureRecognizer> const&)+1092)(40e2c83c3608b7b0ebd1477c8d95f092)

# 14 pc 00448d41 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::GestureScope::HandleAcceptDisposal(OHOS::Ace::RefPtr<OHOS::Ace::GestureRecognizer> const&)+624)(40e2c83c3608b7b0ebd1477c8d95f092)

# 15 pc 0044a4c3 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::GestureReferee::Adjudicate(unsigned int, OHOS::Ace::RefPtr<OHOS::Ace::GestureRecognizer> const&, OHOS::Ace::GestureDisposal)+46)(40e2c83c3608b7b0ebd1477c8d95f092)

# 16 pc 004479e7 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::GestureRecognizer::BatchAdjudicate(std::__h::set<unsigned int, std::__h::less<unsigned int>, std::__h::allocator<unsigned int>> const&, OHOS::Ace::RefPtr<OHOS::Ace::GestureRecognizer> const&, OHOS::Ace::GestureDisposal)+242)(40e2c83c3608b7b0ebd1477c8d95f092)

# 17 pc 0044cebd /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::MultiFingersRecognizer::Adjudicate(OHOS::Ace::RefPtr<OHOS::Ace::GestureRecognizer> const&, OHOS::Ace::GestureDisposal)+60)(40e2c83c3608b7b0ebd1477c8d95f092)

# 18 pc 0043fd2d /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::ClickRecognizer::HandleTouchUpEvent(OHOS::Ace::TouchEvent const&)+64)(40e2c83c3608b7b0ebd1477c8d95f092)

# 19 pc 00447381 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::GestureRecognizer::HandleEvent(OHOS::Ace::TouchEvent const&)+64)(40e2c83c3608b7b0ebd1477c8d95f092)

# 20 pc 003ef717 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::EventManager::DispatchTouchEvent(OHOS::Ace::TouchEvent const&)+2098)(40e2c83c3608b7b0ebd1477c8d95f092)

# 21 pc 004a47e1 /system/lib/platformsdk/libace_compatible.z.so(OHOS::Ace::PipelineContext::OnTouchEvent(OHOS::Ace::TouchEvent const&, bool)+2152)(40e2c83c3608b7b0ebd1477c8d95f092)

# 22 pc 01402aa7 /system/lib/platformsdk/libace_compatible.z.so(40e2c83c3608b7b0ebd1477c8d95f092)

# 23 pc 00400d27 /system/lib/platformsdk/libace_compatible.z.so(40e2c83c3608b7b0ebd1477c8d95f092)

# 24 pc 00010b29 /system/lib/chipset-pub-sdk/libeventhandler.z.so(OHOS::AppExecFwk::EventHandler::DistributeEvent(std::__h::unique_ptr<OHOS::AppExecFwk::InnerEvent, void (*)(OHOS::AppExecFwk::InnerEvent*)> const&)+1088)(d5c6cca8b49f238228529e7fa2d8d132)

# 25 pc 0001a2cd /system/lib/chipset-pub-sdk/libeventhandler.z.so(OHOS::AppExecFwk::(anonymous namespace)::EventRunnerImpl::ExecuteEventHandler(std::__h::unique_ptr<OHOS::AppExecFwk::InnerEvent, void (*)(OHOS::AppExecFwk::InnerEvent*)>&)+900)(d5c6cca8b49f238228529e7fa2d8d132)

# 26 pc 00019a4d /system/lib/chipset-pub-sdk/libeventhandler.z.so(OHOS::AppExecFwk::(anonymous namespace)::EventRunnerImpl::Run()+572)(d5c6cca8b49f238228529e7fa2d8d132)

# 27 pc 0001bc8b /system/lib/chipset-pub-sdk/libeventhandler.z.so(OHOS::AppExecFwk::EventRunner::Run()+174)(d5c6cca8b49f238228529e7fa2d8d132)

# 28 pc 0007cc2b /system/lib/platformsdk/libappkit_native.z.so(OHOS::AppExecFwk::MainThread::Start()+610)(b2076b5e4931f3d39ef1f253b408ad23)

# 29 pc 00003a3d /system/lib/appspawn/appspawn/libappspawn_ace.z.so(RunChildProcessor(AppSpawnContent*, AppSpawnClient*)+248)(aa7371861a2e2596acfed71792b30123)

# 30 pc 00005e77 /system/bin/appspawn(AppSpawnChild+298)(cb0631260fa74df0bc9b0323e30ca03d)

# 31 pc 00005c65 /system/bin/appspawn(AppSpawnProcessMsg+260)(cb0631260fa74df0bc9b0323e30ca03d)

# 32 pc 0000a12d /system/bin/appspawn(OnReceiveRequest+888)(cb0631260fa74df0bc9b0323e30ca03d)

# 33 pc 00010999 /system/lib/chipset-pub-sdk/libbegetutil.z.so(HandleRecvMsg_+192)(11f7e292f040cf5d05f6aaad0dca0668)

# 34 pc 000105e3 /system/lib/chipset-pub-sdk/libbegetutil.z.so(HandleStreamEvent_+86)(11f7e292f040cf5d05f6aaad0dca0668)

# 35 pc 0000e797 /system/lib/chipset-pub-sdk/libbegetutil.z.so(ProcessEvent+70)(11f7e292f040cf5d05f6aaad0dca0668)

# 36 pc 0000e437 /system/lib/chipset-pub-sdk/libbegetutil.z.so(RunLoop_+134)(11f7e292f040cf5d05f6aaad0dca0668)

# 37 pc 00008cfd /system/bin/appspawn(AppSpawnRun+100)(cb0631260fa74df0bc9b0323e30ca03d)

# 38 pc 000074e1 /system/bin/appspawn(main+392)(cb0631260fa74df0bc9b0323e30ca03d)

# 39 pc 00072998 /system/lib/ld-musl-arm.so.1(libc_start_main_stage2+56)(5b1e036c4f1369ecfdbb7a96aec31155)

# 40 pc 00005b48 /system/bin/appspawn(_start_c+84)(cb0631260fa74df0bc9b0323e30ca03d)

# 41 pc 00005aec /system/bin/appspawn(cb0631260fa74df0bc9b0323e30ca03d)

Registers:

r0:00000000 r1:ffc47af8 r2:00000001 r3:f6555c94

r4:00000000 r5:f4d90f64 r6:bd8434f8 r7:00000000

r8:00000000 r9:ffc48808 r10:ffc47b70

fp:f7d8a5a0 ip:00000000 sp:ffc47aac lr:f4d6b0c7 pc:bd843510

基于SDK llvm-addr2line解析行号如下所示:

在这里插入图片描述

llvm-addr2line 逐行解析的命令为:llvm-addr2line.exe -fCpie libutils.z.so 偏移量

偏移量可以多个一起解:llvm-addr2line.exe -fCpie libxxx.so 0x1bc868 0x1be28c xxx

使用llvm-addr2line后,如果得出的行号看起来不是很正确,可以考虑对 地址进行微调(如减1),或者考虑关闭一些编译优化。

方式三:通过 DevEco Studio hstack 工具解析堆栈信息
hstack是DevEco Studio为开发人员提供的用于将release应用混淆后的crash堆栈还原为源码对应堆栈的工具,支持Windows、Mac、Linux三个平台。

参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-command-line-hstack-0000001777724494

3. 结合业务检视代码

以上小节为例,获取到栈顶对应的行号后,回到代码中,检视上下文。如下图所示,hello.cpp中的48行是一个空指针解引用的代码问题。

在这里插入图片描述

本场景是一个故障构造的应用,实际的场景往往不会这么简单,需要结合实际业务进行分析。

4. 反汇编

一般而言,如果是比较明确的问题,反编译定位到代码行就能够定位;较少数的情况,比如定位到某一行里面调用的方法有多个参数,参数又涉及到结构体等,就需要借助反汇编来进一步分析;

objdump -S xxx.so > xxx.txt

objdump -d xxxx                    对 xxxx 文件反汇编

objdump -S -l xxxx                 对 xxxx 文件反汇编,同时将指令对应的源码行显示出来

在这里插入图片描述
在这里插入图片描述

5. CppCrash 常见问题分类与原因

空指针解引用 NULL pointer dereference

形如 SIGSEGV(SEGV_MAPERR)@0x00000000 或 r0 r1 等传参寄存器的值为0时,应首先考虑调用时是否传入了空指针

形如 SIGSEGV(SEGV_MAPERR)@0x0000000c 或 r1 等传参寄存器的值为一个很小的值时应考虑调用入参的结构体成员是否包含空指针

程序主动终止SIGABRT

一般为用户/框架/C库主动触发,大部分场景下跳过C库/abort发起的框架库的第一帧即为崩溃原因,这里主要检测的是资源使用类的问题,如线程创建,文件描述符使用,接口调用时序等

SIGSEGV无效内存访问

多线程操作集合,std库的集合为非线程安全,如果多线程添加删除,容易出现SIGSEGV类崩溃,如果使用 llvm-addr2line 后的代码行与集合相关,可以考虑这个原因

不匹配的对象生命周期,比如使用裸指针(不含有封装、自动内存管理等特性的指针)保存sptr类型以及shared_ptr类型,会导致内存泄漏和悬空指针问题

裸指针是指不含有封装、自动内存管理等特性的指针。它只是一个指向内存地址的简单指针,没有对指针指向的内存进行保护或管理。裸指针可以直接访问指向的内存,但也容易出现内存泄漏、空指针引用等问题。因此,在使用裸指针时需要特别小心,避免出现潜在的安全问题;推荐使用智能指针来管理内存;

use after free问题

返回临时变量、野指针:比如返回栈变量的引用,释放后未置空继续访问

# include <iostream>

int& getStackReference() {

    int x = 5;

    return x;  // 返回 x 的引用

}

int main() {

    int& ref = getStackReference();  // 获取 x 的引用

    // x 在 getStackReference 函数返回后被释放

    // ref 现在是悬空引用,继续访问会导致未定义行为

    std::cout << ref << std::endl;  // 试图输出 x 的值,这是未定义行为

    return 0;

}

栈溢出:如递归调用,析构函数相互调用,特殊的栈(信号栈)中使用大块栈内存

# include <iostream>

class RecursiveClass {

public:

    RecursiveClass() {

        std::cout << "Constructing RecursiveClass" << std::endl;

    }

    ~RecursiveClass() {

        std::cout << "Destructing RecursiveClass" << std::endl;

        // 在析构函数中递归调用

        RecursiveClass obj;

    }

};

int main() {

    RecursiveClass obj;

    return 0;

}

创建一个 RecursiveClass 对象时,它的构造函数被调用。销毁这个对象时,它的析构函数被调用。在析构函数中,创建了一个新的RecursiveClass对象,这会导致递归调用,直到栈溢出。递归调用导致了无限的函数调用,最终导致栈空间耗尽,程序崩溃。

二进制不匹配:通常由ABI(应用程序二进制接口)不匹配引起,如自己编译二进制与实际运行的二进制接口存在差异,数据结构定义存在差异,这种一般会产生随机的崩溃栈

踩内存:使用有效的野指针,并修改了其中的内存为非法值,访问越界,覆盖了正常的数据这种一般会产生随机的崩溃栈

SIGBUS (Aligment)

考虑对指针进行强转之后地址是否已经处于非对齐状态

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。在这里插入图片描述

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值