当某个进程发生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解析相关推荐

  1. Android Native crash 处理案例分享

    简介:Android Native crash 处理案例分享 1. 背景 目前 mPaas[1] Android使用Crash SDK对闪退进行的处理,CrashSDK 是 Android 平台上一款 ...

  2. 基于友盟+U-APM解决客户小姐姐Android Native Crash问题,小姐姐说我真棒,要把她闺蜜介绍给我

    文章目录 一.遇到问题 二.Native日志分析 三.信号量(signal) 和 错误码(code)分析 四.PC指针addr2line定位 4.1 addr2line路径 4.2 so路径 4.3 ...

  3. Android Native Crash崩溃及错误原因分析二-实战解决

    一. 简述 之前有一篇文章讲诉了Android实际开发过程中一些崩溃的原因,以及对崩溃类型做了详细的介绍,简单回顾一下:Crash类型:Java和Native,JavaCrash中明显会打印出Andr ...

  4. android native crash的处理机制

    拦截所有信号 Linux信号机制 1.程序奔溃在Unix-like系统中,所有的崩溃都是编程错误或者硬件错误相关的,系统遇到不可恢复的错误时会触发崩溃机制让程序退出,如除零.段地址错误等.异常发生时, ...

  5. 当Android发生Native Crash时,Coredump能为我们带来什么信息?

    ​更多内核安全.eBPF分析和实践文章,请关注博客和公众号: CSDN博客:内核功守道 公众号: 内核功守道 1.概述 1.1 Coredump形成原因 1.2 Coredump的作用 2.使能Cor ...

  6. [Python] Native Crash Addr2line 自动解析Tombstone文件脚本

    [Python] Native Crash Addr2line 自动解析Tombstone文件脚本 文末附上脚本源码 2019.4.24 更新,32位,64位 进程tombstone的兼容 使用方法 ...

  7. java jni 数据类型_【Android JNI】Native层解析Java复杂数据类型HashMap

    前提 Java HashMap 是基于哈希表的 Map 接口的实现.此实现提供所有可选的映射操作,并允许使用null值和null键.HashMap是存放引用类型数据的容器,只能存放引用数据类型,不能存 ...

  8. android 中断处理流程,Android P的native crash处理流程

    一.概述 Android系统有监控程序异常退出的机制,这便是本文要讲述得debuggerd守护进程.当发生native crash或者主动调用debuggerd时,会输出进程相关的状态信息到文件或者控 ...

  9. android crash分析工具,Android Crash之Native Crash分析

    前言 上一篇给大家介绍了Android Crash中的Java Crash分析,我们可以知道Java Crash一般会弹出提示框告诉我们程序崩溃了,通常使用Crash工具都能够捕获到:本篇博客来谈谈如 ...

最新文章

  1. Linux简单的颜色设置
  2. python-函数式编程
  3. 评定星级的前端显示js
  4. 事实表和维度表是怎么造数据_从电商数据指标到电商数据中台
  5. Linkedln技术高管Jay Kreps:Lambda架构剖析
  6. Python笔记-uiautomator2环境搭建(安卓模拟器测试环境+windows开发环境)
  7. mysql 数据库锁一般处理
  8. jQuery实现一个淡入淡出下拉菜单 非常简易
  9. TrustedInstaller.exe in Windows Vista consumes 100% CPU
  10. x86保护模式 任务状态段和控制门
  11. 15. JavaScript Array(数组)对象
  12. SpringBoot2.0.0启动流程
  13. SQL基础教程读书笔记
  14. 电脑、手机常用分辨率
  15. 2019产品数据管理(PDM)技术说明
  16. 关于travis scott的网名_小仙女可爱单纯的网名
  17. pycharm创建的.py文件显示为.txt文件样式
  18. dapr源码分析--injector
  19. 有关“夜壶冲”的由来
  20. 积米浏览器下载|积米浏览器免费下载

热门文章

  1. 制作JavaSript小轮播
  2. AI芯片市场需要一把火还是一桶冰?
  3. 深度学习FPGA实现基础知识2(深度揭秘百度大脑AI专有芯片 缘何用FPGA而非GPU?)
  4. 交流伺服驱动的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  5. 2021年安全员-B证报名考试及安全员-B证考试总结
  6. 攻克 Linux 系统编程
  7. Android 的 fdsan 文件描述符相关介绍
  8. 【饭谈】面试官让你来个“自我介绍”,你准备怎么说?
  9. 队列做题:1333:Blah数集(单调队列);1334:围圈报数
  10. 接口自动化获取excel中数据(一)