Android native crash解析
Posted zhanghui_cuc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android native crash解析相关的知识,希望对你有一定的参考价值。
当某个进程发生crash时会出现下面的错误日志,它可能出现在logcat日志或者/data/tombstones目录下的tombstone文件中
--------- beginning of crash
10-24 00:29:11.558 8660 8934 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x1c in tid 8934 (MainThread)
10-24 00:29:11.620 468 468 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-24 00:29:11.620 468 468 F DEBUG : Build fingerprint: 'xxxx'
10-24 00:29:11.620 468 468 F DEBUG : Revision: '0'
10-24 00:29:11.620 468 468 F DEBUG : ABI: 'arm'
10-24 00:29:11.621 468 468 F DEBUG : pid: 8660, tid: 8934, name: MainThread >>> com.rockstargames.gtasa <<<
10-24 00:29:11.621 468 468 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x1c
10-24 00:29:11.712 468 468 F DEBUG : r0 00000000 r1 00000000 r2 00000000 r3 0000001c
10-24 00:29:11.712 468 468 F DEBUG : r4 00000000 r5 d8af0800 r6 0000000c r7 d54ff474
10-24 00:29:11.712 468 468 F DEBUG : r8 ce6bf809 r9 00000000 sl 00000084 fp 0000547d
10-24 00:29:11.712 468 468 F DEBUG : ip c8dfdadc sp d54ff474 lr ce6bf81b pc ce525a94 cpsr 800f0030
10-24 00:29:11.714 468 468 F DEBUG :
10-24 00:29:11.714 468 468 F DEBUG : backtrace:
10-24 00:29:11.714 468 468 F DEBUG : #00 pc 0019da94 /data/app/com.rockstargames.gtasa-1/lib/arm/libGTASA.so (_Z25RpMatFXMaterialGetEffectsPK10RpMaterial+11)
10-24 00:29:11.714 468 468 F DEBUG : #01 pc 00053817 /data/app/com.rockstargames.gtasa-1/lib/arm/libGTASA.so (offset 0x2e4000)
10-24 00:29:13.677 468 468 F DEBUG :
10-24 00:29:13.677 468 468 F DEBUG : Tombstone written to: /data/tombstones/tombstone_00
64位的错误日志稍有不同:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'xxxx'
Revision: '0'
ABI: 'arm64'
pid: 29357, tid: 29357, name: cnss_diag >>> /system/bin/cnss_diag <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
x0 0000000000000000 x1 0000007fad6570a8 x2 0000007ff70fd720 x3 0000000000000000
x4 0000000000000000 x5 0000007fac890540 x6 000000000000003f x7 0000000000000000
x8 000000556bff3000 x9 0000000000000004 x10 0000000000000000 x11 0000007fad4ac6b8
x12 0000007fad4b1278 x13 0000007fad5d84f0 x14 00000000ffffffff x15 0000007fad5d84f0
x16 000000556bff2da8 x17 0000007fad548068 x18 0000000000000059 x19 0000000000000000
x20 000000556c00f000 x21 000000556bff2000 x22 0000000000000000 x23 000000556c00f000
x24 0000007ff70fd810 x25 000000556c00f6a0 x26 000000556bfd1800 x27 00000000ffffffff
x28 0000000000000000 x29 0000007ff70fd6b0 x30 000000556bfc3e84
sp 0000007ff70fd6b0 pc 0000007fad548078 pstate 0000000060000000
v0 36373234323734315b203a47534d5746 v1 454f4320202d2058454f4345544c205d
v2 5352455649445f544e415f53574d5f58 v3 30317830203436363678302020595449
v4 00000000000000000000000000000000 v5 00000000000000000000000000000000
v6 00000000000000000000000000000000 v7 30337830203038317830203130313031
v8 00000000000000000000000000000000 v9 00000000000000000000000000000000
v10 00000000000000000000000000000000 v11 00000000000000000000000000000000
v12 00000000000000000000000000000000 v13 00000000000000000000000000000000
v14 00000000000000000000000000000000 v15 00000000000000000000000000000000
v16 40100401401004014010040140100401 v17 000000000000000000000000aa80aa00
v18 00000000000000000000000000000000 v19 00000000000000000000000000000000
v20 00000000000000000000000000000000 v21 00000000000000000000000000000000
v22 00000000000000000000000000000000 v23 00000000000000000000000000000000
v24 00000000000000000000000000000000 v25 00000000000000000000000000000000
v26 00000000000000000000000000000000 v27 00000000000000000000000000000000
v28 00000000000000000000000000000000 v29 00000000000000000000000000000000
v30 00000000000000000000000000000000 v31 00000000000000000000000000000000
fpsr 00000000 fpcr 00000000
backtrace:
#00 pc 0000000000055078 /system/lib64/libc.so (fclose+16)
#01 pc 000000000000be80 /system/bin/cnss_diag
#02 pc 000000000000a508 /system/bin/cnss_diag (main+856)
#03 pc 000000000001bf50 /system/lib64/libc.so (__libc_init+100)
#04 pc 000000000000a654 /system/bin/cnss_diag
有时候,crash日志只出现在kernel日志中(当CONFIG_DEBUG_USE使能时),而没有出现在logcat日志或tombstone文件中。
<7>[29216.377747] PowerManagerSer: unhandled page fault (11) at 0x00001eef, code 0x017
<1>[29216.377747] pgd = d7748000
<1>[29216.377777] [00001eef] *pgd=9ea1e831, *pte=00000000, *ppte=00000000
<4>[29216.377777]
<4>[29216.377808] Pid: 591, comm: PowerManagerSer
<4>[29216.377808] CPU: 0 Tainted: G W (3.0.8-00016-g9392d0c #2)
<4>[29216.377838] PC is at 0x406698c0 <4>[29216.377838] LR is at 0x406cf724
<4>[29216.377838] pc : [<406698c0>] lr : [<406cf724>] psr: 20000010
当一个程序发生crash时,debuggerd会创建dump信息。此时,kernel会向即将死亡的程序发送一个信号。这个信号被(所有android native app都安装的一个特别的)signal handler捕获。通过bionic C库,这个signal handler通知debuggerd。Debuggerd通知即将死亡的进程使用ptrace读取寄存器和内存,生成tombstone和日志。
debuggerd
在Android系统中crash处理的应用程序叫debuggerd,它将部分堆栈信息写入日志中并把全部堆栈信息写入tombstone文件。具体地实现详system/core/debuggerd/debuggerd.cpp。
当一个动态链接程序启动,一些连接debuggerd(或debugger64)的signal handler被注册,用于处理进程收到signal的事件。Deuggerd披露堆栈信息和寄存器信息。
举例:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'xxx'
Revision: '0'
ABI: 'arm'
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8
r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c
r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c
ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010
backtrace:
#00 pc 00042c98 /system/lib/libc.so (tgkill+12)
#01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32)
#02 pc 0001bb87 /system/lib/libc.so (raise+10)
#03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34)
#04 pc 000168e8 /system/lib/libc.so (abort+4)
#05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16)
#06 pc 00018d35 /system/lib/libc.so (__assert2+20)
#07 pc 00000f21 /system/xbin/crasher
#08 pc 00016795 /system/lib/libc.so (__libc_init+44)
#09 pc 00000abc /system/xbin/crasher
Tombstone written to: /data/tombstones/tombstone_06
把这段日志输入到development/scripts/stack中能展开代码所在行的详细信息(如果能找到未清除符号的二进制库)。如果在编译的时候一些库指定 LOCAL_STRIP_MODULE := keep_symbols 标志,debuggerd能够直接提供有用的backtrace。
【提示】共享库的符号(Library symbols)
使用addr2line、objdump、stack等工具解析地址定位问题时,需要没有清除符号的共享库。这些共享库通常存放在out/target/product/<product_name>/symbols/(system/lib)目录。
清除符号的共享库也包含少量的符号,但是对于分析native crash问题一般是不够的。清除符号的共享库存放在设备的/system/lib/目录或源代码的out/target/product/<product_name>/(system/lib)目录。
Crash dumps
如果当前你没有一个正在研究的crash例子,Android系统源代码中提供了一个用于测试debuggerd的工具,叫做crasher。在 system/core/debuggerd/ 目录下执行 mm 命令会编译得到 crasher 和 crasher64 两个工具(crasher64 用于测试64-bit的crash)。crasher通过不同的命令行参数能够触发各种各样的crash。
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
这行的星号和空格用于在日志中搜索natvie crash日志。一般地,natvie crash日志是以字符串"*** ***"起始。
Build fingerprint:'xxxx'
Fingerprint 信息用于辨别发生crash的编译版本。它与system property ro.build.fingerprint 一致。
Revision: '0'
Revision信息与硬件相关,通常不用。
ABI: 'arm'
ABI值是arm(32位), arm64(64位), mips, mips64,x86或者x86-64。这对前面提到的 stack 脚本非常有用,知道工具链信息。
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
这行表明进程中导致crash的具体线程。在本例中,它是进程的主线程,因此进程ID和线程ID相同。第一个name是线程的名字,符号>>> 和 <<<包围的name是进程的名字。在查找crash发生之前有关的日志时,pid和tid信息也是有用的。
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
这行显示收到的信号(SIGABRT)还有是怎样收到的(SI_TKILL),它是进程退出的原因。由debuggerd 报告的信号有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGSEGV和SIGTRAP。
【提示】Linux信号机制
信号机制是 Linux 进程间通信的一种重要方式,Linux 信号一方面用于正常的进程间通信和同步,如任务控制(SIGINT, SIGTSTP,SIGKILL, SIGCONT,……);另一方面,它还负责监控系统异常及中断。 当应用程序运行异常时, Linux 内核将产生错误信号并通知当前进程。 当前进程在接收到该错误信号后,可以有三种不同的处理方式: 忽略该信号、捕捉该信号并执行对应的信号处理函数(signal handler)、执行该信号的缺省操作(如 SIGSEGV, 其缺省操作是终止进程)。
当 Linux 应用程序在执行时发生严重错误,一般会导致程序 crash。其中,Linux 专门提供了一类 crash 信号,在程序接收到此类信号时,缺省操作是将 crash 的现场信息记录到 core 文件,然后终止进程。
Crash 信号列表:
Signal Description
SIGSEGV:Invalid memory reference.
SIGBUS:Access to an undefined portion of a memory object.
SIGFPE:Arithmetic operation error, like divide by zero.
SIGILL:Illegal instruction, like execute garbage or a privileged instruction
SIGSYS:Bad system call.
SIGXCPU:CPU time limit exceeded.
SIGXFSZ:File size limit exceeded.
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
不是所有的crash日志都有abort message这一行。它是logcat日志中此pid/tid的fatal消息的最后一行日志。一般它会解释程序为什么退出,例如:
Abort message: 'Invalid address 0xc420b06c passed to free: value not allocated'。
r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8
r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c
r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c
ip 00000006 sp ff96ad18 lr f700ced5 pc **f700dc98** cpsr 400b0010
d0 ffffffffffffffff d1 76203a6565726620
d2 746f6e2065756c61 d3 7461636f6c6c6120
...
d30 3ff55d890c229271 d31 bf788480fcb07257
寄存器显示的是在收到signal的时刻CPU寄存器中的信息,它们是否有用取决于当前的crash。通常需要关注r0到pc寄存器,pc(program counter)和lr(link register)寄存器最有用。d0-d31寄存器通常是数据存取时使用。
backtrace:
#00 pc **00042c98** /system/lib/libc.so (tgkill+12)
#01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32)
#02 pc 0001bb87 /system/lib/libc.so (raise+10)
#03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34)
#04 pc 000168e8 /system/lib/libc.so (abort+4)
#05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16)
#06 pc 00018d35 /system/lib/libc.so (__assert2+20)
#07 pc 00000f21 /system/xbin/crasher
#08 pc 00016795 /system/lib/libc.so (__libc_init+44)
#09 pc 00000abc /system/xbin/crasher
这里backtrace描述了crash发生时刻代码的位置。第一列是frame号(gdb样式)。PC(program counter)数值是基于shared library的相对地址。第四列是内存映射区的名字(通常是一个shared library或者可执行程序)。如果符号表存在的话,PC数值对应的符号和位移显示在最后一列。再配合 objdump能找到对应的汇编指令。
注意:PC寄存器的值f700dc98与backtrace中pc 00042c98不同,是由于dumper程序自动的减去了基地址。
memory near r1:
efaf4a2c 2064696c 64697376 2078253a 6320726f lid vsid:%x or c
efaf4a3c 5f6c6c61 74617473 64253a65 00000000 all_state:%d....
efaf4a4c 69766564 6d5f6563 00657475 65726964 device_mute.dire
efaf4a5c 6f697463 0000006e 203a7325 65726964 ction...%s: dire
efaf4a6c 6f697463 656b206e 6f6e2079 6f662074 ction key not fo
efaf4a7c 00646e75 203a7325 6c696146 74206465 und.%s: Failed t
efaf4a8c 6573206f 756d2074 65206574 253a7272 o set mute err:%
efaf4a9c 00000064 6c6c6163 7079745f 00000065 d...call_type...
efaf4aac 203a7325 6c6c6163 70797420 73692065 %s: call type is
efaf4abc 00732520 004d5347 69647561 6f6d5f6f %s.GSM.audio_mo
efaf4acc 00006564 5f6c6c61 6c6c6163 6174735f de..all_call_sta
efaf4adc 00736574 253a6425 00002c64 706d6f63 tes.%d:%d,..comp
efaf4aec 73736572 696f765f 00000070 203a7325 ress_voip...%s:
efaf4afc 65746e65 66202c72 616d726f 64253d74 enter, format=%d
efaf4b0c 00000000 203a7325 69726544 20646576 ....%s: Derived
efaf4b1c 65646f6d 25203d20 00000064 70696f56 mode = %d...Voip
...
这部分显示程序发生crash时刻寄存器地址附近的内存信息。通常,检查内存信息能够进一步定位发生crash的原因。
Tombstones
Tombstone包含的信息有:
- 编译版本
- 发生crash的进程及PID
- 终止信号和错误地址
- CPU寄存器信息
- 调用堆栈
- 每个调用的堆栈内容
Tombstone包含和crash dump一样的信息,还有一些额外的信息。例如,它包含所有线程的backtrace信息(不只是发生crash的线程)、浮点寄存器、raw stack dumps和寄存器地址附近的内存信息。最有用的,它还包含一个全面的内存地址映射关系表(类似/proc/pid/maps)。
【提示】如何查看进程的内存地址映射
$ adb shell ps | grep mediaserver
media 779 1 419800 237360 binder_thr 00f6e0b058 S /system/bin/mediaserver
$ adb shell cat /proc/779/maps
aaef0000-aaef5000 r-xp 00000000 103:03 1009 /system/bin/mediaserver
aaef5000-aaef6000 r–p 00004000 103:03 1009 /system/bin/mediaserver
aaef6000-aaef7000 rw-p 00000000 00:00 0
dc300000-dc380000 rw-p 00000000 00:00 0 [anon:libc_malloc]
dc400000-dc480000 rw-p 00000000 00:00 0 [anon:libc_malloc]
dc680000-dc700000 rw-p 00000000 00:00 0 [anon:libc_malloc]
dd080000-dd480000 rw-s 00000000 00:01 52609 /dev/ashmem/AudioFlinger::Client (deleted)
dd480000-dd880000 rw-s 00000000 00:01 47141 /dev/ashmem/AudioFlinger::Client (deleted)
dd880000-dd900000 rw-p 00000000 00:00 0 [anon:libc_malloc]
dda00000-dda80000 rw-p 00000000 00:00 0 [anon:libc_malloc]
ddda9000-dde78000 r-xp 00000000 103:03 5640 /system/vendor/lib/libmmparser_lite.so
dde78000-dde7e000 r–p 000ce000 103:03 5640 /system/vendor/lib/libmmparser_lite.so
dde7e000-dde7f000 rw-p 000d4000 103:03 5640 /system/vendor/lib/libmmparser_lite.so
举例:
memory map: (fault address prefixed with --->)
--->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (BuildId:b9527db01b5cf8f5402f899f64b9b121)
有两个值得注意的地方。首先这一行以"—>"为前缀。对非空指针引起的crash内存映射关系非常有用。如果fault address的值很小,它可能是某个变量的空指针引起的。通过查看memory map可识别的一些可能存在的问题包括:读/写延伸到内存块末尾之外;在内存块开始之前读/写;尝试执行非代码内容;在堆栈末尾之外运行; 尝试写数据到代码段。第二个值得注意的地方是可执行程序和共享库文件显示BuildId信息,因此能准确地知道代码的哪个版本发生过crash。
ab163000-ab163fff r-- 3000 1000 /system/xbin/crasher
ab164000-ab164fff rw- 0 1000
f6c80000-f6d7ffff rw- 0 100000 [anon:libc_malloc]
在Android中堆不必是一块单独的区域。堆区域会以[anon:libc_malloc]标记。
分析工具及使用方法
addr2line
addr2line是用来获得指定动态链接库文件或者可执行文件中指定地址对应的源代码信息。通过backtrace提供的PC地址查询对应的符号,定位到文件、函数和行数。查看帮助:
$ addr2line -h
Usage: addr2line [option(s)] [addr(s)]
Convert addresses into line number/file name pairs.
If no addresses are specified on the command line, they will be read from stdin
The options are:
@<file> Read options from <file>
-a --addresses Show addresses
-b --target=<bfdname> Set the binary file format
-e --exe=<executable> Set the input file name (default is a.out)
-i --inlines Unwind inlined functions
-j --section=<name> Read section-relative offsets instead of addresses
-p --pretty-print Make the output easier to read for humans
-s --basenames Strip directory names
-f --functions Show function names
-C --demangle[=style] Demangle function names
-h --help Display this information
使用addr2line需要指定一个包含符号的共享库和(一个或多个)地址:
addr2line -aCpife <library> [addr(s)]
【提示】Mangle和Demangle
C++和Java语言支持函数重载功能,即传入不同参数的函数名可以重名。为了区分这些名称相同的函数,C++和Java把它们编码成底层汇编时为每个版本确定唯一标识。这个过程被称为mangle。相反,将底层名字转化为用户层可以阅读的名字叫demangle。
例如:
$ aarch64-linux-android-addr2line -aCpife audio.primary.so 0x13b50
0x00013b50: voice_set_parameters at /hardware/qcom/audio/hal/voice.c:562
【提示】NDK中的addr2line的位置
android-ndk-xx/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-addr2line
android-ndk-xx/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-addr2line
在Ubuntu系统中已集成addr2line,但是一般建议使用android源码或NDK中提供的版本。各个版本addr2line的区别在于支持的目标不同:
$ source build/envsetup.sh && lunch
$ arm-linux-androideabi-addr2line –h
arm-linux-androideabi-addr2line: supported targets: **elf32-littlearm** elf32-bigarm elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
$ aarch64-linux-android-addr2line -h
aarch64-linux-android-addr2line: supported targets: elf64-littleaarch64 elf64-bigaarch64 elf32-littleaarch64 elf32-bigaarch64 **elf32-littlearm** elf32-bigarm elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
$ addr2line -h
addr2line: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 a.out-i386-linux pei-i386 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-x86-64 pe-bigobj-x86-64 pe-i386 plugin srec symbolsrec verilog tekhex binary ihex
查看共享库的ELF信息,选择合适的addr2line版本。
$ aarch64-linux-android-readelf -h audio.primary.so
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: **ELF32**
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: **DYN (Shared object file)**
Machine: **ARM**
Version: 0x1
Entry point address: 0x0
Start of program headers: 52 (bytes into file)
Start of section headers: 1121040 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 9
Size of section headers: 40 (bytes)
Number of section headers: 39
Section header string table index: 38
ndk-stack
Andorid NDK中提供的一个工具,位置是android-ndk-path/ndk-stack。在logcat日志中可以使用ndk-stack过滤出现的stack trace,也用于将shared library中的任何地址转换成源代码中的<source-file>:<line-number>值,使问题精准定位。例如,它将下面的日志:
I/DEBUG ( 31): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 31): Build fingerprint: 'generic/google_sdk/generic/:2.2/FRF91/43546:eng/test-keys'
I/DEBUG ( 31): pid: 351, tid: 351 %gt;%gt;%gt; /data/local/ndk-tests/crasher <<<
I/DEBUG ( 31): signal 11 (SIGSEGV), fault addr 0d9f00d8
I/DEBUG ( 31): r0 0000af88 r1 0000a008 r2 baadf00d r3 0d9f00d8
I/DEBUG ( 31): r4 00000004 r5 0000a008 r6 0000af88 r7 00013c44
I/DEBUG ( 31): r8 00000000 r9 00000000 10 00000000 fp 00000000
I/DEBUG ( 31): ip 0000959c sp be956cc8 lr 00008403 pc 0000841e cpsr 60000030
I/DEBUG ( 31): #00 pc 0000841e /data/local/ndk-tests/crasher
I/DEBUG ( 31): #01 pc 000083fe /data/local/ndk-tests/crasher
I/DEBUG ( 31): #02 pc 000083f6 /data/local/ndk-tests/crasher
I/DEBUG ( 31): #03 pc 000191ac /system/lib/libc.so
I/DEBUG ( 31): #04 pc 000083ea /data/local/ndk-tests/crasher
I/DEBUG ( 31): #05 pc 00008458 /data/local/ndk-tests/crasher
I/DEBUG ( 31): #06 pc 0000d362 /system/lib/libc.so
I/DEBUG ( 31):
转化成易于阅读的输出(相当于按行多次执行addr2line):
********** Crash dump: **********
Build fingerprint: 'generic/google_sdk/generic/:2.2/FRF91/43546:eng/test-keys'
pid: 351, tid: 351 >>> /data/local/ndk-tests/crasher <<<
signal 11 (SIGSEGV), fault addr 0d9f00d8
Stack frame #00 pc 0000841e /data/local/ndk-tests/crasher : Routine zoo in /tmp/foo/crasher/jni/zoo.c:13
Stack frame #01 pc 000083fe /data/local/ndk-tests/crasher : Routine bar in /tmp/foo/crasher/jni/bar.c:5
Stack frame #02 pc 000083f6 /data/local/ndk-tests/crasher : Routine my_comparison in /tmp/foo/crasher/jni/foo.c:9
Stack frame #03 pc 000191ac /system/lib/libc.so
Stack frame #04 pc 000083ea /data/local/ndk-tests/crasher : Routine foo in /tmp/foo/crasher/jni/foo.c:14
Stack frame #05 pc 00008458 /data/local/ndk-tests/crasher : Routine main in /tmp/foo/crasher/jni/main.c:19
Stack frame #06 pc 0000d362 /system/lib/libc.so
使用ndk-stack需要指定一个包含符号的共享库目录。如果是使用NDK编译的(ndk-build),这些共享库存放$PROJECT_PATH/obj/local/<abi>下,其中<abi>代表设备的ABI。默认系统使用armeabi ABI。有两种用法,一种是logcat日志直接输入到ndk-stack:
adb logcat | $NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi
也可以使用-dump选项指定一个logcat日志作为输入,例如:
adb logcat > /tmp/foo.txt
$NDK/ndk-stack -sym $PROJECT_PATH/obj/local/armeabi -dump foo.txt
当它解析logcat日志时会以星号行作为解析起始行,例如:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
案例
$./ndk-stack –sym ~/symbols/system/lib -dump ~/foo.txt
********** Crash dump: **********
Build fingerprint: 'xxxx'
pid: 774, tid: 2212, name: Binder_3 >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8
Stack frame #00 pc 00004cd0 /system/lib/libcutils.so (hashmapGet+3): Routine hashmapGet at ~/system/core/libcutils/hashmap.c:222
Stack frame #01 pc 00005e69 /system/lib/libcutils.so (str_parms_get_str+8): Routine str_parms_get_str at ~/system/core/libcutils/str_parms.c:274
Stack frame #02 pc 00027e64 /system/lib/hw/audio.primary.so (voice_extn_set_parameters+484)
Stack frame #03 pc 00013b5c /system/lib/hw/audio.primary.so (voice_set_parameters+56)
Stack frame #04 pc 0000e3d8 /system/lib/hw/audio.primary.so
Stack frame #05 pc 0002bab9 /system/lib/libaudioflinger.so: Routine android::AudioFlinger::setParameters(int, android::String8 const&) at ~/frameworks/av/services/audioflinger/AudioFlinger.cpp:1102 (discriminator 1)
Stack frame #06 pc 00063893 /system/lib/libmedia.so (_ZN7android14BnAudioFlinger10onTransactEjRKNS_6ParcelEPS1_j+1438):
...
stack
与ndk-stack类似,stack是android源码中提供分析crash日志的工具,位置是<android-source-code>/development/scripts/stack。用于将shared library中的任何地址转换成源代码中的<source-file>:<line-number>值,使问题精准定位。
使用stack需要指定一个包含符号的共享库目录、crash日志和ABI。例如:
stack --arch=arm --symbols-dir=$(symbols_directory) $(crash_log_file)
$ stack -h
usage: stack [options] [FILE]
--arch=arm|arm64|mips|mips64|x86|x86_64 the target architecture
--symbols-dir=path
the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols
FILE should contain a stack trace in it somewhere
the tool will find that and re-print it with
source files and line numbers. If you don't
pass FILE, or if file is -, it reads from
stdin.
案例
$./development/scripts/stack --arch=arm --symbols-dir=~/symbols/ ~/workspace/foo.txt
Searching for native crashes in ~/workspace/foo.txt
Reading symbols from ~/symbols/
Revision: '0'
ABI: 'arm'
pid: 774, tid: 2212, name: Binder_3 >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8
r0 00000000 r1 efaf4a4c r2 de00095c r3 00000100
r4 00000100 r5 00000000 r6 de00095c r7 0001581c
r8 f6d57ec0 r9 e0fb63f0 sl efaf4a4c fp 00000000
ip f6ff1e30 sp de000918 lr f6fe6e6d pc f6fe5cd0 cpsr 600f0030
Using arm toolchain from: ~/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/
Stack Trace:
RELADDR FUNCTION FILE:LINE
00004cd0 hashmapGet+4 ~/system/core/libcutils/hashmap.c:222
00005e69 str_parms_get_str+8 ~/system/core/libcutils/str_parms.c:274
00027e64 voice_extn_set_parameters+484 ~/hardware/qcom/audio/hal/voice_extn/voice_extn.c:481
00013b5c voice_set_parameters+56 ~/hardware/qcom/audio/hal/voice.c:564
0000e3d8 adev_set_parameters+220 ~/hardware/qcom/audio/hal/audio_hw.c:4149
0002bab9 android::AudioFlinger::setParameters(int, android::String8 const&)+120 ~/frameworks/av/services/audioflinger/AudioFlinger.cpp:1102 (discriminator 1)
00063893 android::BnAudioFlinger::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+1438 ~/frameworks/av/media/libmedia/IAudioFlinger.cpp:1078
000199c9 android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+60 ~/frameworks/native/libs/binder/Binder.cpp:108
0001ed5b android::IPCThreadState::executeCommand(int)+550 ~/frameworks/native/libs/binder/IPCThreadState.cpp:1091
objdump
反汇编工具。
Usage: aarch64-linux-android-objdump <option(s)> <file(s)>
Display information from object <file(s)>.
At least one of the following switches must be given:
-a, --archive-headers Display archive header information
-f, --file-headers Display the contents of the overall file header
-p, --private-headers Display object format specific file header contents
-P, --private=OPT,OPT... Display object format specific contents
-h, --[section-]headers Display the contents of the section headers
-x, --all-headers Display the contents of all headers
-d, --disassemble Display assembler contents of executable sections
-D, --disassemble-all Display assembler contents of all sections
-S, --source Intermix source code with disassembly
-s, --full-contents Display the full contents of all sections requested
-g, --debugging Display debug information in object file
-e, --debugging-tags Display debug information using ctags style
-G, --stabs Display (in raw form) any STABS info in the file
-W[lLiaprmfFsoRt] or
--dwarf[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,
=frames-interp,=str,=loc,=Ranges,=pubtypes,
=gdb_index,=trace_info,=trace_abbrev,=trace_aranges,
=addr,=cu_index]
Display DWARF info in the file
-t, --syms Display the contents of the symbol table(s)
-T, --dynamic-syms Display the contents of the dynamic symbo以上是关于Android native crash解析的主要内容,如果未能解决你的问题,请参考以下文章