Android NDK墓碑/崩溃分析

前言

作为程序员,调试Bug永远是最痛苦的一件事情,而在所有的Bug当中访问非法内存又是最为让人崩溃和最难发现的一个问题。

通常我们调试程序Bug的方法主要有下面3种:

  1. 打印日志信息这种方法通过在代码中可能出现Bug的位置添加一些日志输出语句来跟踪整个程序的执行过程或者查看关键变量的值等等。
  2. 单步调试这个方法则主要使用到了调试工具,例如gdb和Visual Studio中内置的调试器。这些高级的工具使得我们可以在程序中任何位置设置断点,或者查看相关变量的值,或者更进一步直接查看CPU中寄存器的值。
  3. 分析崩溃后的错误信息这种方法则主要是分析程序崩溃之后产生的错误信息相关文件来确定产生Bug的原因和位置。

Android开发中常见Crash的情况

在Android开发中,程序崩溃分三种情况:

  • 未捕获的异常
  • ANR(应用程序不响应)
  • 闪退(NDK程序引发错误)

其中未捕获的异常根据logcat打印的堆栈信息很容易定位错误。

ANR错误也好查,机器人规定,应用与用户进行交互时,如果5秒内没有响应用户的操作,则会引发ANR错误,并弹出一个系统提示框,让用户选择继续等待或立即关闭程序。并会在/数据/ ANR目录下生成一个traces.txt文件,记录系统产生ANR异常的堆栈和线程信息。

如果是闪退,这个问题比较难查,通常是项目中用到了NDK引发某类致命的错误导致闪退。因为NDK是使用C / C ++来进行开发,熟悉C / C ++的程序员都知道,指针和内存管理是最重要也是最容易出问题的地方,稍有不慎就会遇到诸如内存地址访问错误,使用野指针,内存泄露,堆栈溢出,初始化错误,类型转换错误,数字除0等常见的问题,导致最后都是同一个结果:程序崩溃。它不会像在Java层产生的异常时弹出“xxx程序无响应,是否立即关闭”之类的提示框当发生NDK错误后,logcat打印出来的那堆日志根据看不懂,更别想从日志当中定位错误的根源。

那么我们怎么调试引发Crash的NDK程序呢?

哈哈,好在Google早就料到了我们写的NDK代码肯定会漏洞百出。首先,当NDK程序在发生崩溃时,它会在路径/ data / tombstones /下产生导致程序Crash的文件tombstone_xx。并且Google还在NDK包中为我们提供了一系列的调试工具,例如addr2lineobjdumpndk-stack

墓碑

Linux信号机制

在介绍墓碑之前,我们首先补充一个Linux信号机制的知识。

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

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

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

崩溃信号列表:

信号 描述
SIGSEGV 内存引用无效。
SIGBUS 访问内存对象的未定义部分。
SIGFPE 算术运算错误,除以零。
SIGILL 非法指令,如执行垃圾或特权指令
SIGSYS 糟糕的系统调用
SIGXCPU 超过CPU时间限制。
SIGXFSZ 文件大小限制。

什么墓碑?

Android本机程序本质上就是一个Linux程序,因此当它在执行时发生严重错误,也会导致程序崩溃,然后产生一个记录崩溃的现场信息的文件,而这个文件在Android系统中就是墓碑文件。

墓碑英文的本意是墓碑,我觉得用这个单词来表示程序Crash之后产生的现场死亡信息真的再恰当不过了,墓碑文件的正确就像墓碑一样记录了死亡了进程的基本信息(例如进程的进程号,线程号),死亡的地址(在哪个地址上发生了Crash),死亡时的现场是什么样的(记录了一系列的堆栈调用信息)等等。

因此,分析出现Crash的原因和代码位置最重要的就是分析这个墓碑文件。

墓碑文件位于路径/ data / tombstones /下,

root@x86:/data/tombstones # ls
tombstone_00
tombstone_01

它的主要内容如下所示:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
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

墓碑文件解析

第一次看到tombstone文件时,我也是一头雾水,一脸懵逼,加上调Bug时本来就烦躁的心情,简直不想多看它一眼。但是没办法,导致Crash的原因只有在这里才能找到,所以我们硬着头皮也要去分析啊(最好还在于心情比较平静时去调Bug吧,这样效率可能会更好一点)。

墓碑文件它主要由下面几部分组成:

  • 构建指纹
  • 崩溃的过程和PID
  • 终止信号和故障地址
  • CPU寄存器
  • 调用堆栈
  • 堆叠每个通话的内容

但是也不是tombstone中的信息我们都需要分析,我们最主要的就是分析崩溃的过程和PID终止的信号和故障地址调用堆栈部分。

崩溃过程和PID信息

从上面tombstone文件中的第5行中我们可以看到崩溃进程的基本信息,如下所示:

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

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

终止信号和故障地址信息

在上面tombstone文件中的第6行中我们可以看到程序是因为什么信号导致了Crash以及出现错误的地址,如下所示:

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

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

调用堆栈信息

