安卓Native崩溃定位

       安卓APP开发人员使用C或C++开发部分程序逻辑时容易出现进程直接崩溃,因此要求我们能分析C/C++崩溃日志和定位问题。本文介绍如何分析Native崩溃日志来确定C/C++代码出错的位置和原因。

  • Native代码示例及崩溃日志

 

安卓Native崩溃定位_第1张图片

这是一段可以引起崩溃的C代码,当调用crashStack(4)时,可以触发Native层的崩溃,一般情况下崩溃日志的格式如下:

安卓Native崩溃定位_第2张图片

其中backtrace下面的日志就是崩溃时函数堆栈调用信息,取第一行分析:

#00 pc 00001ae8  /data/app/com.open.tec-2/lib/arm/libzoom_test.so (crashStack+51)

#00

堆栈序号

pc 00001ae8

崩溃发生时,程序计数器位于libzoom_test.so的偏移量为00001ae8

crashStack+51

00001ae8处正好是相对crashStack符号偏移为51的一条指令

#01 pc 00001acb  /data/app/com.open.tec-2/lib/arm/libzoom_test.so (crashStack+22)

这是第二层堆栈,表示libzoom_test.so的00001acb位置,即相对crashStack偏移22发生函数调用,产生第一层堆栈。

  • Native崩溃分析工具

通常native编译后会有带调试信息和不带调试信息的so两个版本,一般带调试信息的so在工程obj/local/各abi目录下(obj位于工程目录或build/intermediates/ndkBuild下),其中还含有一些中间文件,比如.o文件,如下图:

安卓Native崩溃定位_第3张图片

这些含调试信息的so再经过strip命令去除部分符号表,调试信息即得到最终的发布版so。一般native分析崩溃的工具都是利用含有调试信息的so文件,结合崩溃信息,定位到源代码中的崩溃行号。

1. ndk stack

ndk stack工具位于ndk的根目录,如D:\ndk-bundle-r16b,在此目录下打开命令行窗口,运行命令如下:

ndk-stack -sym ......\obj\local\armeabi-v7a\ -dump crash_log.txt

或者运行:

adb logcat | ndk-stack -sym ......\obj\local\armeabi-v7a\

其中......需替换为obj目录所在的实际路径,crash_log.txt也是指崩溃log所在实际路径。注意-sym参数指示的路径都是obj\local\,并要匹配对应机器abi目录。运行结果如下:

安卓Native崩溃定位_第4张图片

可以看到crashStack+51位置对应Other.cpp的第9行,源码里对*p赋值时出现空指针导致崩溃。

2. addr2line

addr2line工具在ndk目录\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin下,此路径会因操作系统和文件名不同而有所不同。导航到此目录下,运行命令:

arm-linux-androideabi-addr2line.exe -e libzoom_test.so 00001ae8 00001acb

如果运行失败可以在该命令前加上“.\”,注意ndk stack接受obj\local\abi路径,而addr2line接受so文件,故命令中libzoom_test.so应该填入so文件的绝对路径,而00001ae8、00001acb是崩溃栈在so文件中的偏移量。

得到的输出:

同样能找到出错位置为Other.cpp的第9行。

3. objdump

objdump工具和addr2line位于同一目录下,ndk stack和addrline都是将崩溃点对应到源码的行数再进行分析,而objdump则可以在汇编层对崩溃原因进行分析,对开发人员要求了解一些arm/x86的汇编知识。

objdump命令:

arm-linux-androideabi-objdump.exe -s -d libzoom_test.so >D:\dump.txt

具此工具输出内容较多,将其输出到dump.txt文件再打开查看,定位到错误偏移点00001ae8位置:

安卓Native崩溃定位_第5张图片

可以看到偏移为1ae6 movs指令将值100存到寄存器r1中,然后str指令将r1中的数据写入r0+0为地址的寄存器中(出现崩溃),刚好对应的源码码为:

int *p = NULL;
*p = 100;

ndk stack和addr2line工具需要含有调试信息的so文件,如果so没有调试信息那就无能为力,这时候只有使用objdump工具了。

  • Native常见崩溃类型

1. SIGSEGV段错误

SEGV_MAPERR

要访问的地址没有映射到内存空间,如上面例子中的空指针写操作。(大部分异常是这种类型)

SEGV_ACCERR

访问的地址没有权限。如试图对代码段进行写操作。

2. SIGFPE浮点错误

FPE_INDIV

整数除以0

FPE_INTOVE

整数溢出

3. SIGBUS总线错误

BUS_ADRALN:地址对齐错误

4. SIGILL总线错误

ILL_ILLOPC

非法的指令操作码(CPU架构不匹配)

ILL_ILLOPN

非法的指令操作数

你可能感兴趣的:(安卓Native崩溃定位)