【NDK系列】Android tombstone文件分析

文件位置

data/tombstone/tombstone_xx.txt

获取tombstone文件命令:

  1. adb shell cp /data/tombstones ./tombstones

触发时机

NDK程序在发生崩溃时,它会在路径/data/tombstones/下产生导致程序crash的文件tombstone_xx,记录了死亡了进程的基本信息(例如进程的进程号,线程号),死亡的地址(在哪个地址上发生了Crash),死亡时的现场是什么样的(记录了一系列的堆栈调用信息)等等。

内容示例

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4
    eax a6265c06  ebx b7467d88  ecx b7631a22  edx a6265c06
    esi 00000000  edi b6867140
    xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007b
    eip b745a639  ebp bfcfc1e8  esp bfcfc150  flags 00010282
 
backtrace:
    #00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #01 pc 00034b86  /system/lib/libsurfaceflinger.so
    #02 pc 0003229e  /system/lib/libsurfaceflinger.so
    #03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)
    #04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)
    #05 pc 0004eafb  /system/lib/libgui.so (android::Surface::queueBuffer(ANativeWindowBuffer*, int)+411)
    #06 pc 0004ce06  /system/lib/libgui.so (android::Surface::hook_queueBuffer(ANativeWindow*, ANativeWindowBuffer*, int)+38)
    #07 pc 00014bc6  /system/lib/egl/libGLES_android.so
    #08 pc 00017f73  /system/lib/egl/libGLES_android.so (eglSwapBuffers+163)
    #09 pc 00015fdb  /system/lib/libEGL.so (eglSwapBuffers+203)
    #10 pc 000013ea  /system/lib/hw/hwcomposer.x86.so
    #11 pc 00034730  /system/lib/libsurfaceflinger.so
    #12 pc 000256d4  /system/lib/libsurfaceflinger.so
    #13 pc 00024bf4  /system/lib/libsurfaceflinger.so
    #14 pc 000236fb  /system/lib/libsurfaceflinger.so
    #15 pc 0002338a  /system/lib/libsurfaceflinger.so
    #16 pc 0001e0ff  /system/lib/libsurfaceflinger.so
    #17 pc 0001d9ce  /system/lib/libutils.so (android::Looper::pollInner(int)+926)
    #18 pc 0001db73  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+67)
    #19 pc 0001e561  /system/lib/libsurfaceflinger.so
    #20 pc 00022ce7  /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::run()+39)
    #21 pc 00000ca3  /system/bin/surfaceflinger
    #22 pc 0001365a  /system/lib/libc.so (__libc_init+106)
    #23 pc 00000da8  /system/bin/surfaceflinger
 
stack:
         bfcfc110  00000000  
         bfcfc114  b6839270  
         bfcfc118  00000000  
         bfcfc11c  00000000  
         bfcfc120  b68394e0  
         bfcfc124  00000002  
         bfcfc128  00000002  
         bfcfc12c  b75d8185  /system/lib/libutils.so (android::RefBase::incStrong(void const*) const+53)
         bfcfc130  b6839270  
         bfcfc134  bfcfc1e8  [stack]
         bfcfc138  00000002  
         bfcfc13c  a6265c06  
         bfcfc140  b7467d88  /system/lib/libui.so
         bfcfc144  00000000  
         bfcfc148  b6867140  
         bfcfc14c  b745a639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #00  bfcfc150  b683af18  
         bfcfc154  bfcfc1e8  [stack]
         bfcfc158  00000000  
         bfcfc15c  00000000  
         bfcfc160  00000000  
         bfcfc164  b683af18  
         bfcfc168  b75ec9c4  /system/lib/libutils.so
         bfcfc16c  b75d8285  /system/lib/libutils.so (android::RefBase::weakref_type::decWeak(void const*)+37)
         bfcfc170  00000000  
         bfcfc174  00000000  
         bfcfc178  00000000  
         bfcfc17c  00000000  
         bfcfc180  b7642968  /system/lib/libsurfaceflinger.so
         bfcfc184  bfcfc1e8  [stack]
         bfcfc188  b6867140  
         bfcfc18c  b7622b87  /system/lib/libsurfaceflinger.so

构建指纹

Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'

典型的格式为:AOSP/[Android Version]/[Build ID]/[Build Date]

  • "Android-x86": 表示Android-x86工程
  • "android_x86": 表示Android-x86工程的分支名或者构建变体
  • "x86:5.1.1": 表示安卓版本为5.1.1, 即Lollipop。"x86"表示其针对x86架构CPU进行优化
  • "LMY48W": 表示构建号(build number),构建号可以自定义,比如某个feature、bugfix的提交号
  • "woshijpf04211939:eng": 自定义标签,比如构建者、构建目等,"eng" 可能表示使用了engineering配置
  • "test-keys": 表示此构建使用了测试key而不是正式发布的key文件