调用栈信息是分析程序崩溃的非常重要的一个信息,它主要记录了程序在Crash前的函数调用关系以及当前正在执行函数的信息,它对应的是我们的墓碑文件中backtrace符号开始的信息,上面例中的backtrace的信息如下所示:

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中有关调用栈的信息。

定位崩溃源码位置的工具

前面我们简要地介绍了tombstone文件的结构以及每个部分的相关含义,我们可以得到导致程序Crash掉的主要原因是什么(根据Signal的类型),也知道了是在主线程还是在子线程中挂掉了,但是我们对程序具体在代码中的哪个位置挂掉了,还不是特别清楚,最多还只是通过回溯中的栈帧的信息大概定位到位于哪个函数中,但具体是哪个文件哪个函数那一行还是不清楚的。所以,我们接下来就需要借助一些更加高级的工具来定位Bug在代码中的具体位置。

说明

Google提供的Android NDK开发包中已经为我们提供了非常便利好用的解析工具了,我们主要使用了下面两种工具来解析tombstone:

  • addr2line
  • NDK堆栈

所以,在使用这两种工具之前,你首先得把Android NDK工具包在你的电脑上安装好。

addr2line

addr2line是NDK中用来获得指定动态链接库文件或者可执行文件中指定地址对应的源代码信息,它们位于NDK包中的如下位置中:

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

其中NDK_HOME表示你的NDK的安装路径。 虽然在Linux中同样有addr2line命令了,但是它与NDK中提供的addr2line指令还是略有差别的,所以我们可以使用别名来将shell中默认的addr2line指令链接的NDK的上述路径中,命令如下所示:

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

这样之后,我们就可以在Linux中的shell环境中来直接使用addr2line命令了。addr2line命令的各个参数的含义如下所示:

woshijpf@woshijpf-OptiPlex-9020:~/newspace/android-x86/out/target/product/x86/symbols/system/lib$ 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
  -v --version           Display the program's version

addr2line: supported targets: elf64-x86-64 elf32-i386 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-i386 plugin srec symbolsrec verilog tekhex binary ihex
Report bugs to <http://www.sourceware.org/bugzilla/>

addr2line的基本用法如下所示:

woshijpf@woshijpf-OptiPlex-9020:~/newspace/android-x86/out/target/product/x86/symbols/system/lib$ addr2line -f -e libui.so 00006639
_ZN7android5Fence11waitForeverEPKc
/home/woshijpf/newspace/android-x86/frameworks/native/libs/ui/Fence.cpp:59

哈哈,使用了addr2line工具之后,我们终于看到libui.so文件中地址00006639对应的源码是什么了,它对应的是Android系统源码中/ home / woshijpf / newspace / android-x86 / frameworks / native / libs /ui/Fence.cpp:59处代码(因为上面的tombstone文件是由于Android系统中的surfaceFlinger进程崩溃而产生的,所以它对应的源码也是Android系统中有关SurfaceFlinger部分的源码)。

NDK堆栈

Android NDK自从版本r6开始,提供了一个工具ndk-stack。这个工具能自动分析tombstone文件,能将崩溃时的调用内存地址和c ++代码一行一行对应起来。

ndk-stack工具同样也位于NDK包中,它的路径如下所示:

$NDK_HOME/ndk-stack

ndk-stack的使用说明如下所示:

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

其中,

  • dump参数很容易理解,即dump下来的log文本文件。ndk-stack会分析此文件,这里我们就是指定我们从Android系统中获取到的tombstone(这个需要通过adb拉的方式拉取到本地的宿主机中)文件存放的位置。
  • sym参数就是你的android项目下,编译成功之后,obj目录下的文件。

由于ndk-stack主要是用来分析用C ++编写的单独的NDK程序,所以下面就以解析一个NDK程序运行时Crash后产生的墓碑为例,墓碑文件的内容如下所示:

// 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堆叠处理之后的结果:

woshijpf@woshijpf-OptiPlex-9020:~/android_workspace/droidVNCserver-real$ 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)

经过NDK叠地这么处理之后,我们就非常直接明了地看到了每个栈帧中调用函数的内存地址和程序源码的关系。是不是感觉很爽啊!

总结

Android NDK程序的系统调试其实也没那那复杂,虽然它长着一副恐怖的外表,但是只需掌握了正确的方法,了解Tombstone文件中关键信息的含义,学会使用addr2line和ndk_stack这两个超级方便的工具,那么一步一步找出导致NDK程序崩溃的Bug就是非常易了。但上面的这些工作也还只是帮助你快速地定位到你的代码出现问题的位置,具体的Bug还是需要你进一步地根据业务逻辑来分析代码。

参考链接

  1. [cocos2dx]利用NDK崩溃日志查找BUG] 0

  2. 使用ndk-stack和addr2line调试墓碑

  3. 调试本机Android平台代码

  4. Android Tombstone / Crash的日志分析和定位

  5. Android的重启原因分析

  6. android crash的类型和原因分析(上)

  7. Android调试

  8. Android平台抓取本机崩溃日志

  9. Android Debuggerd简要介绍和源码分析

  10. Android NDK墓碑分析工具

  • 8
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值