ToB企服应用市场:ToB评测及商务社交产业平台

标题: 鸿蒙HarmonyOS实战开辟:CppCrash故障分析(历程崩溃) [打印本页]

作者: 汕尾海湾    时间: 前天 18:20
标题: 鸿蒙HarmonyOS实战开辟:CppCrash故障分析(历程崩溃)
 鸿蒙NEXT开辟实战往期必看文章:
一分钟了解”纯血版!鸿蒙HarmonyOS Next应用开辟!
“非常详细的” 鸿蒙HarmonyOS Next应用开辟学习路线!(从零根本入门到精通)
HarmonyOS NEXT应用开辟案例实践总结合(连续更新......)
HarmonyOS NEXT应用开辟性能优化实践总结(连续更新......)

历程崩溃指C/C++运行时崩溃。FaultLogger模块提供历程崩溃故障检测、日志采集、日志存储、日志上报的本领,为开辟者提供详细的维测日志以辅助故障定位。
本文将分别介绍历程崩溃检测本领、崩溃标题定位分析思路,以及具体的案例分析。在使用本指导分析处置惩罚崩溃日志前,必要开辟者了解C/C++程序堆栈信息的根本知识。
Cpp Crash异常检测本领

历程崩溃基于posix信号机制,目前主要支持对以下崩溃异常信号的处置惩罚:
信号值(signo)信号解释触发原因4SIGILL非法指令。历程实验了非法、格式错误、未知或特权指令。5SIGTRAP断点或陷阱异常。异常或trap指令发生。6SIGABRT历程终止。历程异常终止,通常为历程自身调用标准函数库的abort()函数。7SIGBUS非法内存访问。历程访问了对齐或者不存在的物理地址。8SIGFPE浮点异常。历程实验了错误的算术运算,如除数为0、浮点溢出、整数溢出等。11SIGSEGV无效内存访问。历程访问了无效内存引用。16SIGSTKFLT栈错误。处置惩罚器实验了错误的栈操作,如栈空时弹出、栈满时压入。31SIGSYS错误的体系调用。体系调用时使用了错误或非法参数。 以上部门故障信号,根据具体的场景还有二级分类(code):
SIGILL是一个在Unix和类Unix操作体系中的信号,它表示非法指令异常。SIGILL信号通常由以下几种类型的标题场景引起:
二级分类信号字符串解释触发原因1ILL_ILLOPC非法操作码异常这种异常通常发生在实验不被CPU支持的指令时,或者在实验实验特权指令时。2ILL_ILLOPN非法操作数异常这种异常通常发生在指令使用了不正确的操作数,或者是操作数的类型不正确时。3ILL_ILLADR非法地址异常这种异常通常发生在程序实验访问无效的内存地址时,或者是在实验实验未对齐的内存访问时。4ILL_ILLTRP非法陷阱异常这种异常通常发生在程序实验实验一个非法的陷阱指令时,或者是在实验实验一个未定义的操作时。5ILL_PRVOPC特权操作码异常这种异常通常发生在普通用户实验实验特权指令时。6ILL_PRVREG特权寄存器异常这种异常通常发生在普通用户实验访问特权寄存器时。7ILL_COPROC协处置惩罚器异常这种异常通常发生在程序实验使用未定义的协处置惩罚器指令时。8ILL_BADSTK无效的堆栈异常这种异常通常发生在程序实验在无效的堆栈地址上实验操作时,或者是在堆栈溢出时。 SIGTRAP信号通常用于调试和跟踪程序的实验。下面是上面列出的四种SIGTRAP信号类别的标题场景介绍:
二级分类信号字符串解释触发原因1TRAP_BRKPT软件断点这个信号是由软件断点引起的,当程序实验到设置的断点时会触发该信号。软件断点通常用于调试程序,可以在程序的关键位置设置断点,以便在调试时暂停程序的实验并检查变量值等信息。2TRAP_TRACE单步调试这个信号是由单步实验引起的,当程序实验单个指令时会触发该信号。单步实验通常用于调试程序,可以渐渐实验程序并检查每个指令的实验结果。3TRAP_BRANCH分支跟踪这个信号是由分支指令引起的,当程序实验分支指令时会触发该信号。分支指令通常用于控制程序的实验流程,比方if语句和循环语句等。4TRAP_HWBKPT硬件断点这个信号是由硬件断点引起的,当程序实验到设置的硬件断点时会触发该信号。硬件断点通常用于调试程序,可以在程序的关键位置设置断点,以便在调试时暂停程序的实验并检查变量值等信息。与软件断点差别的是,硬件断点是由CPU硬件实现的,因此可以在程序实验过程中实时检测断点是否被触发。 SIGBUS是一种由操作体系向历程发送的信号,通常表示内存访问错误。其中,差别的信号类别表示差别的错误场景:
二级分类信号字符串解释触发原因1BUS_ADRALN内存地址对齐错误这种错误通常发生在实验访问未对齐的内存地址时,比方实验访问一个4字节整数的非偶数地址。2BUS_ADRERR非法内存地址错误这种错误通常发生在实验访问不属于历程地址空间的内存地址时,比方实验访问一个空指针。3BUS_OBJERR对象访问错误这种错误通常发生在实验访问一个已经被删除或未初始化的对象时。4BUS_MCEERR_AR硬件内存校验错误发生在访问内存时检测到校验和错误。5BUS_MCEERR_AO硬件内存校验错误发生在访问内存时检测到地址和校验和错误。 SIGFPE是一个信号,它表示浮点异常或算术异常。下面是这些SIGFPE信号类别的标题场景:
二级分类信号字符串解释触发原因1FPE_INTDIV整数除法错误这个信号表示整数除法中的除数为零的情况。当一个程序实验进行整数除法,但除数为零时,会发出这个信号。2FPE_INTOVF整数溢出错误这个信号表示整数除法中的除数为负数的情况。当一个程序实验进行整数除法,但除数为负数时,会发出这个信号。3FPE_FLTDIV浮点除法错误这个信号表示浮点数除法中的除数为零的情况。当一个程序实验进行浮点数除法,但除数为零时,会发出这个信号。4FPE_FLTOVF浮点溢出错误这个信号表示浮点数除法中的除数为负数的情况。当一个程序实验进行浮点数除法,但除数为负数时,会发出这个信号。5FPE_FLTUND浮点下溢错误这个信号表示浮点数除法中的除数为零的情况。当一个程序实验进行浮点数除法,但除数为零时,会发出这个信号。6FPE_FLTRES浮点结果未定义错误这个信号表示浮点数除法中的除数为正数的情况。当一个程序实验进行浮点数除法,但除数为正数时,会发出这个信号。7FPE_FLTINV无效浮点操作错误这个信号表示浮点数除法中的除数为负数的情况。当一个程序实验进行浮点数除法,但除数为负数时,会发出这个信号。8FPE_FLTSUB浮点陷阱错误这个信号表示浮点数除法中的除数为零的情况。当一个程序实验进行浮点数除法,但除数为零时,会发出这个信号。 SIGSEGV是一种信号,它表示历程试图访问一个不属于它的内存地址,或者试图访问一个已被操作体系标记为不可访问的内存地址。SIGSEGV信号通常是由以下两种情况引起的:
二级分类信号字符串解释触发原因1SEGV_MAPERR不存在的内存地址历程试图访问一个不存在的内存地址,或者试图访问一个没有映射到历程地址空间的内存地址。这种情况通常是由于程序中的指针错误或内存泄漏引起的。2SEGV_ACCERR不可访问的内存地址历程试图访问一个已被操作体系标记为不可访问的内存地址,比方只读内存或没有实验权限的内存。这种情况通常是由于程序中的缓冲区溢出或者试图修改只读内存等错误引起的。 二级分类(code)除了以上根据信号值(signo)维度分类,还可以根据信号产生的原因维度分类。其中根据信号值(signo)维度分类是每个信号值(signo)特有的,根据信号产生的原因维度分类是所有信号值(signo)共有的,当前已有信号产生原因分类的code值如下:
二级分类信号字符串解释触发原因0SI_USER用户空间信号该信号是由用户空间的历程发送给另一个历程的,通常是通过 kill() 体系调用发送的。比方,当用户在终端中按下Ctrl+C时,会发送一个SIGINT信号给前台历程组中的所有历程。0x80SI_KERNEL内核信号该信号是由内核发送给历程的,通常是由内核检测到某些错误或异常情况时发出的。比方,当历程访问无效的内存地址或者实验非法指令时,内核会发送一个SIGSEGV信号给历程。-1SI_QUEUEsigqueue()函数信号该信号是由sigqueue()体系调用发送的,可以携带一个附加的整数值和一个指针。通常用于历程间高级通信,比方传递数据或者关照历程某个事件已经发生。-2SI_TIMER定时器信号该信号是由定时器发送的,通常用于定时任务或者周期性任务的实验。比方,当一个定时器到期时,内核会向历程发送一个SIGALRM信号。-3SI_MESGQ消息队列信号该信号是由消息队列发送的,通常用于历程间通信。比方,当一个历程向一个消息队列发送消息时,内核会向接收历程发送一个SIGIO信号。-4SI_ASYNCIO异步I/O信号该信号是由异步I/O操作发送的,通常用于非阻塞I/O操作。比方,当一个文件形貌符上的I/O操作完成时,内核会向历程发送一个SIGIO信号。-5SI_SIGIO同步I/O信号该信号是由异步I/O操作发送的,通常用于非阻塞I/O操作。比方,当一个文件形貌符上的I/O操作完成时,内核会向历程发送一个SIGIO信号。-6SI_TKILLtkill()函数信号该信号是由tkill()体系调用发送的,与kill()体系调用类似,但是可以指定发送信号的线程ID。通常用于多线程程序中,向指定线程发送信号。 标题定位步调与思路

