1. addr2line命令
addr2line -h 可以查看命令使用帮助:
一般命令使用方式:addr2line -e 可执行程序文件 -f -C address
比如下面一个调用栈打印:
01-01 08:00:08.030 2981 2981 D surfaceflinger start: #00 pc 00002875 /system/bin/surfaceflinger (main+636)
01-01 08:00:08.030 2981 2981 D surfaceflinger start: #01 pc 00088161 /system/lib/libc.so (__libc_init+48)
01-01 08:00:08.030 2981 2981 D surfaceflinger start: #02 pc 000025b7 /system/bin/surfaceflinger (_start_main+38)
01-01 08:00:08.030 2981 2981 D surfaceflinger start: #03 pc 00000306 <anonymous:f266e000>
这是在surfaceflinger模块的启动入口:main_surfaceflinger.cpp的main方法中打印的,我们可以用addr2line命令看下第3行和第2行对应的代码行, 第3行的system/bin/surfaceflinger是一个可执行程序, 第2行的system/lib/libc.so是一个so库, Android系统源码编译后生成的带调试符号的可执行程序文件或so文件都在out/target/product/xxx/symbols目录下,为了防止addr2line命令参数过长,我们可以先进入该目录下。
第3行的地址是0x000025b7, 命令执行结果如下:
第2行的地址是0x00088161, 命令执行结果如下:
我们可以分别看下这2个执行结果所对应的代码:
bionic/libc/arch-common/bionic/crtbegin.c
39 __used static void _start_main(void* raw_args) {
40 structors_array_t array;
41 array.preinit_array = &__PREINIT_ARRAY__;
42 array.init_array = &__INIT_ARRAY__;
43 array.fini_array = &__FINI_ARRAY__;
44
45 __libc_init(raw_args, NULL, &main, &array);
46 }
bionic/libc/bionic/libc_init_dynamic.cpp
104 // This function is called from the executable's _start entry point
105 // (see arch-$ARCH/bionic/crtbegin_dynamic.S), which is itself
106 // called by the dynamic linker after it has loaded all shared
107 // libraries the executable depends on.
108 //
109 // Note that the dynamic linker has also run all constructors in the
110 // executable at this point.
111 __noreturn void __libc_init(void* raw_args,
112 void (*onexit)(void) __unused,
113 int (*slingshot)(int, char**, char**),
114 structors_array_t const * const structors) {
115 BIONIC_STOP_UNWIND;
116
117 KernelArgumentBlock args(raw_args);
118
119 // Several Linux ABIs don't pass the onexit pointer, and the ones that
120 // do never use it. Therefore, we ignore it.
121
122 // The executable may have its own destructors listed in its .fini_array
123 // so we need to ensure that these are called when the program exits
124 // normally.
125 if (structors->fini_array) {
126 __cxa_atexit(__libc_fini,structors->fini_array,NULL);
127 }
128
129 exit(slingshot(args.argc, args.argv, args.envp));
130 }
目前还看不太懂。。。但看注释意思是正确的。
2)使用ndk-stack工具
工具是在android ndk开发包中, 可以从下面2个网址下载:
https://developer.android.google.cn/ndk/downloads/
https://developer.android.google.cn/ndk/downloads/older_releases
我是在linux环境使用的, 下载的linux-x86_64版本,然后上传到ubuntu虚拟机某一目录后解压,解压后可以用下面的命令加入到环境变量中, 环境变量要持久化的话需要将这行命令追加到~/.bashrc文件:
export PATH=$PATH:/home/xxuser/android-ndk-r21
ndk-stack命令使用方式很简单,-h可以看到使用帮助:
-sym或--sym 指定符号文件路径, -i或-dump或--dump指定输入文件,也就是调用栈文件,可以直接是tomstones文件,也可以通过管道|将logcat与ndk-stack命令连接使用。
下面是一个使用示例:
crash.txt文件:
01-01 08:00:42.270 4570 4570 F libc : Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 4570 (main), pid 4570 (main)
01-01 08:00:42.315 4605 4605 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-01 08:00:42.315 4605 4605 F DEBUG : Build fingerprint: 'tcl/tcl_m7642/tcl_m7642:9/PPR2.180905.006.A1/xiang10_chen08311137:userdebug/dev-keys'
01-01 08:00:42.315 4605 4605 F DEBUG : Revision: '1234'
01-01 08:00:42.315 4605 4605 F DEBUG : ABI: 'arm'
01-01 08:00:42.315 4605 4605 F DEBUG : pid: 4570, tid: 4570, name: main >>> zygote <<<
01-01 08:00:42.315 4605 4605 F DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
01-01 08:00:42.315 4605 4605 F DEBUG : Abort message: 'jni_internal.cc:616] JNI FatalError called: RegisterNatives failed for 'android/view/SurfaceControl'; aborting...'
01-01 08:00:42.316 4605 4605 F DEBUG : r0 00000000 r1 000011da r2 00000006 r3 00000008
01-01 08:00:42.316 4605 4605 F DEBUG : r4 000011da r5 000011da r6 ffe021bc r7 0000010c
01-01 08:00:42.316 4605 4605 F DEBUG : r8 00000000 r9 f1f10720 r10 ffe023c8 r11 f1e6a65e
01-01 08:00:42.316 4605 4605 F DEBUG : ip ffe02158 sp ffe021a8 lr f48a5f69 pc f489ddba
01-01 08:00:42.348 4605 4605 F DEBUG :
01-01 08:00:42.348 4605 4605 F DEBUG : backtrace:
01-01 08:00:42.348 4605 4605 F DEBUG : #00 pc 0001cdba /system/lib/libc.so (abort+58)
01-01 08:00:42.348 4605 4605 F DEBUG : #01 pc 0034db8f /system/lib/libart.so (art::Runtime::Abort(char const*)+910)
01-01 08:00:42.348 4605 4605 F DEBUG : #02 pc 000071b3 /system/lib/libbase.so (android::base::LogMessage::~LogMessage()+494)
01-01 08:00:42.348 4605 4605 F DEBUG : #03 pc 00265a53 /system/lib/libart.so (art::JNI::FatalError(_JNIEnv*, char const*)+122)
01-01 08:00:42.348 4605 4605 F DEBUG : #04 pc 00001f35 /system/lib/libnativehelper.so (jniRegisterNativeMethods+120)
01-01 08:00:42.348 4605 4605 F DEBUG : #05 pc 000a2645 /system/lib/libandroid_runtime.so (android::register_android_view_SurfaceControl(_JNIEnv*)+20)
01-01 08:00:42.348 4605 4605 F DEBUG : #06 pc 0006efa9 /system/lib/libandroid_runtime.so (android::AndroidRuntime::startReg(_JNIEnv*)+64)
01-01 08:00:42.348 4605 4605 F DEBUG : #07 pc 0006ed0f /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+214)
01-01 08:00:42.348 4605 4605 F DEBUG : #08 pc 00001989 /system/bin/app_process32 (main+728)
01-01 08:00:42.348 4605 4605 F DEBUG : #09 pc 00088161 /system/lib/libc.so (__libc_init+48)
01-01 08:00:42.348 4605 4605 F DEBUG : #10 pc 0000166f /system/bin/app_process32 (_start_main+38)
01-01 08:00:42.348 4605 4605 F DEBUG : #11 pc 00000306 <anonymous:f5ba3000>
ndk-stack执行结果:
user@SZ0000303:~/samba/9652_A200/Android9.0_beta_IP_svn1640_20200514/out/target/product/tcl_m7642/symbols$ ndk-stack -sym ./system/lib -i ~/android-ndk-r21/crash.txt
********** Crash dump: **********
Build fingerprint: 'tcl/tcl_m7642/tcl_m7642:9/PPR2.180905.006.A1/xiang10_chen08311137:userdebug/dev-keys'
Abort message: 'jni_internal.cc:616] JNI FatalError called: RegisterNatives failed for 'android/view/SurfaceControl'; aborting...'
#00 0x0001cdba /system/lib/libc.so (abort+58)
inline_tgkill(int, int, int)
bionic/libc/bionic/abort.cpp:43:3
abort
bionic/libc/bionic/abort.cpp:68:0
#01 0x0034db8f /system/lib/libart.so (art::Runtime::Abort(char const*)+910)
art::Runtime::Abort(char const*)
art/runtime/runtime.cc:588:3
#02 0x000071b3 /system/lib/libbase.so (android::base::LogMessage::~LogMessage()+494)
std::__1::function<void (char const*)>::operator()(char const*) const
external/libcxx/include/functional:1916:12
android::base::LogMessage::~LogMessage()
system/core/base/logging.cpp:458:0
#03 0x00265a53 /system/lib/libart.so (art::JNI::FatalError(_JNIEnv*, char const*)+122)
art::JNI::FatalError(_JNIEnv*, char const*)
art/runtime/jni_internal.cc:616:5
#04 0x00001f35 /system/lib/libnativehelper.so (jniRegisterNativeMethods+120)
_JNIEnv::FatalError(char const*)
libnativehelper/include_jni/jni.h:541:7
jniRegisterNativeMethods
libnativehelper/JNIHelp.cpp:155:0
#05 0x000a2645 /system/lib/libandroid_runtime.so (android::register_android_view_SurfaceControl(_JNIEnv*)+20)
android::RegisterMethodsOrDie(_JNIEnv*, char const*, JNINativeMethod const*, int)
frameworks/base/core/jni/core_jni_helpers.h:70:15
android::register_android_view_SurfaceControl(_JNIEnv*)
frameworks/base/core/jni/android_view_SurfaceControl.cpp:1049:0
#06 0x0006efa9 /system/lib/libandroid_runtime.so (android::AndroidRuntime::startReg(_JNIEnv*)+64)
android::register_jni_procs(android::RegJNIRec const*, unsigned int, _JNIEnv*)
frameworks/base/core/jni/AndroidRuntime.cpp:1337:13
android::AndroidRuntime::startReg(_JNIEnv*)
frameworks/base/core/jni/AndroidRuntime.cpp:1538:0
#07 0x0006ed0f /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)+214)
android::AndroidRuntime::start(char const*, android::Vector<android::String8> const&, bool)
frameworks/base/core/jni/AndroidRuntime.cpp:1103:9
#08 0x00001989 /system/bin/app_process32 (main+728)
#09 0x00088161 /system/lib/libc.so (__libc_init+48)
__libc_init
bionic/libc/bionic/libc_init_dynamic.cpp:129:8
#10 0x0000166f /system/bin/app_process32 (_start_main+38)
#11 0x00000306 <anonymous:f5ba3000>
Crash dump is completed
ndk-stack对输入有要求,调用栈前必须有如下一行*号分隔符才可以:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
ndk-stack工具也可以用于app的native crash分析,用法一样,只是此时的符号文件路径可能是类似 app/build/intermediates/cmake/debug/obj/x86这种的。