在移植Android过程中会遇到很多Crash的情况,尤其是启动Android过程中。一般这些问题都可以通过看代码能解决,当然也有一些问题,非常难找到头绪,在logcat日志也只会打印一些崩溃的堆栈,这些信息很难帮助我们定位问题。根据个人一个实例来介绍一下在Android 移植过程中反汇编的用法。
首先先看一下我遇到的一个logcat关于Crash的打印信息:
I/DEBUG ( 1417): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG ( 1417): Build fingerprint: 'generic/sdk/generic/:Eclair/ECLAIR/eng.simon.20100607.133011:eng/test-keys' I/DEBUG ( 1417): pid: 1434, tid: 1460 >>> system_server <<< I/DEBUG ( 1417): signal 11 (SIGSEGV), fault addr 00000000 I/DEBUG ( 1417): zr 00000000 at 00000000 v0 00007265 v1 00193228 I/DEBUG ( 1417): gp 7ef6fd60 sp 30564e90 s8 2fa07858 ra 7ef53470 I/DEBUG ( 1417): hi 0000000f lo 04444444 bva 00007265 epc 7ef534a4 I/DEBUG ( 1417): #00 pc 7ef534a4 /system/lib/libc.so I/DEBUG ( 1417): #01 ra 7ef53470 /system/lib/libc.so I/DEBUG ( 1417): code around pc: I/DEBUG ( 1417): 7ef53494 afa7002c afa40030 1040000b afa50028 I/DEBUG ( 1417): 7ef534a4 8c4a0000 8c440008 8c590004 8fa2001c I/DEBUG ( 1417): 7ef534b4 0320f809 ac4a0034 8fa9001c 8d220034 I/DEBUG ( 1417): 30564e78 00000000 I/DEBUG ( 1417): 30564e7c 7ef12af4 /system/lib/libc.so I/DEBUG ( 1417): 30564e80 7ef6fd60 I/DEBUG ( 1417): 30564e84 00000000 I/DEBUG ( 1417): 30564ea4 7b10a8e8 /system/lib/libsqlite.so I/DEBUG ( 1417): 30564ea8 7b10a8b4 /system/lib/libsqlite.so I/DEBUG ( 1417): 30564ed0 7ef5d990 /system/lib/libc.so I/DEBUG ( 1417): 30564ed4 2fa0786c I/DEBUG ( 1417): 30564ed8 30465000 I/DEBUG ( 1417): 30564edc 00100000 [heap] I/DEBUG ( 1417): 30564ee0 7b10a8b4 /system/lib/libsqlite.so W/SyncManager( 1434): Updating for new accounts...
通过这个log信息我们可以看到libc.so崩溃了,再研究堆栈发现是libsqilte.so引起的,那么具体是哪一个函数崩溃了呢?这里面没有信 息。另外内核加载动态库是动态加载的,就算我们反汇编出来libc.so和libsqlite.so,符号表也没有办法和log中地址对应上,除非我们能 知道内核加载libc.so和libsqlite.so的基地址,这样我们就可以通过偏移找到相应的函数了。很幸运,Android确实规定了系统中的大 部分库的内核加载地址。文件的位置在build/core下,有对应平台的map文件,比如:Arm平台文件名叫做prelink-linux- arm.map,Mips平台叫做prelink-linux-mips.map。我是在Mips平台出的问题,所以应该用prelink-linux- mips.map文件来定位。文件内容如下:
# 0x7F100000 - 0x7FFF0000 Thread 0 stack # 0x7F000000 - 0x7F0FFFFF Linker # 0x70000000 - 0x7EFFFFFF Prelinked System Libraries # core system libraries libdl.so 0x7EFF0000 libc.so 0x7EF00000 libstdc++.so 0x7EEF0000 libcutils.so 0x7EE000000用readelf -s libc.so查看库中每一个函数地址
从这个map文件我们可以查询到每个lib库的加载基地址。比如libc.so将会被内核加载到0x7EF00000,libsqlite.so加载到 0x7B100000。我们可以对照一下Crash的log信息也对应的上,说明这个文件在Android加载过程中起了作用。
下一步我们需要反汇编libc.so和libsqlite.so。一般交叉编译器都提供了反汇编的工具,我的mips平台提供了mips-linux-gnu-objdump命令来进行反汇编。
mips-linux-gnu-objdump -dS libc.so > libc.dump mips-linux-gnu-objdump -dS libsqlite.so > libsqlite.dump
在Arm平台系统自带的反编译工具在android/prebuild/linux-86/toolchail/arm-abil-4.4.0/bin目录下的arm_eabi-objdump进行反汇编
arm-eabi-objdump -dS libc.so >/work/libc.dump arm-eabi-objdump -dS libsqlite.so >/worl/libsqlite.dump
在Arm平台还提供一个命令直接定位出问题的代码
arm-eabi-addr2line -e ./symbols/system/lib/libc.so 0x10000000//-e=>fileName</p 0x10000000是根据栈打印出来有问题的地址
会直接定位出问题文件的行数;
这样就可以得到libc和libsqlite的符号表。然后通过符号表,Android加载动态库的基地址,log信息就可以定位到那个函数出问题了,如 果你对对应平台汇编语言熟悉的话可以阅读汇编代码找出问题。本文就不具体讲怎样利用这个三个文件信息了。有了这个三个文件,稍一研究就可以明白怎样分析 了。
一般情况下,Crash都不是Android源码的问题,最有可能的是内核有些模块没有编译进去。本例中就是和Mutex相关的模块没有编译进内核引起的问题。