崩溃日志获取

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

日志格式 - 空指针故障场景
该场景会在日志中打印出提示信息,表明故障很有可能是因为空指针解引用导致
以下是一份DevEco Studio归档在FaultLog的历程崩溃日志的焦点内容,与设备/data/log/faultlog/faultlogger下归档的日志内容相同。
  1. Generated by HiviewDFX@HarmonyOS
  2. ================================================================
  3. Device info:HarmonyOS 3.2        <- 设备信息
  4. Build info:HarmonyOS 5.0.0.23    <- 版本信息
  5. Fingerprint:cdf52fd0cc328fc432459928f3ed8edfe8a72a92ee7316445143bed179138073 <- 标识故障特征
  6. Module name:crasher_cpp            <- 模块名
  7. Timestamp:2024-05-06 20:10:51.000  <- 故障发生时间戳
  8. Pid:9623   <- 进程号
  9. Uid:0         <- 用户ID
  10. Process name:./crasher_cpp         <- 进程名称
  11. Process life time:1s               <- 进程存活时间
  12. Reason:Signal:SIGSEGV(SEGV_MAPERR)@0x00000004  probably caused by NULL pointer dereference   <- 故障原因和空指针提示
  13. Fault thread info:
  14. Tid:9623, Name:crasher_cpp         <- 故障线程号,线程名
  15. #00 pc 00008d22 /system/bin/crasher_cpp(TestNullPointerDereferenceCrash0()+22)(adfc673300571d2da1e47d1d12f48b44)  <- 调用栈
  16. #01 pc 000064d1 /system/bin/crasher_cpp(DfxCrasher::ParseAndDoCrash(char const*) const+160)(adfc673300571d2da1e47d1d12f48b44)
  17. #02 pc 00006569 /system/bin/crasher_cpp(main+92)(adfc673300571d2da1e47d1d12f48b44)
  18. #03 pc 00072b98 /system/lib/ld-musl-arm.so.1(libc_start_main_stage2+56)(d820b1827e57855d4f9ed03ba5dfea83)
  19. #04 pc 00004e28 /system/bin/crasher_cpp(_start_c+84)(adfc673300571d2da1e47d1d12f48b44)
  20. #05 pc 00004dcc /system/bin/crasher_cpp(adfc673300571d2da1e47d1d12f48b44)
  21. Registers:   <- 故障现场寄存器
  22. r0:ffffafd2 r1:00000004 r2:00000001 r3:00000000
  23. r4:ffd27e39 r5:0096e000 r6:00000a40 r7:0096fdfc
  24. r8:f7ba58d5 r9:f7baea86 r10:f7cadd38
  25. fp:ffd27308 ip:f7cb2078 sp:ffd272a0 lr:f7c7ab98 pc:0096ad22
  26. Memory near registers:  <-  故障现场寄存器附近内存
  27. r4([stack]):
  28.     ffd27e30 72656873
  29.     ffd27e34 7070635f
  30.     ...
  31.     ffd27eac 3d73746f
  32. r5(/system/bin/crasher_cpp):
  33.     0096dff8 00000000
  34.     0096dffc 0096717d
  35.     ...
  36.     0096e074 00000000
  37. r7(/system/lib/ld-musl-arm.so.1):
  38.     f7cabb58 00000000
  39.     f7cabb5c 0034ba00
  40.     ...
  41.     f7cabbd4 00000000
  42. r8(/system/lib/ld-musl-arm.so.1):
  43.     f7ba58cc 63637573
  44.     f7ba58d0 2e737365
  45.     ...
  46.     f7ba5948 70206269
  47. r9(/system/lib/ld-musl-arm.so.1):
  48.     f7baea7c 20746f6e
  49.     f7baea80 6e756f66
  50.     ...
  51.     f7baeaf8 25206e69
  52. r10([anon:ld-musl-arm.so.1.bss]):
  53.     f7cadd30 00000000
  54.     f7cadd34 00000000
  55.     ...
  56.     f7caddac 00000000
  57. r12([anon:ld-musl-arm.so.1.bss]):
  58.     f7cb2070 56726562
  59.     f7cb2074 65756c61
  60.     ...
  61.     f7cb20ec 00000000
  62. sp([stack]):
  63.     ffd27328 00000000
  64.     ffd2732c 00966dd0
  65.     ...
  66.     ffd273a4 00000004
  67. pc(/system/bin/crasher_cpp):
  68.     00966dc8 e1a0d00c
  69.     00966dcc eb000000
  70.     ...
  71.     00966e44 e5907008
  72. pc(/system/bin/crasher_cpp):
  73.     00966dc8 e1a0d00c
  74.     00966dcc eb000000
  75.     ...
  76.     00966e44 e5907008
  77. FaultStack:   <- 崩溃线程的栈地址空间
  78.     ffd27260 00000000
  79.     ffd27264 f7cac628
  80.     ...
  81.     ffd2729c 0096ad1f
  82. sp0:ffd272a0 0096fdfc <- #00栈顶
  83.     ffd272a4 009684d3
  84. sp1:ffd272a8 00000001
  85.     ffd272ac 73657408
  86.     ffd272b0 f7590074
  87.     ...
  88.     ffd272dc 0096856d
  89. sp2:ffd272e0 ffd27334
  90.     ffd272e4 ffd27334
  91.     ffd272e8 00000002
  92.     ....
  93.     ffd272f4 f7bfbb9c
  94. sp3:ffd272f8 00000000
  95.     ffd272fc ffd27334
  96. Maps:   <-  故障时进程maps
  97. 962000-966000 r--p 00000000 /system/bin/crasher_cpp
  98. 966000-96c000 r-xp 00003000 /system/bin/crasher_cpp
  99. 96c000-96f000 r--p 00008000 /system/bin/crasher_cpp
  100. 96f000-970000 rw-p 0000a000 /system/bin/crasher_cpp
  101. 149f000-14a0000 ---p 00000000 [heap]
  102. 14a0000-14a2000 rw-p 00000000 [heap]
  103. ...
  104. f7b89000-f7be1000 r--p 00000000 /system/lib/ld-musl-arm.so.1
  105. f7be1000-f7ca9000 r-xp 00057000 /system/lib/ld-musl-arm.so.1
  106. f7ca9000-f7cab000 r--p 0011e000 /system/lib/ld-musl-arm.so.1
  107. f7cab000-f7cad000 rw-p 0011f000 /system/lib/ld-musl-arm.so.1
  108. f7cad000-f7cbc000 rw-p 00000000 [anon:ld-musl-arm.so.1.bss]
  109. ffd07000-ffd28000 rw-p 00000000 [stack]
  110. ffff0000-ffff1000 r-xp 00000000 [vectors]
  111. OpenFiles:   <-  故障时进程打开文件Fd信息
  112. 0->/dev/pts/1 native object of unknown type 0
  113. 1->/dev/pts/1 native object of unknown type 0
  114. 2->/dev/pts/1 native object of unknown type 0
  115. 3->socket:[67214] native object of unknown type 0
  116. ...
  117. 11->pipe:[67219] native object of unknown type 0
  118. 12->socket:[29074] native object of unknown type 0
  119. 25->/dev/ptmx native object of unknown type 0
  120. 26->/dev/ptmx native object of unknown type 0
  121. HiLog:   <-  故障时的Hilog日志
  122. 05-06 20:10:51.301  9623  9623 E C03f00/MUSL-SIGCHAIN: signal_chain_handler call 2 rd sigchain action for signal: 11
  123. 05-06 20:10:51.306  9623  9623 I C02d11/DfxSignalHandler: DFX_SigchainHandler :: sig(11), pid(9623), tid(9623).
  124. 05-06 20:10:51.307  9623  9623 I C02d11/DfxSignalHandler: DFX_SigchainHandler :: sig(11), pid(9623), processName(./crasher_cpp), threadName(crasher_cpp).
  125. 05-06 20:10:51.389  9623  9623 I C02d11/DfxSignalHandler: processdump have get all resgs
