Blog Of Leung

personal blog & work notes

View project onGitHub
 

android中使用addr2line工具查so库错误

对android设备debug的时候,如果是内核报错,空指针之类的,会看到非常详细的堆栈信息,跟着信息就可以顺藤摸瓜去翻源码,然后检查代码。

但是如果是动态库错误的话,通常能返回的就是报错的内存地址信息,直接看log是看不出问题的,这时候就应该借助工具了。

addr2line是一个不错的工具,满足一定条件下,它可以根据报错的内存地址信息反查出对应在源代码的行数。

需要满足的条件是:代码需要是带-g参数编译的,这样才会带调试器可利用的信息。

在android的sdk中已经包含这个工具,路径是 prebuilts/tools/gcc-sdk/addr2line

假设我们抓到了以下的log,留意关键字pc,pc就是程序计数器,后面跟的实际就是内存地址

I/DEBUG   (  101):     #00  pc 00b24f72  /system/lib/libwebviewchromium.so

那么直接在工程根目录下执行

 ./prebuilts/tools/gcc-sdk/addr2line -e out/target/product/xxx/system/lib/libwebviewchromium.so 00b24f72

假设顺利的话,addr2line工具就会在终端返回类似以下的信息,是代码的绝对路径+报错的行数

/home/leung/mid/pure_project/rk3188_mid_4.4.2/external/chromium_org/cc/trees/ layer_tree_host_impl.cc:2414

到此,基本就可以知道到哪去检查错误了。

----------------------------------------我是分割线----------------------------------------

抓log的时候,相关信息通常都是大面积的。如下。。。

addr2line-log-info

相信我,花点时间写个shell,进行一些自动化的处理是值得的。根据上面的addr2line调用方法以及报错的信息,其实我们调用addr2line对so库排查需要的东西就两样,so库的路径和地址信息。我们直接把抓到的log信息保存到一个文件中,再作为参数传进shell脚本中分析,然后在shell脚本中循环执行,那么就可以实现自动化处理了。或者说,半自动化。

下面是我的脚本,虽然不太智能,但在android源码环境下已经可用。

#!/bin/bash

############################################################################################################
# version:v0.1
# author:leung
# 该脚本的目的是希望利用addr2line工具,从so库的报错信息中,找出对应在源码中的错误位置
# 该脚本应当运行在android的根目录,并且预先执行source xxx和lunch xxx命令
# 把报错信息按一定格式保存到一个文件中,然后在执行该脚本时作为参数传进去运行,如./addr2line.sh log.tmp
# 错误信息的文本格式请参考log.tmp文件
#
# 该脚本的期望只是半自动使用addr2line工具,有啥疑难杂症,请回归手动,useage参考如下:
# ./prebuilts/tools/gcc-sdk/addr2line -e xxx.so 0011baba
############################################################################################################

set -e

if [ ! $1 ]; then
    echo "you should run this like './addr2line.sh xxxx'"
    exit -1
else
    filename="$1"
fi

if [ ! $OUT ]; then
    echo "you should source and lunch a product first!"
    exit -1
fi

line_num=$(cat $filename | wc -l)
addr_length=8    #默认地址为64位,例如00b2c931
output_file="$filename.out"

cp $filename $filename.out
echo -e "\n" >> $output_file

count=1
tc1=$(date +%s)
while [ $count -le $line_num ];
do
    each_line=$(cat $filename | sed -n $count'p')      
    position=$(($(expr index "$each_line" "pc")+3))    #确定报错内存地址信息在字符串中的位置,以pc作为关键字
    addr_data=$(expr substr "$each_line" $position $addr_length)  #提取子字符串并保存
    check_so=${each_line:$(($position+10))}     #提取so库的路径信息
    check_so=$OUT/symbols/$check_so             #对路径信息补全,使用完整的绝对路径
    if [ ! -f $check_so ]; then
        echo "$check_so not found" >> $output_file
        count=$(($count+1))
        continue
    fi
    ./prebuilts/tools/gcc-sdk/addr2line -e $check_so $addr_data >> $output_file    #利用addr2line工具分析
    count=$(($count+1))
done
tc2=$(date +%s)
echo -e "\n\t done.\n\t it takes $(($tc2 - $tc1)) seconds."
echo -e "\t output file: $output_file\n"

exit 0

Author:leung

17 Apr 2014

← Home

comments powered by Disqus