Android NDK 中堆栈日志 add2line 的分析实践

Posted 小羊子说

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android NDK 中堆栈日志 add2line 的分析实践相关的知识,希望对你有一定的参考价值。

文章目录

目的

android NDK 中出现的 crash 日志分析定位,使用 addr2line 对库中定位so 动态库崩溃位置,定位到某个函数的具体的代码行。

常用的辅助工具

add2line,objdump,ndkstack 等等。本文主要介绍 NDK 环境中的 add2line如何使用。

Addr2line 工具(它是标准的 GNU Binutils 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具。
一般适用于 debug 版本或带有 symbol 信息的库。

分析步骤

  1. 找到ndk中安装目录下的 addr2line.exe

    示例如下:安装了NDK后的某个目录。

    第一个就是我们需要的命令,不过名字太长了,使用时不太方便,于是我就 copy 一个放到最后,并简短的命令一下为addr2line

  2. 然后在 windows 中添加系统环境下,方便我们直接调用该命令。

  3. 抓取日志并找到关键日志信息。

    Android Studio中的日志不容易抓全,容易一闪而过。可以用bat 命令来抓。

    参考命令如下:

    @echo off

    echo wait device
    adb wait-for-device

    echo loging
    adb logcat -v time >C:\\Users\\DELL\\Desktop\\log\\error.log

    pause

    获取崩溃产生的记录堆栈信息的墓碑文件tombstone。 logcat 错误日志如下:

    12-22 23:44:46.790 I/crash_dump64(12441): obtaining output fd from tombstoned, type: kDebuggerdTombstone
    12-22 23:44:46.790 I//system/bin/tombstoned( 1063): received crash request for pid 12359
    12-22 23:44:46.792 I/crash_dump64(12441): performing dump of process 12359 (target tid = 12359)
    12-22 23:44:46.794 F/DEBUG (12441): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    12-22 23:44:46.794 F/DEBUG (12441): Build fingerprint: ‘PANCAKEXR/PANCAKE_1/PANCAKE_1:10/QKQ1.201018.002/11:userdebug/test-keys’
    12-22 23:44:46.794 F/DEBUG (12441): Revision: ‘0’
    12-22 23:44:46.794 F/DEBUG (12441): ABI: ‘arm64’
    12-22 23:44:46.794 F/DEBUG (12441): Timestamp: 2022-12-22 23:44:46+0800
    12-22 23:44:46.794 F/DEBUG (12441): pid: 12359, tid: 12359, name: om.ssnwt.camera >>> com.ssnwt.camera <<<
    12-22 23:44:46.794 F/DEBUG (12441): uid: 10105
    12-22 23:44:46.794 F/DEBUG (12441): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    12-22 23:44:46.794 F/DEBUG (12441): Cause: null pointer dereference
    12-22 23:44:46.794 F/DEBUG (12441): x0 0000007238370ccb x1 000000000000002f x2 0000000000000001 x3 0000007238370ccb
    12-22 23:44:46.794 F/DEBUG (12441): x4 005b257300000000 x5 0000008000000000 x6 1246040000000000 x7 0000000080044612
    12-22 23:44:46.794 F/DEBUG (12441): x8 0000007ff1cc93d0 x9 0000000000000000 x10 000000000000002f x11 0000000000000038
    12-22 23:44:46.794 F/DEBUG (12441): x12 0000000000000020 x13 0000000000000002 x14 0000000000000008 x15 000047544b6a35cd
    12-22 23:44:46.794 F/DEBUG (12441): x16 000000723837eb60 x17 00000073231c2b2c x18 000000729694e210 x19 0000007ff1cc92c0
    12-22 23:44:46.794 F/DEBUG (12441): x20 0000000000000000 x21 0000007325a0cc00 x22 0000007ff1cc9c10 x23 0000007297e12756
    12-22 23:44:46.794 F/DEBUG (12441): x24 0000000000000008 x25 0000007325c9e020 x26 0000007325a0ccb0 x27 0000000000000002
    12-22 23:44:46.794 F/DEBUG (12441): x28 0000007ff1cc99a0 x29 0000007ff1cc98e0
    12-22 23:44:46.794 F/DEBUG (12441): sp 0000007ff1cc92c0 lr 0000007238353544 pc 0000007238353578
    12-22 23:44:46.873 D/InvisionDisplayManagerService( 1375): applySetPowerState mPowerOn = true
    12-22 23:44:46.874 E/InvisionDisplayManagerService( 1375): Failed to applySetPowerState ivslam = null
    12-22 23:44:46.925 F/DEBUG (12441):
    12-22 23:44:46.925 F/DEBUG (12441): backtrace:
    12-22 23:44:46.926 F/DEBUG (12441): #00 pc 0000000000013578 /data/app/com.ssnwt.camera-hfkg6MwSsTZphlAHWYVnzw==/base.apk!libndk_camera.so (offset 0x651000) (NdkCamera::open(char const*, void ()(char const, unsigned char*, int, int, int, int, long), ANativeWindow**, int)+460) (BuildId: 953887cae84ec067885a1b0c7315d189686e353d)
    12-22 23:44:46.926 F/DEBUG (12441): #01 pc 0000000000011980 /data/app/com.ssnwt.camera-hfkg6MwSsTZphlAHWYVnzw==/base.apk!libndk_camera.so (offset 0x651000) (Java_com_ssnwt_camera_NativeCameraActivity_openMultiCamera+468) (BuildId: 953887cae84ec067885a1b0c7315d189686e353d)
    12-22 23:44:46.926 F/DEBUG (12441): #02 pc 000000000013f350 /apex/com.android.runtime/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #03 pc 0000000000136334 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_stub+548) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #04 pc 0000000000144fec /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+244) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #05 pc 00000000002e204c /apex/com.android.runtime/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+384) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #06 pc 00000000002dd2ac /apex/com.android.runtime/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+892) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #07 pc 00000000005a1538 /apex/com.android.runtime/lib64/libart.so (MterpInvokeDirect+424) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #08 pc 0000000000130914 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_direct+20) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #09 pc 0000000000003648 /data/app/com.ssnwt.camera-hfkg6MwSsTZphlAHWYVnzw==/base.apk (com.ssnwt.camera.NativeCameraActivity.lambda$initCameraView 2 2 2NativeCameraActivity+4)
    12-22 23:44:46.926 F/DEBUG (12441): #10 pc 000000000059f4d0 /apex/com.android.runtime/lib64/libart.so (MterpInvokeVirtual+1352) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #11 pc 0000000000130814 /apex/com.android.runtime/lib64/libart.so (mterp_op_invoke_virtual+20) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #12 pc 0000000000002538 /data/app/com.ssnwt.camera-hfkg6MwSsTZphlAHWYVnzw==/base.apk (com.ssnwt.camera.-$ L a m b d a Lambda LambdaNativeCameraActivityKaTeX parse error: Expected 'EOF', got '#' at position 80: …(12441): #̲13 pc 000000000…MethodAndArgsCaller.run+22)
    12-22 23:44:46.926 F/DEBUG (12441): #41 pc 00000000002b3360 /apex/com.android.runtime/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEbb.llvm.12500273830171183841+240) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #42 pc 0000000000590778 /apex/com.android.runtime/lib64/libart.so (artQuickToInterpreterBridge+1032) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #43 pc 000000000013f468 /apex/com.android.runtime/lib64/libart.so (art_quick_to_interpreter_bridge+88) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #44 pc 00000000009b947c /system/framework/arm64/boot-framework.oat (com.android.internal.os.ZygoteInit.main+2076) (BuildId: 487da90bd032b6e46119f4e28971201c8f9f3457)
    12-22 23:44:46.926 F/DEBUG (12441): #45 pc 00000000001365b8 /apex/com.android.runtime/lib64/libart.so (art_quick_invoke_static_stub+568) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #46 pc 000000000014500c /apex/com.android.runtime/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+276) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #47 pc 00000000004af0e4 /apex/com.android.runtime/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #48 pc 00000000004aecd4 /apex/com.android.runtime/lib64/libart.so (art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #49 pc 00000000003b9df4 /apex/com.android.runtime/lib64/libart.so (art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+624) (BuildId: 8fb5976d4465346647f3e5e5870bdc7a)
    12-22 23:44:46.926 F/DEBUG (12441): #50 pc 00000000000c199c /system/lib64/libandroid_runtime.so (_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, …)+116) (BuildId: a13dc1a4db7d246c6df31ff4e581e460)
    12-22 23:44:46.926 F/DEBUG (12441): #51 pc 00000000000c4878 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::start(char const*, android::Vectorandroid::String8 const&, bool)+776) (BuildId: a13dc1a4db7d246c6df31ff4e581e460)
    12-22 23:44:46.926 F/DEBUG (12441): #52 pc 00000000000035b0 /system/bin/app_process64 (main+1376) (BuildId: 1a86d090ff0d3dd5f5a671601a88a247)
    12-22 23:44:46.926 F/DEBUG (12441): #53 pc 000000000007e898 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: 21847aa9757f000b0461310a9f5e6e51)
    12-22 23:44:46.958 D/SVR_AndroidInterface(12313): Android interface branch: master, version code: 20, version name: 1.0.20-6d81be3

部分信息展示了出错时的运行状态, 当前中断原因是收到SIGSEGV(通常 crash 也都是因为收到这个信号,也有少数是因为 SIGFPE,即除0操作)。
错误码是SEGV_MAPERR,常见的段错误。然后出错地址为 0000000000013578

说明:我们常见的信号有下面这些:

信号码值描述
SIGILL4非法指令,例如损坏的可执行文件或代码区损坏
SIGABRT6通过C函数abort()发送;为assert()使用
SIGBUS7不存在的物理地址,更多为硬件或系统引起
SIGFPE8浮点数运算错误,如除0操作
SIGKILL9迅速完全终止进程;不能被捕获
SIGSEGV11段地址错误,例如空指针、野指针、数组越界等
  1. 最后在堆栈信息中找到 addr 表示栈地址。执行命令,示例如下:
C:\\Users\\DELL>addr2line.exe  -C -f -e E:\\demo\\India\\CameraTest\\app\\build\\intermediates\\cmake\\debug\\obj\\arm64-v8a\\libndk_camera.so 0000000000013578
NdkCamera::open(char const*, void (*)(char const*, unsigned char*, int, int, int, int, long), ANativeWindow**, int)
E:/demo/India/CameraTest/app/src/main/cpp/NdkCamera.cpp:77

于是问题得到了定位,在 NdkCamera.cpp:77 第 77行的代码有问题,引发了 crash。 于时反向定位去进一步分析。

注意点: so 文件需要用 debug 中的 so 文件, 不要用 dubug.apk 中解压后的 so 文件, 不然会出现???.无法识别到。

命令的参数说明:

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

参考

Android Native Crash 分析指南

以上是关于Android NDK 中堆栈日志 add2line 的分析实践的主要内容,如果未能解决你的问题,请参考以下文章

Android NDK 中堆栈日志 add2line 的分析实践

一次Android App NDK崩溃问题的分析及解决

找不到 android NDK 堆栈跟踪

Android NDK- ndk-stack 还原堆栈信息

Android NDK- ndk-stack 还原堆栈信息

android 通过adb 和 ndk调试堆栈