复制代码
日志格式 - 栈溢出故障场景
该场景会在日志中打印出提示信息,表明故障很有可能是因为栈溢出导致。焦点日志如下:
  1. Generated by HiviewDFX@HarmonyOS
  2. ================================================================
  3. Device info:HarmonyOS 3.2            <- 设备信息
  4. Build info:HarmonyOS 5.0.0.23        <- 版本信息
  5. Fingerprint:8bc3343f50024204e258b8dce86f41f8fcc50c4d25d56b24e71fe26c0a23e321  <- 标识故障特征
  6. Module name:crasher_cpp                <- 模块名
  7. Timestamp:2024-05-06 20:18:24.000      <- 故障发生时间戳
  8. Pid:9838                               <- 进程号
  9. Uid:0                                  <- 用户ID
  10. Process name:./crasher_cpp             <- 进程名称
  11. Process life time:2s                   <- 进程存活时间
  12. Reason:Signal:SIGSEGV(SEGV_ACCERR)@0xf76b7ffc  current thread stack low address = 0xf76b8000, probably caused by stack-buffer-overflow    <- 故障原因和栈溢出提示
  13. ...
复制代码
日志格式 - 栈覆盖故障场景
在栈覆盖场景下,由于栈上内存被踩,无法成功回溯栈帧,该场景会在日志中打印出提示信息,说明回栈失败并实验从线程栈里解析获取不可靠的调用栈,尽可能提供开辟者信息以分析标题。焦点日志如下:
  1. Generated by HiviewDFX@HarmonyOS
  2. ================================================================
  3. Device info:HarmonyOS 3.2               <- 设备信息
  4. Build info:HarmonyOS 5.0.0.23           <- 版本信息
  5. Fingerprint:79b6d47b87495edf27135a83dda8b1b4f9b13d37bda2560d43f2cf65358cd528    <- 标识故障特征
  6. Module name:crasher_cpp                   <- 模块名
  7. Timestamp:2024-05-06 20:27:23.2035266415  <- 故障发生时间戳
  8. Pid:10026                                 <- 进程号
  9. Uid:0                                     <- 用户ID
  10. Process name:./crasher_cpp                <- 进程名称
  11. Process life time:1s                      <- 进程存活时间
  12. Reason:Signal:SIGSEGV(SEGV_MAPERR)@0000000000  probably caused by NULL pointer dereference      <- 故障原因
  13. LastFatalMessage: Failed to unwind stack, try to get unreliable call stack from #02 by reparsing thread stack   <- 尝试从线程栈里获取不可靠的堆栈
  14. Fault thread info:
  15. Tid:10026, Name:crasher_cpp               <- 故障线程号,线程名
  16. #00 pc 00000000 Not mapped
  17. #01 pc 00008d22 /system/bin/crasher_cpp(TestNullPointerDereferenceCrash0()+22)(adfc673300571d2da1e47d1d12f48b44)  <- 调用栈
  18. #02 pc 000064d1 /system/bin/crasher_cpp(DfxCrasher::ParseAndDoCrash(char const*) const+160)(adfc673300571d2da1e47d1d12f48b44)
  19. #03 pc 00006569 /system/bin/crasher_cpp(main+92)(adfc673300571d2da1e47d1d12f48b44)
  20. #04 pc 00072b98 /system/lib/ld-musl-arm.so.1(libc_start_main_stage2+56)(d820b1827e57855d4f9ed03ba5dfea83)
  21. ...
