安卓backtrace分析流程
安卓backtrace分析流程
backtrace是Linux用于日志诊断的工具,回溯线程当前活动的函数调用列表。安卓程序发生崩溃等异常会打印backtrace信息,一般位于"/data/tombstones"或者mobile
log和kernel log中,分析流程如下:
若没有backtrace所在的symbols-library(符号库),则需编译对应模块获取。
- 从日志中获取异常调用栈,获取符号库文件
- 通过
objdump定位库文件中的汇编代码 - 通过
addr2line定位到C/C++代码 - 结合调用栈、汇编代码和
C/C++代码分析
Linux backtrace
概要:
1 | |
说明:
backtrace是程序当前活动的函数调用栈,参数buffer指向一个用于存放栈帧地址的数组,size是这个栈帧数组的最大长度,如果backtrace总栈帧数大于size,则剩余的栈帧不会继续回溯,backtrace从当前栈帧依次向上回溯。
backtrace()返回存放在buffer缓冲区中的地址数。backtrace_symbols()函数获取backtrace并将栈帧地址转换为字符串描述,返回描述栈帧的字符串数组。栈帧地址的符号格式:"program(function+offset) [address]"backtrace_symbols_fd()函数具有backtrace_symbols函数相同功能,但是它将描述栈帧的字符串数组写入fd文件中,返回值与backtrace()一样。
注:backtrace_symbols函数的返回值将通过malloc函数申请的字符串数组,如果出现错误,返回值将是NULL,调用者需要检查释放此内存,但是不能释放此数组中字符串。
objdump和addr2line
Binutils是一组二进制文件处理工具,包括:addr2line, ar, objcopy, objdump, as, ld, ldd, readelf, size等,此处只讲解objdump和addr2line.
objdump
objdump用于查看二进制文件的信息。
objdump [options] objfile
选项:(仅列出部分)
-C将底层符号名显示为C/C++标识符(例如函数)-g显示调试信息,尝试以C语法显示-d反汇编机器指令码的section(如.text代码段)-D与-d类似,但反汇编所有section-H显示帮助信息-j仅仅显示指定的section信息(用法:"-j name")-l用文件名和行号标注相应的目标代码(仅仅与-d,-D或-r一起使用)-m指定反汇编文件时使用的处理器架构-r显示文件的重定位表的入口-R显示文件的动态重定位表的入口-s显示指定section的完整内容,默认显示所有非空section-S尽可能反汇编出源代码并显示(隐含了-d参数)-t显示文件的符号表入口-T显示文件的动态符号表入口-V显示版本信息
addr2line
addr2line将代码地址转为文件名和行号。
addr2line [options] address
选项:(仅列出部分)
-a在函数名、文件名和行号信息之前,以十六进制显示地址-b指定目标文件的目标代码格式(用法:"-b bfdname")-e指定需要转换地址的文件名(用法:"-e filename")-j表明给出的地址代表指定section的偏移(用法:"-j name")-C将底层符号显示为C/C++标识符(例如函数)-f在显示文件名和行号的同时显示函数名信息-s仅显示每个文件名的基础名-p美观的显示,每个地址信息各占一行
编译安卓模块源码
为了调试安卓源码并定位具体问题,需要能够编译系统源码,有单编和整编两种方式。
安卓编译系统概述
- Makefile 安卓有许多Makefile文件共同组成一个自动化编译系统
- Android.mk Makefile编译系统的一部分,定义了一个模块的必要参数
- Ninja Ninja是一个致力于速度的小型编译系统(目前AOSP源码的编译方式)
- Soong Soong是谷歌用于替代Makefile编译工具,将Android.bp文件转为Ninja文件
- Blueprint 用于解析Android.bp文件,是Soong的一部分
- kati 是专为Android开发的基于Golang和C++的工具,将Android.mk文件转为Ninja文件
- Android.bp 是谷歌用于替换Android.mk的文件,是纯粹的配置,没有流程控制和运算
安卓源码整编
- 初始化环境,在AOSP的根目录执行命令:
source build/envsetup.sh - 选择编译目标,根据提示选择编译目标,命令:
lunch - 开始编译,可通过
-jN参数来设置并行任务数(默认由编译程序确定),命令:m
安卓源码单编
单编和整编流程一样,但是编译命令不一样,主要有如下命令:
mm构建当前目录下的所有模块,但是不包括其依赖mmm构建指定目录下的所有模块(格式:"mmm dir/:module"),但是不包括其依赖mma构建当前目录下的所有模块(类似mm),也包括其依赖mmma构建指定目录下的所有模块(类似mmm),也包括其依赖
在初始化安卓编译环境後,可以通过hmm命令查看有关说明。
安卓backtrace示例分析
安卓的addr2line和objdump
这里我们下载安卓的NDK工具包,选择Linux版本,解压到Linux路径上,通过`alias`定义两个别名以方便使用,例如:
alias addr3line='~/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line'
alias objdump2='~/android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump'
因为在Linux上也是有原来的addr2line和objdump的,所以这个别名需要定义为其他名字。至于这两个工具所在的路径,不同NDK可能会不一样,在NDK路径下用以下命令查找即可:
find . -name *addr2line*
find . -name *objdump*
这两个工具的使用方法也和Linux上的一样(会有细微区别),此处就不详讲。