App下载 微信公众号

SO库Crash问题定位工具 addr2line & objdump

技术 · 移动开发 · Android/ 作者【吾非言】/ 发布于2021-7-13/ 1.89k次浏览
2021 7/13 4:33
摘要: 在一个App中引入so库,去支持更加丰富的功能,已经不是一件罕见的事情了。那么so库引发线上错误或者Crash该如何处理呢?可能对于很多开发者来说有些无从入手,但如果可以通过工具定位到so库具体的错误位置,那么解决这个Crash就不远了。

addr2line(它是标准的 GNU Binutils 中的一部分)

addr2line translates addresses into file names and line numbers. Given an address in an executable or an offset in a section of a relocatable object, it uses the debugging information to figure out which file name and line number are associated with it.

直译过来就是addr2line作用在于将地址转换成文件名字以及代码行数,通过该命令,可以将寄存器的地址转换成对应的行数,方便发现以及改正Native的一些问题。

工具位置

如果使用NDK开发,addr2line一般位于toolchains目录对应 平台/CPU架构/位数32或64 目录下。

如:/…/android-ndk-r21b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line

相关指令参数

-a --addresses:在函数名、文件和行号信息之前,显示地址,以十六进制形式。
-b --target=:指定目标文件的格式为bfdname。
-e --exe=:指定需要转换地址的可执行文件名。
-i --inlines : 如果需要转换的地址是一个内联函数,则输出的信息包括其最近范围内的一个非内联函数的信息。
-j --section=:给出的地址代表指定section的偏移,而非绝对地址。
-p --pretty-print:使得该函数的输出信息更加人性化:每一个地址的信息占一行。
-s --basenames:仅仅显示每个文件名的基址(即不显示文件的具体路径,只显示文件名)。
-f --functions:在显示文件名、行号输出信息的同时显示函数名信息。
-C --demangle[=style]:将低级别的符号名解码为用户级别的名字。
-h --help:输出帮助信息。
-v --version:输出版本号。

所以如果想要通过addr2line工具查询so库中错误信息,如:文件名字以及代码行数,可以使用如下套式:

./aarch64-linux-android-addr2line -f -C -e 带符号so的文件路径 寄存器地址

具体实例

假如执行so库方法报如下错误:

图片描述

如果想要定位第一个位置的错误:

#00 pc 004ba9de  /data/data/com.wujie.chengxin/files/libdimina-v8.so (_ZN2v84base2OS5AbortEv+13)

只需要在CMD面板执行如下命令即可:

./arm-linux-androideabi-addr2line -f -C -e ../libdimina-v8.so 004ba9de

图片描述

具体指令如下:

Last login: Fri Jun 18 12:14:02 on ttys004
didi@zoufenli ~ % cd /Users/didi/Desktop/ffmpeg/android-ndk-r21b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin
didi@zoufenli bin % ./arm-linux-androideabi-addr2line -f -C -e /Users/didi/Desktop/didi-project/dimina-android/jscore-j2v8/src/main/jni/V8/lib/armeabi-v7a/libdimina-v8.so 004ba9de
v8::base::OS::AllocateShared(unsigned int, v8::base::OS::MemoryPermission)
libgcc2.c:?
didi@zoufenli bin %
v8::base::OS::AllocateShared(unsigned int, v8::base::OS::MemoryPermission)
libgcc2.c:?

如果MAC运行过程中提示 '无法打开“arm-linux-androideabi-addr2line”,因为无法验证开发者' 的错误,只需要打开设置,选择 ‘安全性与隐私’ ,点击仍然允许,重新运行即可。

注意事项:addr2line要选择对应位数的程序

aarch64-linux-android-4.9:so库为arm架构 64位
arm-linux-androideabi-4.9:so库为arm架构 32位

mips64el-linux-android-4.9:so库为mips架构 64位
mipsel-linux-android-4.9:so库为mips架构 32位

x86_64-4.9:so库为x86架构 64位
x86-4.9:so库为x86架构 32位

根据所生成的so的架构平台不同,选择不同的架构平台文件夹里的文件程序,如我这里的so文件架构是arm 32位的,所以选择arm-linux-androideabi-4.9里的文件程序。

如何判断是32位还是64位?

可根据报错log中pc字段后的数字个数“004ba9de”,如为8个,是32位的;如为16个,是64位的。

objdump(gcc工具,用来查看编译后目标文件的组成)

objdump displays information about one or more object files. The options control what particular information to display. This information is mostly useful to programmers who are working on the compilation tools, as opposed to programmers who just want their program to compile and work.

objdump主要用于获取对应so库的汇编代码。

工具位置

如果使用NDK开发,objdump一般位于toolchains目录对应 平台/CPU架构/位数32或64 目录下。

如:/…/android-ndk-r21b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump

相关指令参数

图片描述

objdump实现展示错误信息一般采用如下套式:

arm-linux-androideabi-objdump -d 带符号so的文件路径(库文件) > 输出文件

具体实例

假如执行so库方法报如下错误:

图片描述

如果想要定位第一个位置的错误:

#00 pc 004ba9de  /data/data/com.wujie.chengxin/files/libdimina-v8.so (_ZN2v84base2OS5AbortEv+13)

只需要在CMD面板执行如下命令即可:

./arm-linux-androideabi-objdump -d ../libdimina-v8.so > ../test.md

图片描述

运行arm-linux-androideabi-objdump命令之后,将会把so的汇编代码输入到test.md文件中:

图片描述

这个时候分析寄存器地址004ba9de,(_ZN2v84base2OS5AbortEv+13)偏移量为13,所以真实地址是4ba9ec。在test.md文件中找到4ba9ec位置,就能找到在该区域内的调用方法:

_ZN2v84base2OS14AllocateSharedEjNS1_16MemoryPermissionE

这里的方法名不容易看懂,可以使用 arm-linux-androideabi-c++filt 命令找到实际的代码段可以更方面定位:

图片描述

其中arm-linux-androideabi-c++filt工具和arm-linux-androideabi-objdump属于同一个目录下,所以可以直接使用。

具体指令如下:

Last login: Fri Jun 18 17:08:28 on ttys003
didi@zoufenli ~ % cd /Users/didi/Desktop/ffmpeg/android-ndk-r21b/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin
didi@zoufenli bin % ./arm-linux-androideabi-objdump -d /Users/didi/Desktop/didi-project/dimina-android/jscore-j2v8/src/main/jni/V8/lib/armeabi-v7a/libdimina-v8.so > /Users/didi/Desktop/test.md
didi@zoufenli bin % ./arm-linux-androideabi-c++filt _ZN2v84base2OS14AllocateSharedEjNS1_16MemoryPermissionE
v8::base::OS::AllocateShared(unsigned int, v8::base::OS::MemoryPermission)
didi@zoufenli bin % 
v8::base::OS::AllocateShared(unsigned int, v8::base::OS::MemoryPermission)

如果MAC运行指令过程中提示 '无法打开“arm-linux-androideabi-objdump”,因为无法验证开发者' 的错误,只需要打开设置,选择 ‘安全性与隐私’ ,点击仍然允许,重新运行即可。

图片描述

图片描述

图片描述

注意:objdump也要选择对应位数的程序,判断和使用方式如上addr2line注意事项一致。

感谢您使用伴职平台,如有侵权,请投诉删除!

全部评价

最新
查看更多评论 加载

猜你喜欢

换一批