复制代码
日志格式 - 异步线程场景故障
(目前支持ARM64架构,且在调试应用(HAP_DEBUGGABLE)下开启)
当异步线程发生崩溃后,把提交该异步任务的线程的栈也打印出来,资助定位由于异步任务提交者造成的崩溃标题。崩溃线程的调用栈和其提交线程的调用栈用SubmitterStacktrace分割开。焦点日志如下:
  1. Generated by HiviewDFX@HarmonyOS
  2. ================================================================
  3. Device info:HarmonyOS 3.2                 <- 设备信息
  4. Build info:HarmonyOS 5.0.0.23             <- 版本信息
  5. Fingerprint:8bc3343f50024204e258b8dce86f41f8fcc50c4d25d56b24e71fe26c0a23e321  <- 标识故障特征
  6. Module name:crasher_cpp                     <- 模块名
  7. Timestamp:2024-05-06 20:28:24.000           <- 故障发生时间戳
  8. Pid:9838                                    <- 进程号
  9. Uid:0                                       <- 用户ID
  10. Process name:./crasher_cpp                  <- 进程名称
  11. Process life time:2s                        <- 进程存活时间
  12. Reason:Signal:SIGSEGV(SI_TKILL)@0x000000000004750  from:18256:0  <- 故障原因
  13. Fault thread info:
  14. Tid:18257, Name:crasher_cpp                 <- 故障线程号,线程名
  15. #00 pc 000054e6 /system/bin/ld-musl-aarch64.so.l(raise+228)(adfc673300571d2da1e47d1d12f48b44)  <- 调用栈
  16. #01 pc 000054f9 /system/bin/crasher_cpp(CrashInSubThread(void*)+56)(adfc673300571d2da1e47d1d12f48b50)
  17. #02 pc 000054f9 /system/bin/ld-musl-aarch64.so.l(start+236)(adfc673300571d2da1e47d1d12f48b44)
  18. ========SubmitterStacktrace========       <- 任务异常时打印任务提交者调用栈
  19. #00 pc 000094dc /system/bin/crasher_cpp(DfxCrasher::AsyncStacktrace()+36)(adfc673300571d2da1e47d1d12f48b50)
  20. #01 pc 00009a58 /system/bin/crasher_cpp(DfxCrasher::ParseAndDoCrash(char const*) const+232)(adfc673300571d2da1e47d1d12f48b50)
  21. #02 pc 00009b40 /system/bin/crasher_cpp(main+140)(adfc673300571d2da1e47d1d12f48b50)
  22. #03 pc 0000a4e1c /system/bin/ld-musl-aarch64.so.l(libc_start_main_stage2+68)(adfc673300571d2da1e47d1d12f48b44)
  23. ...
复制代码
基于崩溃栈定位行号

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


方式二:通过SDK llvm-addr2line 工具定位行号
方式三:通过 DevEco Studio hstack 工具解析堆栈信息
hstack是DevEco Studio为开辟人员提供的用于将release应用混淆后的crash堆栈还原为源码对应堆栈的工具,支持Windows、Mac、Linux三个平台。DevEco Studio hstack使用指南
结合业务检视代码

根据基于崩溃栈定位行号章节中介绍的三种方式获取到栈顶对应的行号后,回到代码中,检视上下文。如下图所示,hello.cpp中的48行是一个空指针解引用的代码标题。


本场景是一个故障构造的应用,实际的场景往往不会这么简单,必要结合实际业务进行分析。
反汇编(可选)

一样平常而言,如果是比较明确的标题,反编译定位到代码行就可以或许定位;较少数的情况,比如定位到某一行里面调用的方法有多个参数,参数又涉及到结构体等,就必要借助反汇编来进一步分析。
  1. objdump -S xxx.so > xxx.txt
  2. objdump -d xxxx                    对 xxxx 文件反汇编
  3. objdump -S -l xxxx                 对 xxxx 文件反汇编,同时将指令对应的源码行显示出来
复制代码
CppCrash 常见标题分类与原因


分析案例

本章节从信号分类、标题场景分类和维测工具分类三个维度来对CppCrash典型标题进行分析和归纳。
信号分类,侧重对常见崩溃信号覆盖介绍,各类信号提供一个典型案例。
标题场景分类,侧重归纳目前高频标题背后的通用场景,各类场景提供一个典型案例。
维测工具分类,侧重总结各类维测工具如果使用类分析相应的标题,各类工具提供一个典型案例。
从信号维度分析标题

类型一:SIGSEGV类崩溃标题
SIGSEGV信号陪同着程序发生段错误(Segmentation Fault)故障,其故障场景为当程序试图访问不被答应访问的内存区域(比如,实验写一块属于操作体系的内存),或以错误的类型访问内存区域(比如,实验写一块只读内存)。概括有如下几点:

SIGSEGV在许多时候是由于指针越界引起的,但并不是所有的指针越界都会引发SIGSEGV。如果不解引用越界指针,是不会引起SIGSEGV崩溃的。而且即使解引用了一个越界的指针,也不一定会引起SIGSEGV。SIGSEGV涉及到操作体系、C库、编译器、链接器各方面的内容,以如下具体的例子来说明。
类型二:SIGABRT类崩溃标题
SIGABRT信号被发送到历程,告诉历程中止。既可以历程自己调用C标准库的abort()函数,信号通常由历程自己发起,也可以跟其他信号一样从外部发送给历程。
从场景维度分析标题

类型一:内存访问类崩溃标题
标题背景
每次崩溃地址0x7f82764b70都在libace_napi_ark.z.so的可读可实验段上。崩溃原因是必要对地址进行写操作,而对应的maps段只有可读、可实验权限没有写权限,当历程试图访问不被答应访问的内存区域时,历程发生内存访问类崩溃。
  1. 7f82740000-7f8275c000 r--p 00000000 /system/lib64/libace_napi_ark.z.so
  2. 7f8275c000-7f8276e000 r-xp 0001b000 /system/lib64/libace_napi_ark.z.so <-崩溃地址落在该地址区间
  3. 7f8276e000-7f82773000 r--p 0002c000 /system/lib64/libace_napi_ark.z.so
  4. 7f82773000-7f82774000 rw-p 00030000 /system/lib64/libace_napi_ark.z.so
复制代码
崩溃调用栈如下图:


定位思路
每次地址出错都很有规律,但node地址不应该落在libace_napi_ark.z.so,从此类标题的现象来看,很有可能是踩内存标题。踩内存标题可使用ASAN工具排查标题。于是后续使用ASAN版本进行压测复现,也找到了稳定必现的场景。ASAN版本检测出来的标题也和上面崩溃栈反映的标题一致。堆栈报的是heap-use-after-free,实际上是对同一个address进行重复释放,只是在重复释放那次操作时,使用该地址去访问了其对象成员,进而报出了UAF标题。
ASAN焦点日志如下:
  1. =================================================================
  2. ==appspawn==2029==ERROR: AddressSanitizer: heap-use-after-free on address 0x003a375eb724 at pc 0x002029ba8514 bp 0x007fd8175710 sp 0x007fd8175708
  3. READ of size 1 at 0x003a375eb724 thread T0 (thread name)
  4.     # 0 0x2029ba8510  (/system/asan/lib64/platformsdk/libark_jsruntime.so+0xca8510) panda::ecmascript::Node::IsUsing() const at arkcompiler/ets_runtime/ecmascript/ecma_global_storage.h:82:16
  5. (inlined by) panda::JSNApi::DisposeGlobalHandleAddr(panda::ecmascript::EcmaVM const*, unsigned long) at arkcompiler/ets_runtime/ecmascript/napi/jsnapi.cpp:749:67 BuildID[md5/uuid]=9a18e2ec0dc8a83216800b2f0dd7b76a
  6.     # 1 0x403ee94d30  (/system/asan/lib64/libace.z.so+0x6194d30) panda::CopyableGlobal<panda::ObjectRef>::Free() at arkcompiler/ets_runtime/ecmascript/napi/include/jsnapi.h:1520:9
  7. (inlined by) panda::CopyableGlobal<panda::ObjectRef>::Reset() at arkcompiler/ets_runtime/ecmascript/napi/include/jsnapi.h:189:9
  8. (inlined by) OHOS::Ace::Framework::JsiType<panda::ObjectRef>::Reset() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsi/jsi_types.inl:112:13
  9. (inlined by) OHOS::Ace::Framework::JsiWeak<OHOS::Ace::Framework::JsiObject>::~JsiWeak() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsi/jsi_ref.h:167:16
  10. (inlined by) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:44:5 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  11.     # 2 0x403ee9296c  (/system/asan/lib64/libace.z.so+0x619296c) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:42:5
  12. (inlined by) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:42:5 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  13.     # 3 0x403ed9b130  (/system/asan/lib64/libace.z.so+0x609b130) OHOS::Ace::Referenced::DecRefCount() at foundation/arkui/ace_engine/frameworks/base/memory/referenced.h:76:13
  14. (inlined by) OHOS::Ace::RefPtr<OHOS::Ace::Framework::ViewFunctions>::~RefPtr() at foundation/arkui/ace_engine/frameworks/base/memory/referenced.h:148:22 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  15.     # 4 0x403ed9b838  (/system/asan/lib64/libace.z.so+0x609b838) OHOS::Ace::RefPtr<OHOS::Ace::Framework::ViewFunctions>::Reset() at foundation/arkui/ace_engine/frameworks/base/memory/referenced.h:163:9
  16. (inlined by) OHOS::Ace::Framework::JSViewFullUpdate::~JSViewFullUpdate() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view.cpp:159:21 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  17.     # 5 0x403ed9bf24  (/system/asan/lib64/libace.z.so+0x609bf24) OHOS::Ace::Framework::JSViewFullUpdate::~JSViewFullUpdate() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view.cpp:157:1
  18. (inlined by) OHOS::Ace::Framework::JSViewFullUpdate::~JSViewFullUpdate() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view.cpp:157:1 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  19. ...
  20. freed by thread T0 (thread name) here:
  21.     # 0 0x2024ed3abc  (/system/asan/lib64/libclang_rt.asan.so+0xd3abc)
  22.     # 1 0x2029ba8424  (/system/asan/lib64/platformsdk/libark_jsruntime.so+0xca8424) std::__h::__function::__value_func<void (unsigned long)>::operator()[abi:v15004](unsigned long&&) const at prebuilts/clang/ohos/linux-x86_64/llvm/bin/../include/libcxx-ohos/include/c++/v1/__functional/function.h:512:16
  23. (inlined by) std::__h::function<void (unsigned long)>::operator()(unsigned long) const at prebuilts/clang/ohos/linux-x86_64/llvm/bin/../include/libcxx-ohos/include/c++/v1/__functional/function.h:1197:12
  24. (inlined by) panda::ecmascript::JSThread::DisposeGlobalHandle(unsigned long) at arkcompiler/ets_runtime/ecmascript/js_thread.h:604:9
  25. (inlined by) panda::JSNApi::DisposeGlobalHandleAddr(panda::ecmascript::EcmaVM const*, unsigned long) at arkcompiler/ets_runtime/ecmascript/napi/jsnapi.cpp:752:24 BuildID[md5/uuid]=9a18e2ec0dc8a83216800b2f0dd7b76a
  26.     # 2 0x403ee94b68  (/system/asan/lib64/libace.z.so+0x6194b68) panda::CopyableGlobal<panda::FunctionRef>::Free() at arkcompiler/ets_runtime/ecmascript/napi/include/jsnapi.h:1520:9
  27. (inlined by) panda::CopyableGlobal<panda::FunctionRef>::Reset() at arkcompiler/ets_runtime/ecmascript/napi/include/jsnapi.h:189:9
  28. (inlined by) OHOS::Ace::Framework::JsiType<panda::FunctionRef>::Reset() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsi/jsi_types.inl:112:13
  29. (inlined by) OHOS::Ace::Framework::JsiWeak<OHOS::Ace::Framework::JsiFunction>::~JsiWeak() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/engine/jsi/jsi_ref.h:167:16
  30. (inlined by) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:44:5 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  31.     # 3 0x403ee9296c  (/system/asan/lib64/libace.z.so+0x619296c) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:42:5
  32. (inlined by) OHOS::Ace::Framework::ViewFunctions::~ViewFunctions() at foundation/arkui/ace_engine/frameworks/bridge/declarative_frontend/jsview/js_view_functions.h:42:5 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  33.     # 4 0x403ed9b130  (/system/asan/lib64/libace.z.so+0x609b130) OHOS::Ace::Referenced::DecRefCount() at foundation/arkui/ace_engine/frameworks/base/memory/referenced.h:76:13
  34. (inlined by) OHOS::Ace::RefPtr<OHOS::Ace::Framework::ViewFunctions>::~RefPtr() at foundation/arkui/ace_engine/frameworks/base/memory/referenced.h:148:22 BuildID[md5/uuid]=1330f8b9be73bdb76ae18107c2a60ca1
  35. ...
  36. previously allocated by thread T0 (thread name) here:
  37.     # 0 0x2024ed3be4  (/system/asan/lib64/libclang_rt.asan.so+0xd3be4)
  38.     # 1 0x2029ade778  (/system/asan/lib64/platformsdk/libark_jsruntime.so+0xbde778) panda::ecmascript::NativeAreaAllocator::AllocateBuffer(unsigned long) at arkcompiler/ets_runtime/ecmascript/mem/native_area_allocator.cpp:98:17 BuildID[md5/uuid]=9a18e2ec0dc8a83216800b2f0dd7b76a
  39.     # 2 0x2029a39064  (/system/asan/lib64/platformsdk/libark_jsruntime.so+0xb39064) std::__h::enable_if<!std::is_array_v<panda::ecmascript::NodeList<panda::ecmascript::WeakNode>>, panda::ecmascript::NodeList<panda::ecmascript::WeakNode>*>::type panda::ecmascript::NativeAreaAllocator::New<panda::ecmascript::NodeList<panda::ecmascript::WeakNode>>() at arkcompiler/ets_runtime/ecmascript/mem/native_area_allocator.h:61:19
  40. (inlined by) unsigned long panda::ecmascript::EcmaGlobalStorage<panda::ecmascript::Node>::NewGlobalHandleImplement<panda::ecmascript::WeakNode>(panda::ecmascript::NodeList<panda::ecmascript::WeakNode>**, panda::ecmascript::NodeList<panda::ecmascript::WeakNode>**, unsigned long) at arkcompiler/ets_runtime/ecmascript/ecma_global_storage.h:565:34
  41. (inlined by) panda::ecmascript::EcmaGlobalStorage<panda::ecmascript::Node>::SetWeak(unsigned long, void*, void (*)(void*), void (*)(void*)) at arkcompiler/ets_runtime/ecmascript/ecma_global_storage.h:455:26 BuildID[md5/uuid]=9a18e2ec0dc8a83216800b2f0dd7b76a
  42.     # 3 0x2029ba5620  (/system/asan/lib64/platformsdk/libark_jsruntime.so+0xca5620) std::__h::__function::__value_func<unsigned long (unsigned long, void*, void (*)(void*), void (*)(void*))>::operator()[abi:v15004](unsigned long&&, void*&&, void (*&&)(void*), void (*&&)(void*)) const at prebuilts/clang/ohos/linux-x86_64/llvm/bin/../include/libcxx-ohos/include/c++/v1/__functional/function.h:512:16
  43. (inlined by) std::__h::function<unsigned long (unsigned long, void*, void (*)(void*), void (*)(void*))>::operator()(unsigned long, void*, void (*)(void*), void (*)(void*)) const at prebuilts/clang/ohos/linux-x86_64/llvm/bin/../include/libcxx-ohos/include/c++/v1/__functional/function.h:1197:12
  44. (inlined by) panda::ecmascript::JSThread::SetWeak(unsigned long, void*, void (*)(void*), void (*)(void*)) at arkcompiler/ets_runtime/ecmascript/js_thread.h:610:16
  45. (inlined by) panda::JSNApi::SetWeak(panda::ecmascript::EcmaVM const*, unsigned long) at arkcompiler/ets_runtime/ecmascript/napi/jsnapi.cpp:711:31 BuildID[md5/uuid]=9a18e2ec0dc8a83216800b2f0dd7b76a
  46. ...
复制代码
根据堆栈继续分析,
JsiWeak析构或重置的时候会触发其成员(类型为JsiObject/JsiValue/JsiFunction)父类JsiType中CopyableGlobal被释放,如下图:


运行时在GC过程中IterateWeakEcmaGlobalStorage,会对无callback的WeakNode调用DisposeGlobalHandle操作,也对其进行释放,如下图:


因此,对于同一个WeakNode,可能会存在两个入口释放。如果是GC过程中IterateWeakEcmaGlobalStorage先释放,因为无callback回调关照到JsiWeak进行整理,JsiWeak那边仍保存一个对已释放的WeakNode引用,即CopyableGlobal;当前面讲的WeakNode所在的NodeList被整体释放,归还给操作体系后,JsiWeak处保存的CopyableGlobal再释放,就会存在double-free标题。


修改方法
JsiWeak调用SetWeakCallback,传入callback,在GC过程中IterateWeakEcmaGlobalStorage释放WeakNode时,关照JsiWeak对其保存的CopyableGlobal进行重置,确保同一个地址不被double-free。
建议与总结
使用内存时应思量是否存在重复释放或者未释放的可能,别的定位内存访问类崩溃标题(一样平常是SIGSEGV类型标题)时,如果根据崩溃栈分析标题无头绪时,应优先思量跑ASAN版本复现标题。
类型二:多线程类标题
标题背景
napi_env释放后仍被使用。
标题场景
napi接口的env传入非法,崩溃栈直接挂在NativeEngineInterface::ClearLastError()中,根据日志打印env地址定位,发现是env被释放后仍然被使用。