崩溃的过程和PID

pid: 1019, tid: 1019, name: surfaceflinger  >>> /system/bin/surfaceflinger <<<

如果pid等于tid,那么就说明这个程序是在主线程中Crash掉的,名称的属性则表示Crash进程的名称以及在文件系统中位置。

终止信号和故障地址

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4

信息说明出现进程Crash的原因是因为程序产生了段错误的信号,访问了非法的内存空间,而访问的非法地址是0x4。

典型的内存地址访问错误:

  1. 野指针
  2. 内存泄露
  3. 堆栈溢出
  4. 初始化错误
  5. 类型转换错误
  6. 数字除0

Linux信号机制

崩溃信号列表

信号机制是Linux进程间通信的一种重要方式,Linux信号一方面用于正常的进程间通信和同步,如任务控制(SIGINT,SIGTSTP,SIGKILL,SIGCONT,...);另一方面,它还负责监控系统异常及中断。当应用程序运行异常时,Linux内核将产生错误信号并通知当前进程。当前进程在接收到该错误信号后,可以有三种不同的处理方式:

  1. 忽略该信号。
  2. 捕捉该信号并执行对应的信号处理函数(信号处理程序)。
  3. 执行该信号的缺省操作(如SIGSEGV,其缺省操作是终止进程)。

当Linux应用程序在执行时发生严重错误,一般会导致程序崩溃。其中,Linux专门提供了一类crash信号,在程序接收到此类信号时,缺省操作是将崩溃的现场信息记录到核心文件,然后终止进程。

CPU寄存器

调用堆栈

backtrace:
    #00 pc 00006639  /system/lib/libui.so (android::Fence::waitForever(char const*)+41)
    #01 pc 00034b86  /system/lib/libsurfaceflinger.so
    #02 pc 0003229e  /system/lib/libsurfaceflinger.so
    #03 pc 0002cb9c  /system/lib/libgui.so (android::BufferQueue::ProxyConsumerListener::onFrameAvailable(android::BufferItem const&)+652)
    #04 pc 000342f4  /system/lib/libgui.so (android::BufferQueueProducer::queueBuffer(int, android::IGraphicBufferProducer::QueueBufferInput const&, android::IGraphicBufferProducer::QueueBufferOutput*)+2580)
  • #00,#01,#02表示函数调用栈中栈帧的编号,编号越小的栈帧表示着当前最近调用的函数信息,所以栈帧标号#00表示的就是当前正在执行并导致程序崩溃函数的信息。
  • pc后面的16进制数值表示的是当前函数正在执行的语句在共享链接库或者可执行文件中的位置
  • /system/lib/libui.so表示的是当前执行指令是在哪个文件当中
  • 小括号则是注明对应的是哪个函数
    例如,在上面的例子中,我们就可以定位到是程序是在Fence :: waitForever(char const *)中出现了错误,但是具体在那一行呢,我们还不是特别清楚,所以就需要我们进一步地使用更加高级的工具来帮助我们解析tombstone中有关调用栈的信息。

堆叠每个通话的内容

处理工具

Google在NDK包中为我们提供了一系列的调试工具:

  • addr2line
  • objdump
  • ndk-stack

在介绍上述工具的使用方法之前有必要再次介绍一下so文件的构成,虽然这部分内容属于NDK范畴。

so文件介绍

so文件组成

完整的 .so 文件由 C/C++代码和一些 debug 信息组成,这些 debug 信息会记录 .so中所有方法的对照表,就是方法名和其偏移地址的对应表,也叫做符号表symbolic 信息,这种.so被称为未strip的,通常体积会比较大。

注意:

  1. 符号表可以类比为 Java 代码混淆中的 mapping 文件,只有拥有这个 mapping 文件才能进行堆栈分析。
  2. 编译完so文件后,需要保留「机器码+debug信息的完整so文件」或者「仅含debug信息的符号表文件」

可以通过file命令查看so文件基本信息,以判断是否包含debug信息:

bash 复制代码
# 查看已被stripped的so文件
file libbreakpad-core-s.so
libbreakpad-core-s.so: *******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, stripped
# 查看未被stripped的so文件
file libbreakpad-core.so
libbreakpad-core.so: ******, BuildID[sha1]=54ad86d708f4dc0926ad220b098d2a9e71da235a, with debug_info, not stripped

so文件获取

目前 Android Studio 无论是使用 mk 或者 Cmake 编译的方式都会同时输出 strip 和未 strip 的 so:

  • strip 之前的 so 路径:{project}/app/build/intermediates/merged_native_libs
  • strip 之后的 so 路径:{project}/app/build/intermediates/stripped_native_libs

