Android-NDK开发Crash错误定位

01-01 17:59:38.296: I/dalvikvm(20794): Enabling JNI app bug workarounds for target SDK version 3…
01-01 17:59:38.366: D/dalvikvm(20794): Trying to load lib /data/app-lib/com.example.hellojni-1/libhello-jni.so 0x422a4f58
01-01 17:59:38.366: D/dalvikvm(20794): Added shared lib /data/app-lib/com.example.hellojni-1/libhello-jni.so 0x422a4f58
01-01 17:59:38.366: A/libc(20794): Fatal signal 8 (SIGFPE) at 0x0000513a (code=-6), thread 20794 (xample.hellojni)
01-01 17:59:38.476: I/DEBUG(253): pid: 20794, tid: 20794, name: xample.hellojni >>> com.example.hellojni <<<
01-01 17:59:38.476: I/DEBUG(253): signal 8 (SIGFPE), code -6 (SI_TKILL), fault addr 0000513a
01-01 17:59:38.586: I/DEBUG(253): r0 00000000 r1 0000513a r2 00000008 r3 00000000
01-01 17:59:38.586: I/DEBUG(253): r4 00000008 r5 0000000d r6 0000513a r7 0000010c
01-01 17:59:38.586: I/DEBUG(253): r8 75226d08 r9 00000000 sl 417c5c38 fp bedbf134
01-01 17:59:38.586: I/DEBUG(253): ip 41705910 sp bedbf0f0 lr 4012e169 pc 4013d10c cpsr 000f0010
// 省略部份日志 。。。。。。
01-01 17:59:38.596: I/DEBUG(253): backtrace:
01-01 17:59:38.596: I/DEBUG(253): #00 pc 0002210c /system/lib/libc.so (tgkill+12) 01-01 17:59:38.596: I/DEBUG(253): #01 pc 00013165 /system/lib/libc.so (pthread_kill+48) 01-01 17:59:38.596: I/DEBUG(253): #02 pc 00013379 /system/lib/libc.so (raise+10) 01-01 17:59:38.596: I/DEBUG(253): #03 pc 00000e80 /data/app-lib/com.example.hellojni-1/libhello-jni.so (__aeabi_idiv0+8) 01-01 17:59:38.596: I/DEBUG(253): #04 pc 00000cf4 /data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32) 01-01 17:59:38.596: I/DEBUG(253): #05 pc 00000d1c /data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20) 01-01 17:59:38.596: I/DEBUG(253): #06 pc 00052eb1 /system/lib/libdvm.so (dvmLoadNativeCode(char const*, Object*, char**)+468) 01-01 17:59:38.596: I/DEBUG(253): #07 pc 0006a62d /system/lib/libdvm.so 01-01 17:59:38.596: I/DEBUG(253): // 省略部份日志 。。。。。。
01-01 17:59:38.596: I/DEBUG(253): stack:
01-01 17:59:38.596: I/DEBUG(253): bedbf0b0 71b17034 /system/lib/libsechook.so
01-01 17:59:38.596: I/DEBUG(253): bedbf0b4 7521ce28
01-01 17:59:38.596: I/DEBUG(253): bedbf0b8 71b17030 /system/lib/libsechook.so
01-01 17:59:38.596: I/DEBUG(253): bedbf0bc 4012c3cf /system/lib/libc.so (dlfree+50)
01-01 17:59:38.596: I/DEBUG(253): bedbf0c0 40165000 /system/lib/libc.so
01-01 17:59:38.596: I/DEBUG(253): // 省略部份日志 。。。。。。
01-01 17:59:38.736: W/ActivityManager(1185): Force finishing activity com.example.hellojni/.HelloJni

日志分析:

第3行开始启动应用,第5行尝试加载应用数据目录下的so,第6行在加载so文件的时候产生了一个致命的错误,第7行的Fatal signal 8提示这是一个致命的错误,这个信号是由linux内核发出来的,信号8的意思是浮点数运算异常,应该是在willCrash函数中做除0操作所产生的。下面重点看第15行backtrace的日志,backtrace日志可以看作是JNI调用的堆栈信息,以“#两位数字 pc”开头的都是backtrace日志。注意看第20行和21行,是我们自己编译的so文件和定义的两个函数,在这里引发了异常,导致程序崩溃。

01-01 17:59:38.596: I/DEBUG(253): #04 pc 00000cf4 /data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32)
01-01 17:59:38.596: I/DEBUG(253): #05 pc 00000d1c /data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20)

