使用Python脚本对 ndk crash 进行快速提取定位

Android 开发过程中,一些对效率要求很高的模块我们通常使用 c/c++ 来编写。他们比 Java 通过虚拟机再到机器上效率快很多,所以时常我们的应用当中一般由 Java 层代码 和 c/c++ 代码组成。即使自己不编写 c/c++ 代码,但是项目中难免引入一些第三方库 .so 文件间接使用到,常常这些 so 如果出现问题出现在 logcat 的崩溃栈,有一些类似于地址值的 log 如下:


12-18 15:45:19.448 3725-3725/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
12-18 15:45:19.448 3725-3725/? A/DEBUG: Build fingerprint: 'Huawei/MT7-TL10/hwmt7:6.0/HuaweiMT7-TL10/C00B571:user/release-keys'
12-18 15:45:19.448 3725-3725/? A/DEBUG: Revision: '0'
12-18 15:45:19.449 3725-3725/? A/DEBUG: ABI: 'arm'
12-18 15:45:19.449 3725-3725/? A/DEBUG: pid: 20616, tid: 20997, name: Thread-1059  >>> cn.rongcloud.im:ipc <<<
12-18 15:45:19.449 3725-3725/? A/DEBUG: signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
12-18 15:45:19.483 3725-3725/? A/DEBUG: Abort message: 'art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: JNI GetObjectClass called with pending exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference'
12-18 15:45:19.483 3725-3725/? A/DEBUG:     r0 00000000  r1 00005205  r2 00000006  r3 9be0f978
12-18 15:45:19.483 3725-3725/? A/DEBUG:     r4 9be0f980  r5 9be0f930  r6 00000002  r7 0000010c
12-18 15:45:19.483 3725-3725/? A/DEBUG:     r8 b42b4388  r9 b42b4388  sl fffffb04  fp b4267048
12-18 15:45:19.484 3725-3725/? A/DEBUG:     ip 00000006  sp 9be0ec50  lr b6cd2e39  pc b6cd4dfc  cpsr 40070010
12-18 15:45:19.513 3725-3725/? A/DEBUG: backtrace:
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #00 pc 00043dfc  /system/lib/libc.so (tgkill+12)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #01 pc 00041e35  /system/lib/libc.so (pthread_kill+32)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #02 pc 0001bb53  /system/lib/libc.so (raise+10)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #03 pc 00018db1  /system/lib/libc.so (__libc_android_abort+34)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #04 pc 0001696c  /system/lib/libc.so (abort+4)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #05 pc 00331be1  /system/lib/libart.so (_ZN3art7Runtime5AbortEv+232)
12-18 15:45:19.513 3725-3725/? A/DEBUG:     #06 pc 000f4cdb  /system/lib/libart.so (_ZN3art10LogMessageD2Ev+2226)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #07 pc 0025a717  /system/lib/libart.so (_ZN3art9JavaVMExt8JniAbortEPKcS2_+1550)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #08 pc 0025aac5  /system/lib/libart.so (_ZN3art9JavaVMExt9JniAbortVEPKcS2_St9__va_list+64)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #09 pc 000fd921  /system/lib/libart.so (_ZN3art11ScopedCheck6AbortFEPKcz+32)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #10 pc 00102a35  /system/lib/libart.so (_ZN3art11ScopedCheck5CheckERNS_18ScopedObjectAccessEbPKcPNS_12JniValueTypeE.constprop.95+5072)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #11 pc 0010959f  /system/lib/libart.so (_ZN3art8CheckJNI14GetObjectClassEP7_JNIEnvP8_jobject+386)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #12 pc 000121fb  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #13 pc 0003c3e3  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #14 pc 00016e2b  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #15 pc 0002c259  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #16 pc 00035f1b  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #17 pc 000367f7  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #18 pc 00036339  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #19 pc 0003a599  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #20 pc 0003a66b  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #21 pc 0003845d  /data/app/cn.rongcloud.im-1/lib/arm/libRongIMLib.so
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #22 pc 00041737  /system/lib/libc.so (_ZL15__pthread_startPv+30)
12-18 15:45:19.514 3725-3725/? A/DEBUG:     #23 pc 00019433  /system/lib/libc.so (__start_thread+6)


看着这些日志 和 pc 0003845d 一些这个值,我第一眼是比较懵逼的。还好 Android ndk 给我们提供了根据 pc 0003845d 定位到具体错误的方法