如下图是 Cmake 编译 so 产生的两个对应的 so:

addr2line

该工具通过输入so文件和backtrace中的地址来输出源码中的行号,支持一次性输入多个地址。

工具路径:

  • Mac OS:$NDK_ROOT/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin/i686-linux-android-addr2line

最佳实践:

alias addr2line='$NDK_HOME/toolchains/x86-4.6/prebuilt/linux-x86/bin/i686-linux-android-addr2line'

注意:

  1. so文件需要带符号表,位于out/target/product/cc_company/symbols/system/lib
  2. 由于是逐行解析,因此想要得到完整的源码调用栈需要自行封装写个脚本工具;

用法

Usage:android-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
  -v --version           Display the program's version

android-addr2line: supported targets: elf32-i386 elf32-iamcu a.out-i386-linux pei-i386 elf64-x86-64 elf32-x86-64 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://www.sourceware.org/bugzilla/>

推荐:add2line -fCp -e /path/to/xxx.so \<addresses\>

示例

执行命令:
addr2line -f -e libui.so 00006639

输出结果:

_ZN7android5Fence11waitForeverEPKc
/home/woshijpf/newspace/android-x86/frameworks/native/libs/ui/Fence.cpp:59

ndk-stack

可将墓碑文件中的backtrace和stack完整还原成源码文件路径+代码行号的呈现方式。

工具路径:$NDK_HOME/ndk-stack

注意:

  1. 需要obj目录,例如obj/local/x86/
  2. 通常用于本地调试阶段的问题排查,对于线上问题排查时不一定保留这些符号表文件

用法

Usage:
   ndk-stack -sym <path> [-dump <path>]
 
      -sym  Contains full path to the root directory for symbols.
      -dump Contains full path to the file containing the crash dump.
            This is an optional parameter. If ommited, ndk-stack will
            read input data from stdin
  • sym: 需要输入符号表文件的根目录,即obj目录
  • dump:输入指定的trace文本文件路径或者若缺省则从标准输入读取

示例

原墓碑文件内容:

// tombstone_01 文件内容
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
Revision: '0'
ABI: 'x86'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    eax 00000000  ebx b76ffff4  ecx b6a37000  edx 00000000
    esi 00000000  edi 00000000
    xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000  xss 0000007b
    eip b75a4ec5  ebp bfa9bd08  esp bfa9bbf0  flags 00010246
 
backtrace:
    #00 pc 0004bec5  /system/bin/androidvncserver
    #01 pc 0004e3e4  /system/bin/androidvncserver
    #02 pc 0001365a  /system/lib/libc.so (__libc_init+106)
    #03 pc 0001060c  /system/bin/androidvncserver
 