焦点崩溃栈如下:


修改方法
一个线程的创建的env,不要传给另一个线程使用。
建议与总结
对于多线程类标题可以打开方舟多线程检测功能,可以或许更加方便定位标题,见工具类方舟多线程检测章节。
注:napi接口中的env,是引擎创建时候的arkNativeEngine。
类型三:生命周期类标题
标题背景
开辟者在写native代码创建napi_value时,必要配合napi_handle_scope一起使用。napi_handle_scope的作用是管理napi_value的生命周期,napi_value只能在napi_handle_scope的作用域范围内进行使用,离开napi_handle_scope作用域范围后,napi_value及它所持有的js对象的生命周期不再得到保护,一旦引用计数为0,就会被GC接纳掉,此时再去使用napi_value就会访问已释放的内存,产生标题。
标题场景
napi_value实在是个裸指针(结构体指针),其作用是持有js对象,用于保持js对象的生命周期,保证js对象不被GC当成垃圾对象接纳。napi_handle_scope用来管理napi_value,离开napi_handle_scope作用域之后,napi_value由GC接纳,napi_value不再持有js对象(不再保护js对象生命周期)。
定位思路
根据崩溃栈反编译找到出现标题的napi接口的上层接口,在上层接口内找到出标题的napi_value,检查napi_value的使用范围是否超出了napi_handle_scope的作用域范围。
案例
napi_value超出NAPI框架的scope,如下:


js侧通过Add接口添加数据,native侧以napi_value保存到vector,js侧通过get接口获取添加的数据,native侧将保存的napi_value以数组情势返回回去,然后js侧读取数据的属性。出现报错:Can not get Prototype on non ECMA Object。跨napi的native_value未使用napi_ref保存,导致native_value失效。
注:NAPI框架的scope即napi_handle_scope,napi开辟者可以通过napi_handle_scope来管理napi_value的生命周期。框架层的scope嵌入在js call native的端到端流程中,即进入开辟者自己写的native方法前open scope,native方法竣过后close scope。
类型四:指针类标题
标题背景
智能指针使用之前未判空,造成历程运行时发生空指针解引用崩溃标题。
标题影响
历程发生崩溃,影响历程的稳定运行,非预期退出。
定位思路


空指针类型崩溃可以从故障原因得到提示信息。通过llvm-addr2line解行号发现业务代码中在使用智能指针之前未对智能指针判空,对清闲址进行访问导致崩溃产生。
修复方法
对所有使用该指针的地方进行保护性判空。
建议与总结
指针在使用之前应该要进行判空处置惩罚,防止访问空指针造成历程崩溃退出。
配合工具分析标题

工具一:ASAN
ASAN使用指南
工具二:方舟多线程检测
根本原理
js是单线程的,操作js对象只答应发生在创建该js线程上,否则将会有多线程安全标题(主线程创建的js对象只能在主线程上操作,worker创建的js对象只能在worker线程上操作)。napi接口会直接涉及到对象的操作,因此绝大部门(95%)的napi接口只答应在js线程上使用。多线程检测机制检测的是:当前线程和使用的vm/env中的js thread id是否一致,若不一致,则表明vm/env被跨线程使用,存在多线程安全标题。常见标题有:1. 非js线程使用napi接口,2. napi接口使用其他线程的env。
使用方法


DevEco勾选Multi Thread Check选项即可开启方舟多线程检测功能。
使用场景
如果crash日志的堆栈难以分析,出现概率也相对比较高,对于此类标题,应该思量开启多线程检测。 开启多线程检测之后,如果cpp_crash日志中fatal信息为Fatal: ecma_vm cannot run in multi-thread! thread:3096 currentThread:3550,则发生了多线程安全标题,意思是当前线程号为3550,而使用的js thread却是3096线程创建出来的,跨线程使用vm。
案例
打开后重新触发崩溃,如果是多线程标题,会显示fatal 信息,参考如下:
  1. Fatal: ecma_vm cannot run in multi-thread! thread:xxx currentThread:yyy
复制代码
该信息意思是当前线程号为17585,而使用的 js thread 却是17688 线程创建出来的,跨线程使用 vm。vm 就是 js thread 的 napi_env__* ,运行线程代码的环境,一个线程使用一个 vm。
崩溃日志焦点部门如下所示:
  1. Reason:Signal:SIGABRT(SI_TKILL)@0x01317b9f000044b1 from:17585: 20020127
  2. LastFatalMessage: [default] CheckThread:177 Fatal: ecma_vm cannot run in multi-thread! thread:17688 currentThread:17585
  3. Fault thread Info:
  4. Tid:17585, Name:xxxxx
  5. # 00 pc 00000000000f157c /system/lib/ld-musl-aarch64-asan.so.1(__restore_sigs+52)(38eb4ca904ae601d4b4dca502e948960)
  6. # 01 pc 00000000000f1800 /system/lib/ld-musl-aarch64-asan.so.1(raise+112) (38eb4ca904aeó01d4b4dca502e948960)
  7. # 02 pc 00000000000adc74 /system/lib/ld-musl-aarch64-asan.so.1(abort.+20) (38eb4ca904ae601d4b4dca502e948960)
  8. # 03 pc 0000000000844fdc /system/asan/libó4/platformsdk/libark_jsruntime.so(panda::ecmascript::EcmaVM::CheckThread() const+2712)(1df055932338c14060b864435aec88ab)
  9. # 04 pc 0000000000f3d930 /system/asan/libó4/platformsdk/libark_jsruntime.so(panda::0bjectRef:: New(panda::ecmascript::EcmaVM const*)+908)(1df055932338c14060b864435aec88
  10. # 05 pC 0000000000095048 /sYstem/asan/lib64/platformsdk/libace_napi.z.so(napi_create_object+80)(efc1b3d1378f56b4b800489fb30dcded)
  11. # 06 pc 00000000005d9770 /data/ storage/el1/bundle/libs/arm64/xxxxx.so (c0f1735eada49fadc5197745f5afOc0a52246270)