阅读本文需要掌握的概念:

  • .so文件 : 动态链接库(shared object library)在 linux 里以.so结尾,c/c++ 在 Linux 下编译生成的文件,Android 下可以通过 ndk-build 将 .c .h .mk 文件编译成 .so 文件
  • .asm文件: 是以asm作为扩展名的文件,是汇编语言的源程序文件。它是文本格式的文件,可以用任何文本编辑器进行创建或编辑,Android 下可使用 ndk 命令将 .so 文件转换成 .asm 文件
  • ABI(Application Binary Interface): 应用程序二进制接口 描述了应用程序和操作系统之间,一个应用和它的库之间,或者应用的组成部分之间的低接口。通俗理解为设备的 CPU 内核架构,例如: arm、x86、x86_64、armabiv7 等等
  • 符号表: 符号表是内存地址与函数名、文件名、行号的映射表。配置符号表]能快速并准确地定位用户APP发生Crash的代码位置

环境要求:

  • Android-NDK 环境
  • Python 环境

建议配置环境变量

定位错误步骤:

1 产生 crash 获取崩溃日志保存成文件待用
2 检查崩溃手机的 CPU 型号: 可通过 adb shell cat /proc/cpuinfo 查询,例子输出如下:


adb shell cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 5 (v7l)
processor       : 0
BogoMIPS        : 38.40

processor       : 1
BogoMIPS        : 38.40

processor       : 2
BogoMIPS        : 38.40

processor       : 3
BogoMIPS        : 38.40

processor       : 4
BogoMIPS        : 38.40

processor       : 5
BogoMIPS        : 38.40

processor       : 6
BogoMIPS        : 38.40

processor       : 7
BogoMIPS        : 38.40

Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 evtstrm
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0 & 0x3
CPU part        : 0xc07 & 0xc0f
CPU revision    : 5 & 3

Hardware        : Hisilicon Kirin 925
Revision        : 0000
Serial      : 0000000000000000

3 准备带符号表的 so 文件,例如崩溃手机是 arm 型号的,那就需要准备带符号表的 arm 型的 so 文件。
Android Sutdio+NDK,默认情况下,Debug编译的Debug SO文件将位于: <项目文件夹>//build/intermediates/ndk/debug/obj/local<架构>/

而Release编译的Debug SO文件将位于: <项目文件夹>//build/intermediates/ndk/release/obj/local<架构>/

如果工程中有 jni 文件夹又 ndk-build 生成的 so 文件可在输出文件夹 obj/<架构> 去找带符号表的 so 文件

4 使用 ndk objdump 工具将带符号表 .so 文件编译成汇编 .asm 文件:

例:

./arm-linux-androideabi-objdump -S /Users/zhouxuming/Documents/ReviewRongCloudSrc/android-workspace/lib/src/main/obj/local/armeabi/libRongIMLib.so > /Users/zhouxuming/Documents/ReviewRongCloudSrc/android-workspace/lib/src/main/obj/local/armeabi/libRongIMLib.asm

./arm-linux-androideabi-objdump -S xxx.so > xxx.asm

注意 ndk objdump 工具需要使用对应的 CPU ABI objdump 去编译

5 执行 parse_stack.py 脚本将对应映射定位的地址输出:

例:


python parse_stack.py /Users/zhouxuming/Documents/ReviewRongCloudSrc/android-workspace/lib/src/main/obj/local/armeabi/libRongIMLib.asm /Users/zhouxuming/Desktop/crashlog.txt


python parse_stack.py file.asm crashlog.txt

类似输出产物如下:


0x0001493b:_ZN19LogInfoListenerWrap9OnLogInfoESsb + 0x002f
0x00044797:      _ZN9RongCloud5RcLog1dEPKcz + 0x0087
0x0001a3df:_ZN9RongCloud12RCloudClient13NotifyMessageERNS_12CMessageInfoEibbi + 0x0037
0x00032ebd:_ZN9RongCloud19CSyncMessageCommand6DecodeEv + 0x0265
0x0003d6a9:_ZN9RongCloud8CCommand5ErrorENS_10error_typeEPKc + 0x0075
0x0003fa3b:_ZN9RongCloud17CRmtpSendWaitting5ErrorENS_10error_typeEPKc + 0x000f
0x0003e131:_ZN9RongCloud9CRcSocket18ProcessRmtpPackageEPNS_9_RmtpDataE + 0x0521
0x0003db69:_ZN9RongCloud9CRcSocket9OnRawDataEPKcj + 0x0095
0x000431b3:_ZN9RongCloud9TcpSocket6OnReadEv + 0x00e3
0x00042569:_ZN9RongCloud13SocketHandler21ISocketHandler_SelectEP7timeval + 0x00c1
0x00042657:_ZN9RongCloud13SocketHandler6SelectEll + 0x0037
0x0004007d:    _ZN9RongCloud10RmtpThreadEPv + 0x0115

如果对输出结果定位到的位置感觉不一致,需要验证可以通过 ndk addr2line 命令提取一个地址值进行输出对比:


./arm-linux-androideabi-addr2line -C -f -e xxx.so 0003deb4

调试过程中需要注意的事项

  • 提供的 .so 文件一定是带符号表的,不然没有映射能够正确定位
  • 使用 ndk addr2line 和 objdump 工具中记得选准确对应的 CPU 架构
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值