stack:
         bfa9bbb0  bfa9bbc8  [stack]
         bfa9bbb4  b72c6fb0  /system/lib/libdvnc_flinger_sdk22.so
         bfa9bbb8  b72c7004  /system/lib/libdvnc_flinger_sdk22.so
         bfa9bbbc  b72c5b26  /system/lib/libdvnc_flinger_sdk22.so (readfb_flinger+38)
         bfa9bbc0  b68ae080  
         bfa9bbc4  00000000  
         bfa9bbc8  00000000  
         bfa9bbcc  00000000  
         bfa9bbd0  00000000  
         bfa9bbd4  b76ffff4  /system/bin/androidvncserver
         bfa9bbd8  b76a5e20  /system/bin/androidvncserver
         bfa9bbdc  b75ac181  /system/bin/androidvncserver
         bfa9bbe0  b75ac16b  /system/bin/androidvncserver
         bfa9bbe4  b76ffff4  /system/bin/androidvncserver
         bfa9bbe8  bfa9bd08  [stack]
         bfa9bbec  b75a579b  /system/bin/androidvncserver
    #00  bfa9bbf0  00000012  
         bfa9bbf4  bfa9bc1c  [stack]
         bfa9bbf8  00000000  
         bfa9bbfc  00000000  
         bfa9bc00  bfa9bc14  [stack]
         bfa9bc04  00000000  
         bfa9bc08  00000000  
         bfa9bc0c  b7498825  /system/lib/libc.so (je_free+453)
         bfa9bc10  0000000e  
         bfa9bc14  00000400  
         bfa9bc18  00000000  
         bfa9bc1c  b749538a  /system/lib/libc.so (je_malloc+778)
         bfa9bc20  0000000c  
         bfa9bc24  00000065  
         bfa9bc28  00000000  
         bfa9bc2c  b6a37000  
         ........  ........
    #01  bfa9bd10  b6bb7300  
         bfa9bd14  00001b58  
         bfa9bd18  b76aa954  /system/bin/androidvncserver
         bfa9bd1c  0000000b  
         bfa9bd20  00000005  
         bfa9bd24  00000000  
         bfa9bd28  00000000  
         bfa9bd2c  00000005  
         bfa9bd30  00000006  
         bfa9bd34  00000005  
         bfa9bd38  00000000  
         bfa9bd3c  00000000  
         bfa9bd40  00000000  
         bfa9bd44  bfa9bd24  [stack]
         bfa9bd48  b754f9c8  /system/bin/linker
         bfa9bd4c  b7557bd8  /system/bin/linker
         ........  ........
    #02  bfa9bed0  00000001  
         bfa9bed4  bfa9bf14  [stack]
         bfa9bed8  bfa9bf1c  [stack]
         bfa9bedc  00000000  
         bfa9bee0  b7556fec  /system/bin/linker
         bfa9bee4  bfa9bf10  [stack]
         bfa9bee8  00000000  
         bfa9beec  b7556fec  /system/bin/linker
         bfa9bef0  bfa9bf10  [stack]
         bfa9bef4  00000000  
         bfa9bef8  bfa9bf0c  [stack]
         bfa9befc  b756960d  /system/bin/androidvncserver
    #03  bfa9bf00  bfa9bf10  [stack]
         bfa9bf04  00000000  
         bfa9bf08  b756960d  /system/bin/androidvncserver
         bfa9bf0c  b7569612  /system/bin/androidvncserver
         bfa9bf10  00000001  
         bfa9bf14  bfa9cb05  [stack]
         bfa9bf18  00000000  
         bfa9bf1c  bfa9cb16  [stack]
         bfa9bf20  bfa9cb35  [stack]
         bfa9bf24  bfa9cb48  [stack]
         bfa9bf28  bfa9cba3  [stack]
         bfa9bf2c  bfa9cbae  [stack]
         bfa9bf30  bfa9cbc1  [stack]
         bfa9bf34  bfa9cbdc  [stack]
         bfa9bf38  bfa9cbe7  [stack]
         bfa9bf3c  bfa9cbfd  [stack]

执行命令:
ndk-stack -sym obj/local/x86/ -dump ~/android-x86-debug-log/tombstone_01

输出结果:

********** Crash dump: **********
Build fingerprint: 'Android-x86/android_x86/x86:5.1.1/LMY48W/woshijpf04211939:eng/test-keys'
pid: 2125, tid: 2125, name: androidvncserve  >>> androidvncserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
Stack frame #00 pc 0004bec5  /system/bin/androidvncserver: Routine update_screen_16 in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/updateScreen.c:68
Stack frame #01 pc 0004e3e4  /system/bin/androidvncserver: Routine main in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:805
Stack frame #02 pc 0001365a  /system/lib/libc.so (__libc_init+106)
Stack frame #03 pc 0001060c  /system/bin/androidvncserver: Unable to locate routine information for address 1060c in module obj/local/x86//androidvncserver
Stack frame #00 pc 0007bf71  /system/lib/libc.so (nanosleep+17)
Stack frame #01 pc 00047ed6  /system/lib/libc.so (usleep+70)
Stack frame #02 pc 0004fa6b  /system/bin/androidvncserver: Routine camera_io in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/camera_io.c:557
Stack frame #03 pc 0004af6a  /system/bin/androidvncserver: Routine receive_camera in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/droidvncserver.c:273
Stack frame #04 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #05 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #06 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)
Stack frame #00 pc 0007cc33  /system/lib/libc.so (recvfrom+19)
Stack frame #01 pc 00050cdb  /system/bin/androidvncserver: Routine handle_connections in /home/woshijpf/android_workspace/droidVNCserver-real/jni/vnc/gui.c:105
Stack frame #02 pc 00022168  /system/lib/libc.so (__pthread_start(void*)+56)
Stack frame #03 pc 0001cc69  /system/lib/libc.so (__start_thread+25)
Stack frame #04 pc 000137c6  /system/lib/libc.so (__bionic_clone+70)

objdump

使用objdump命令对目标文件(obj)或可执行文件进行反汇编,它以一种可阅读的格式让你更多的了解二进制文件可能带有的附加信息。

参考文章:objdump的使用

参考资料

相关推荐
C4rpeDime13 分钟前
自建MD5解密平台-续
android
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
m0_548514776 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯6 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯6 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐7 小时前
Handle
android
m0_748232928 小时前
Android Https和WebView
android·网络协议·https
m0_748251728 小时前
Android webview 打开本地H5项目(Cocos游戏以及Unity游戏)
android·游戏·unity
m0_7482546610 小时前
go官方日志库带色彩格式化
android·开发语言·golang
zhangphil10 小时前
Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现“刮刮乐”效果,Kotlin(2)
android·kotlin