复制代码
多线程标题分析步调:
i. 检查 libace_napi.z.so 下面的第一个栈帧,上图为xxxxx.so,判断是否把 17688 线程的 napi_env 传给了 17585 线程;
ii. 如果 libace_napi.z.so 下面的栈帧没有明显的 napi_env 参数传递,必要检查是否以结构体成员变量的方式传递;
工具三:objdump
使用方法
objdump二进制是体系侧工具,开辟者必要具备HarmonyOS编译环境,项目代码在gitee上可获取,命令如下:
  1. repo init -u git@gitee.com:HarmonyOS/manifest.git -b master --no-repo-verify --no-clone-bundle --depth=1
  2. repo sync -c
  3. ./build/prebuilts_download.sh
复制代码
工具在工程目录下prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-objdump,命令如下:
  1. prebuilts/clang/ohos/linux-x86_64/llvm/bin/llvm-objdump -d libark_jsruntime.so > dump.txt
复制代码
使用场景
有些情况下,通过addr2line只能看出代码某一行有标题,无法确认具体是哪个变量异常,此时可以通过objdump反汇编并结合cppcrash寄存器内容,进一步确认具体崩溃原因。
案例
日志内容如下:
  1. Tid:6655, Name:GC_WorkerThread
  2. # 00 pc 00000000004492d4 /system/lib64/platformsdk/libark_jsruntime.so(panda::ecmascript::NonMovableMarker::MarkObject(unsigned int, panda::ecmascript::TaggedObject*)+124)(21cf5411626d5986a4ba6383e959b3cc)
  3. # 01 pc 000000000044b580 /system/lib64/platformsdk/libark_jsruntime.so(panda::ecmascript::NonMovableMarker::MarkValue(unsigned int, panda::ecmascript::ObjectSlot&, panda::ecmascript::Region*, bool)+72)(21cf5411626d5986a4ba6383e959b3cc)
  4. # 02 pc 000000000044b4e8 /system/lib64/platformsdk/libark_jsruntime.so(std::__h::__function::__func<panda::ecmascript::NonMovableMarker::ProcessMarkStack(unsigned int)::$_2, std::__h::allocator<panda::ecmascript::NonMovableMarker::ProcessMarkStack(unsigned int)::$_2>, void (panda::ecmascript::TaggedObject*, panda::ecmascript::ObjectSlot, panda::ecmascript::ObjectSlot, panda::ecmascript::VisitObjectArea)>::operator()(panda::ecmascript::TaggedObject*&&, panda::ecmascript::ObjectSlot&&, panda::ecmascript::ObjectSlot&&, panda::ecmascript::VisitObjectArea&&)+256)(21cf5411626d5986a4ba6383e959b3cc)
  5. # 03 pc 0000000000442ac0 /system/lib64/platformsdk/libark_jsruntime.so(void panda::ecmascript::ObjectXRay::VisitObjectBody<(panda::ecmascript::VisitType)1>(panda::ecmascript::TaggedObject*, panda::ecmascript::JSHClass*, std::__h::function<void (panda::ecmascript::TaggedObject*, panda::ecmascript::ObjectSlot, panda::ecmascript::ObjectSlot, panda::ecmascript::VisitObjectArea)> const&)+216)(21cf5411626d5986a4ba6383e959b3cc)
  6. # 04 pc 0000000000447ccc /system/lib64/platformsdk/libark_jsruntime.so(panda::ecmascript::NonMovableMarker::ProcessMarkStack(unsigned int)+248)(21cf5411626d5986a4ba6383e959b3cc)
  7. # 05 pc 0000000000438588 /system/lib64/platformsdk/libark_jsruntime.so(panda::ecmascript::Heap::ParallelGCTask::Run(unsigned int)+148)(21cf5411626d5986a4ba6383e959b3cc)
  8. # 06 pc 00000000004e31c8 /system/lib64/platformsdk/libark_jsruntime.so(panda::ecmascript::Runner::Run(unsigned int)+144)(21cf5411626d5986a4ba6383e959b3cc)
  9. # 07 pc 00000000004e3780 /system/lib64/platformsdk/libark_jsruntime.so(void* std::__h::__thread_proxy[abi:v15004]<std::__h::tuple<std::__h::unique_ptr<std::__h::__thread_struct, std::__h::default_delete<std::__h::__thread_struct>>, void (panda::ecmascript::Runner::*)(unsigned int), panda::ecmascript::Runner*, unsigned int>>(void*)+64)(21cf5411626d5986a4ba6383e959b3cc)
  10. # 08 pc 000000000014d894 /system/lib/ld-musl-aarch64.so.1
  11. # 09 pc 0000000000085d04 /system/lib/ld-musl-aarch64.so.1
复制代码
首先先用addr2line查察出错的行,如下:


能看出的信息是判断IsYongSpace的时候访问到了空指针挂了,可以或许大概猜测出来是Region是空指针。
继续使用objdump反汇编,搜索出错地址4492d4 , 对应的汇编指令如下。


查察x20寄存器,发现为0x000000000000000,x20从上面可以看出是基于x2做位运算(清除掉后18位,典型的Region::ObjectAddressToRange操作)。这样分析之后,就清晰了,x2为MarkObject函数的第二个参数object,x20为变量objectRegion,如下:
  1. Registers: x0:0000007f0fe31560 x1:0000000000000003 x2:0000000000000000 x3:0000005593100000
  2.         x4:0000000000000000 x5:0000000000000000 x6:0000000000000000 x7:0000005596374fa0
  3.         x8:0000000000000000 x9:0000000000000000 x10:0000000000000000 x11:0000007f9cb42bb8
  4.         x12:000000000000005e x13:000000000061f59e x14:00000005d73d60fb x15:0000000000000000
  5.         x16:0000007f9cc5f200 x17:0000007f9f201f68 x18:0000000000000000 x19:0000000000000000
  6.         x20:0000000000000000 x21:0000000000000000 x22:0000000000000000 x23:000000559313f860
  7.         x24:000000559313f868 x25:0000000000000003 x26:00000055a0e19960 x27:0000007f9cc57b38
  8.         x28:0000007f9f21a1c0 x29:00000055a0e19700 lr:0000007f9cb4b584 sp:00000055a0e19700 pc:0000007f9cb492d4
复制代码
上面ldrb w8, [x20]对应 packedData_.flags_.spaceFlag_ 是因为,packedData_是region的第一个域,flags_是packedData_的第一个域,spaceFlag_是flags_的第一个域,以是直接取objectRegion地址对应的第一个字节。
查察汇编代码必要认识常见的汇编指令,以及传参规则,比方对于c++非inline的成员函数r0一样平常保存的是this指针。别的,由于编译器优化,源码和汇编代码对应关系可能不是很直观,我们可以根据代码中的一些特征值(常量),较快地找到对应关系。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4