开始有些眉目了,但具体崩在这两个函数的哪个位置,我们是不确定的,如果函数代码比较少还好查,如果比较复杂的话,查起来也费劲。这时候就需要靠NDK为我们提供的工具来精确定位了。在这之前,我们先记录下让程序崩溃的汇编指令地址,willCrash:00000cf4,JNI_OnLoad:00000d1c

(ps:对于可执行程序及动态库,一般在LINKED子目录中是带有符号的库(没有经过符号剥离,如混淆等),如果可执行文件中没有包括调试符号,您将获得??:0 作为响应。

方式1:使用arm-linux-androideabi-addr2line 定位出错位置

以arm架构的CPU为例,执行如下命令:

/Users/yangxin/Documents/devToos/java/android-ndk-r9d/toolchains/arm-linux-androideabi-
4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line -e
/Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a/libhello-
jni.so 00000cf4 00000d1c

-e:指定so文件路径

0000cf4 0000d1c:出错的汇编指令地址

结果如下:

是不是惊喜的看到我们想要的结果了,分别在hello-jni.c的10和15行的出的错,再回去看看hello-jni.c的源码,15行的Jni_OnLoad函内调用了willCrash函数,第10行做了除0的操作引发的crash。

方式2:使用arm-linux-androideabi-objdump 定位出错的函数信息

在第一种方式中,通过addr2lin已经获取到了代码出错的位置,但是不知道函数的上下文信息,显得有点不是那么的“完美”,对于追求极致的我来说,这显然是不够的,下面我们来看一下怎么来定位函数的信息。 首先使用如下命令导出so的函数表信息:

[cpp] view plain copy
/Users/yangxin/Documents/devToos/java/android-ndk-r9d/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -S -D /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a/libhello-jni.so > Users/yangxin/Desktop/dump.log

在生成的asm文件中,找出我们开始定位到的那两个出错的汇编指令地址(在文件中搜索cf4或willCrash可以找到),如下图所示:

通过这种方式,也可以查出这两个出错的指针地址分别位于哪个函数中。

方式3:ndk-stack

如果你觉得上面的方法太麻烦的话,ndk-stack可以帮你减轻操作步聚,直接定位到代码出错的位置。

实时分析日志:

使用adb获取logcat的日志,并通过管道输出给ndk-stack分析,并指定包含符号表的so文件位置。如果程序包含多种CPU架构,需要根据手机的CPU类型,来选择不同的CPU架构目录。以armv7架构为例,执行如下命令:

adb logcat | ndk-stack -sym /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a

当程序发生crash时,会输出如下信息:

pid: 22654, tid: 22654, name: xample.hellojni >>> com.example.hellojni <<<
signal 8 (SIGFPE), code -6 (SI_TKILL), fault addr 0000587e
Stack frame #00 pc 0002210c /system/lib/libc.so (tgkill+12) Stack frame #01 pc 00013165
/system/lib/libc.so (pthread_kill+48) Stack frame #02 pc 00013379 /system/lib/libc.so (raise+10) Stack
frame #03 pc 00000e80 /data/app-lib/com.example.hellojni-1/libhello-jni.so (__aeabi_idiv0+8): Routine
__aeabi_idiv0 at /s/ndk-toolchain/src/build/…/gcc/gcc-4.6/libgcc/…/gcc/config/arm/lib1funcs.asm:1270 Stack
frame #04 pc 00000cf4 /data/app-lib/com.example.hellojni-1/libhello-jni.so (willCrash+32): Routine
willCrash at /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/jni/hello-jni.c:10
Stack frame #05 pc 00000d1c /data/app-lib/com.example.hellojni-1/libhello-jni.so (JNI_OnLoad+20):
Routine JNI_OnLoad at /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/jni/hello-
jni.c:15 Stack frame #06 pc 00052eb1 /system/lib/libdvm.so (dvmLoadNativeCode(char const*, Object*,
char**)+468) Stack frame #07 pc 0006a62d /system/lib/libdvm.so

第7行和第8行分别打印出了在源文件中出错的位置,和addr2line得到的结果一样。

先获取日志再分析:

这种方式和上面的方法差不多,只是获取log的来源不一样。适用于应用或游戏给测试部们测试的时候,测试人员发现crash,用adb logcat保存日志文件,然后发给程序员通过ndk-stack命令分析。操作流程如下:

adb logcat > crash.log
ndk-stack -sym /Users/yangxin/Documents/devToos/java/android-ndk-r9d/samples/hello-jni/obj/local/armeabi-v7a -dump crash.log

得到的结果和上面的方式是一样的。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!**

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值