安卓backtrace分析流程

安卓backtrace分析流程

backtrace是Linux用于日志诊断的工具,回溯线程当前活动的函数调用列表。安卓程序发生崩溃等异常会打印backtrace信息,一般位于"/data/tombstones"或者mobile log和kernel log中,分析流程如下:

若没有backtrace所在的symbols-library(符号库),则需编译对应模块获取。

  1. 从日志中获取异常调用栈,获取符号库文件
  2. 通过objdump定位库文件中的汇编代码
  3. 通过addr2line定位到C/C++代码
  4. 结合调用栈、汇编代码和C/C++代码分析

Linux backtrace

概要:

1
2
3
4
#include <execinfo.h>
int backtrace(void **buffer, int size);
char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);

说明:

backtrace是程序当前活动的函数调用栈,参数buffer指向一个用于存放栈帧地址的数组,size是这个栈帧数组的最大长度,如果backtrace总栈帧数大于size,则剩余的栈帧不会继续回溯,backtrace从当前栈帧依次向上回溯。

  1. backtrace()返回存放在buffer缓冲区中的地址数。
  2. backtrace_symbols()函数获取backtrace并将栈帧地址转换为字符串描述,返回描述栈帧的字符串数组。栈帧地址的符号格式: "program(function+offset) [address]"
  3. 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 美观的显示,每个地址信息各占一行

编译安卓模块源码

为了调试安卓源码并定位具体问题,需要能够编译系统源码,有单编和整编两种方式。

安卓编译系统概述

  1. Makefile 安卓有许多Makefile文件共同组成一个自动化编译系统
  2. Android.mk Makefile编译系统的一部分,定义了一个模块的必要参数
  3. Ninja Ninja是一个致力于速度的小型编译系统(目前AOSP源码的编译方式)
  4. Soong Soong是谷歌用于替代Makefile编译工具,将Android.bp文件转为Ninja文件
  5. Blueprint 用于解析Android.bp文件,是Soong的一部分
  6. kati 是专为Android开发的基于Golang和C++的工具,将Android.mk文件转为Ninja文件
  7. Android.bp 是谷歌用于替换Android.mk的文件,是纯粹的配置,没有流程控制和运算

安卓源码整编

  1. 初始化环境,在AOSP的根目录执行命令: source build/envsetup.sh
  2. 选择编译目标,根据提示选择编译目标,命令: lunch
  3. 开始编译,可通过-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上的一样(会有细微区别),此处就不详讲。


安卓backtrace分析流程
https://blog.siantao.top/技术/计算机/软件/Android/内核/安卓backtrace分析流程/
作者
玉水仙楊
发布于
2023年3月1日
许可协议