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 0x10x0 0000000000000000 x1 0000007fad6570a8 x2 0000007ff70fd720 x3 0000000000000000x4 0000000000000000 x5 0000007fac890540 x6 000000000000003f x7 0000000000000000x8 000000556bff3000 x9 0000000000000004 x10 0000000000000000 x11 0000007fad4ac6b8x12 0000007fad4b1278 x13 0000007fad5d84f0 x14 00000000ffffffff x15 0000007fad5d84f0x16 000000556bff2da8 x17 0000007fad548068 x18 0000000000000059 x19 0000000000000000x20 000000556c00f000 x21 000000556bff2000 x22 0000000000000000 x23 000000556c00f000x24 0000007ff70fd810 x25 000000556c00f6a0 x26 000000556bfd1800 x27 00000000ffffffffx28 0000000000000000 x29 0000007ff70fd6b0 x30 000000556bfc3e84sp 0000007ff70fd6b0 pc 0000007fad548078 pstate 0000000060000000v0 36373234323734315b203a47534d5746 v1 454f4320202d2058454f4345544c205dv2 5352455649445f544e415f53574d5f58 v3 30317830203436363678302020595449v4 00000000000000000000000000000000 v5 00000000000000000000000000000000v6 00000000000000000000000000000000 v7 30337830203038317830203130313031v8 00000000000000000000000000000000 v9 00000000000000000000000000000000v10 00000000000000000000000000000000 v11 00000000000000000000000000000000v12 00000000000000000000000000000000 v13 00000000000000000000000000000000v14 00000000000000000000000000000000 v15 00000000000000000000000000000000v16 40100401401004014010040140100401 v17 000000000000000000000000aa80aa00v18 00000000000000000000000000000000 v19 00000000000000000000000000000000v20 00000000000000000000000000000000 v21 00000000000000000000000000000000v22 00000000000000000000000000000000 v23 00000000000000000000000000000000v24 00000000000000000000000000000000 v25 00000000000000000000000000000000v26 00000000000000000000000000000000 v27 00000000000000000000000000000000v28 00000000000000000000000000000000 v29 00000000000000000000000000000000v30 00000000000000000000000000000000 v31 00000000000000000000000000000000fpsr 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 f70b6dc8r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010cr8 ffffffed r9 00000000 sl 00000000 fp ff96ae1cip 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 cefaf4a3c 5f6c6c61 74617473 64253a65 00000000 all_state:%d....efaf4a4c 69766564 6d5f6563 00657475 65726964 device_mute.direefaf4a5c 6f697463 0000006e 203a7325 65726964 ction...%s: direefaf4a6c 6f697463 656b206e 6f6e2079 6f662074 ction key not foefaf4a7c 00646e75 203a7325 6c696146 74206465 und.%s: Failed tefaf4a8c 6573206f 756d2074 65206574 253a7272 o set mute err:%efaf4a9c 00000064 6c6c6163 7079745f 00000065 d...call_type...efaf4aac 203a7325 6c6c6163 70797420 73692065 %s: call type isefaf4abc 00732520 004d5347 69647561 6f6d5f6f %s.GSM.audio_moefaf4acc 00006564 5f6c6c61 6c6c6163 6174735f de..all_call_staefaf4adc 00736574 253a6425 00002c64 706d6f63 tes.%d:%d,..compefaf4aec 73736572 696f765f 00000070 203a7325 ress_voip...%s: efaf4afc 65746e65 66202c72 616d726f 64253d74 enter, format=%defaf4b0c 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 stdinThe 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 endianVersion: 1 (current)OS/ABI: UNIX - System VABI Version: 0Type: **DYN (Shared object file)**Machine: **ARM**Version: 0x1Entry point address: 0x0Start of program headers: 52 (bytes into file)Start of section headers: 1121040 (bytes into file)Flags: 0x5000000, Version5 EABISize of this header: 52 (bytes)Size of program headers: 32 (bytes)Number of program headers: 9Size of section headers: 40 (bytes)Number of section headers: 39Section 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 -husage: stack [options] [FILE]--arch=arm|arm64|mips|mips64|x86|x86_64 the target architecture--symbols-dir=paththe path to a symbols dir, such as =/tmp/out/target/product/dream/symbols
FILE should contain a stack trace in it somewherethe tool will find that and re-print it withsource files and line numbers. If you don'tpass FILE, or if file is -, it reads fromstdin.
案例
$./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:LINE00004cd0 hashmapGet+4 ~/system/core/libcutils/hashmap.c:22200005e69 str_parms_get_str+8 ~/system/core/libcutils/str_parms.c:27400027e64 voice_extn_set_parameters+484 ~/hardware/qcom/audio/hal/voice_extn/voice_extn.c:48100013b5c voice_set_parameters+56 ~/hardware/qcom/audio/hal/voice.c:5640000e3d8 adev_set_parameters+220 ~/hardware/qcom/audio/hal/audio_hw.c:41490002bab9 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:1078000199c9 android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+60 ~/frameworks/native/libs/binder/Binder.cpp:1080001ed5b 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 symbol table-r, --reloc Display the relocation entries in the file-R, --dynamic-reloc Display the dynamic relocation entries in the file@<file> Read options from <file>-v, --version Display this program's version number-i, --info List object formats and architectures supported-H, --help Display this information
使用方法
Usage: objdump -S $(objfile) > $(output_file)例如,反汇编动态链接库文件并存入一个文件:
objdump -S -D libc.so > deassmble_libc.txt
通过汇编代码定位错误的原因,一些复杂的问题可以通过这种方式得到解决。
案例
$ aarch64-linux-android-objdump -D ~/symbols/system/lib/libcutils.so > libcutils.so.txt
也可以只显示一部分:
$ aarch64-linux-android-objdump -d -l --start-address=0x4ca0 --stop-address=0x4ce0 ~/symbols/system/lib/libcutils.so | aarch64-linux-android-c++filt
【提示】NDK中的objdump的位置
android-ndk-rxx/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump
android-ndk-rxx/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objdump
【提示】ARM汇编基本指令
ldr 从指定地址加载寄存器运算数
str 将寄存器运算数存到指定地址
add 两个寄存器相加
adds 寄存器和数值相加
mov 寄存器之间赋值
movs 将数值赋给寄存器
cmp 比较两个寄存器
bx lr 表示一个函数执行结束,跳转到lr中存放的地址处。
lr就是连接寄存器(Link Register, LR),在ARM体系结构中LR的特殊用途有两种:一是用来保存子程序返回地址;二是当异常发生时,LR中保存的值等于异常发生时PC的值减4(或者减2),因此在各种异常模式下可以根据LR的值返回到异常发生前的相应位置继续执行。
当通过BL或BLX指令调用子程序时,硬件自动将子程序返回地址保存在R14寄存器中。在子程序返回时,把LR的值复制到程序计数器PC即可实现子程序返回。如,可以使用MOV PC, LR或者BX LR来完成子程序返回。另外,也可以在在子程序入口处使用下面的指令将LR保存到栈中
欢迎关注我的公众号灰度五十,分享各类音视频、移动开发知识~
文章帮到你了?可以扫描如下二维码进行打赏,打赏多少您随意~
Android native crash解析相关推荐
- Android Native crash 处理案例分享
简介:Android Native crash 处理案例分享 1. 背景 目前 mPaas[1] Android使用Crash SDK对闪退进行的处理,CrashSDK 是 Android 平台上一款 ...
- 基于友盟+U-APM解决客户小姐姐Android Native Crash问题,小姐姐说我真棒,要把她闺蜜介绍给我
文章目录 一.遇到问题 二.Native日志分析 三.信号量(signal) 和 错误码(code)分析 四.PC指针addr2line定位 4.1 addr2line路径 4.2 so路径 4.3 ...
- Android Native Crash崩溃及错误原因分析二-实战解决
一. 简述 之前有一篇文章讲诉了Android实际开发过程中一些崩溃的原因,以及对崩溃类型做了详细的介绍,简单回顾一下:Crash类型:Java和Native,JavaCrash中明显会打印出Andr ...
- android native crash的处理机制
拦截所有信号 Linux信号机制 1.程序奔溃在Unix-like系统中,所有的崩溃都是编程错误或者硬件错误相关的,系统遇到不可恢复的错误时会触发崩溃机制让程序退出,如除零.段地址错误等.异常发生时, ...
- 当Android发生Native Crash时,Coredump能为我们带来什么信息?
更多内核安全.eBPF分析和实践文章,请关注博客和公众号: CSDN博客:内核功守道 公众号: 内核功守道 1.概述 1.1 Coredump形成原因 1.2 Coredump的作用 2.使能Cor ...
- [Python] Native Crash Addr2line 自动解析Tombstone文件脚本
[Python] Native Crash Addr2line 自动解析Tombstone文件脚本 文末附上脚本源码 2019.4.24 更新,32位,64位 进程tombstone的兼容 使用方法 ...
- java jni 数据类型_【Android JNI】Native层解析Java复杂数据类型HashMap
前提 Java HashMap 是基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.HashMap是存放引用类型数据的容器,只能存放引用数据类型,不能存 ...
- android 中断处理流程,Android P的native crash处理流程
一.概述 Android系统有监控程序异常退出的机制,这便是本文要讲述得debuggerd守护进程.当发生native crash或者主动调用debuggerd时,会输出进程相关的状态信息到文件或者控 ...
- android crash分析工具,Android Crash之Native Crash分析
前言 上一篇给大家介绍了Android Crash中的Java Crash分析,我们可以知道Java Crash一般会弹出提示框告诉我们程序崩溃了,通常使用Crash工具都能够捕获到:本篇博客来谈谈如 ...
最新文章
- Linux简单的颜色设置
- python-函数式编程
- 评定星级的前端显示js
- 事实表和维度表是怎么造数据_从电商数据指标到电商数据中台
- Linkedln技术高管Jay Kreps:Lambda架构剖析
- Python笔记-uiautomator2环境搭建(安卓模拟器测试环境+windows开发环境)
- mysql 数据库锁一般处理
- jQuery实现一个淡入淡出下拉菜单 非常简易
- TrustedInstaller.exe in Windows Vista consumes 100% CPU
- x86保护模式 任务状态段和控制门
- 15. JavaScript Array(数组)对象
- SpringBoot2.0.0启动流程
- SQL基础教程读书笔记
- 电脑、手机常用分辨率
- 2019产品数据管理(PDM)技术说明
- 关于travis scott的网名_小仙女可爱单纯的网名
- pycharm创建的.py文件显示为.txt文件样式
- dapr源码分析--injector
- 有关“夜壶冲”的由来
- 积米浏览器下载|积米浏览器免费下载
热门文章
- 制作JavaSript小轮播
- AI芯片市场需要一把火还是一桶冰?
- 深度学习FPGA实现基础知识2(深度揭秘百度大脑AI专有芯片 缘何用FPGA而非GPU?)
- 交流伺服驱动的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- 2021年安全员-B证报名考试及安全员-B证考试总结
- 攻克 Linux 系统编程
- Android 的 fdsan 文件描述符相关介绍
- 【饭谈】面试官让你来个“自我介绍”,你准备怎么说?
- 队列做题:1333:Blah数集(单调队列);1334:围圈报数
- 接口自动化获取excel中数据(一)