美文网首页
ndk-stack使用及符号表还原

ndk-stack使用及符号表还原

作者: 神迹12 | 来源:发表于2021-10-11 09:13 被阅读0次

    在android开发中,对于native产生的异常,很可能会产生闪退。对于ndk和native(c、c++)开发中,指针和内存管理是最重要也是最容易出问题的地方,稍有不慎就会遇到诸如内存地址访问错误、野针对、内存泄露、堆栈溢出、初始化错误、类型转换错误、数字除0等常见的问题。

    Android NDK安装包中提供了三个调试工具:addr2line、objdump和ndk-stack可用于native异常的分析。add2line、objdump的使用可以参考https://www.jianshu.com/p/dd0b0a09aa78。本文着重分析ndk-stack。

    一、ndk-stack

    1、人为制造native异常

    image.png

    此处使用了一个指针,但并未给指针分配空间。

    运行后app会闪退,产生如下报错:

    
    2021-09-21 22:10:06.990 11638-11638/aom.example.dj.appgl E/dj------: dj---------- nativeInit
        
        --------- beginning of crash
    2021-09-21 22:10:06.990 11638-11638/aom.example.dj.appgl A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 11638 (xample.dj.appgl), pid 11638 (xample.dj.appgl)
    
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: Process name is aom.example.dj.appgl, not key_process
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: Build fingerprint: 'OPPO/PBEM00/PBEM00:10/QKQ1.190918.001/2021060001:user/release-keys'
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: Revision: '0'
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: ABI: 'arm'
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: Timestamp: 2021-09-21 22:10:07+0800
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: pid: 11638, tid: 11638, name: xample.dj.appgl  >>> aom.example.dj.appgl <<<
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: uid: 11069
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG: Cause: null pointer dereference
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG:     r0  00000022  r1  00000000  r2  00000001  r3  00000003
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG:     r4  010d9528  r5  010d9528  r6  00ebd4c7  r7  ff8ffa28
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG:     r8  00000000  r9  ebdf1e00  r10 ff8ffa50  r11 ebdf1e00
    2021-09-21 22:10:07.168 11786-11786/? A/DEBUG:     ip  ff8ff518  sp  ff8ff9f8  lr  beb167a1  pc  beb167b6
    2021-09-21 22:10:07.235 549-549/? E/SELinux: avc:  denied  { find } for interface=vendor.qti.hardware.servicetracker::IServicetracker sid=u:r:system_server:s0 pid=2325 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_hwservice:s0 tclass=hwservice_manager permissive=0
    

    backtrace信息如下:

    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG: backtrace:
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #00 pc 0000c7b6  /data/app/aom.example.dj.appgl-ds9TsdpSuM_eCCnaRssZOw==/lib/arm/libnative-lib.so (nativeStringInit+50) (BuildId: 5d55b80f27765026e62fbfb60bdfe78ae321f480)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #01 pc 000dc519  /apex/com.android.runtime/lib/libart.so (art_quick_generic_jni_trampoline+40) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #02 pc 000d7bc5  /apex/com.android.runtime/lib/libart.so (art_quick_invoke_stub_internal+68) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #03 pc 0043d75f  /apex/com.android.runtime/lib/libart.so (art_quick_invoke_static_stub+246) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #04 pc 000dff95  /apex/com.android.runtime/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+188) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #05 pc 002146f3  /apex/com.android.runtime/lib/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+270) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #06 pc 002108e7  /apex/com.android.runtime/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+738) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #07 pc 00434f4f  /apex/com.android.runtime/lib/libart.so (MterpInvokeStatic+326) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #08 pc 000d2994  /apex/com.android.runtime/lib/libart.so (mterp_op_invoke_static+20) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #09 pc 0002ffee  [anon:dalvik-classes2.dex extracted in memory from /data/app/aom.example.dj.appgl-ds9TsdpSuM_eCCnaRssZOw==/base.apk!classes2.dex] (com.example.dj.appgl.MainActivity.onClick+482)
    2021-09-21 22:10:07.600 11786-11786/? A/DEBUG:       #10 pc 0043413d  /apex/com.android.runtime/lib/libart.so (MterpInvokeInterface+1536) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    ···
    

    可以看到出错位置在/libnative-lib.so (nativeStringInit+50)。但是具体信息不详,只知道出错的汇编指令地址在:#00 pc 0000c7b6

    2、使用ndk-stack恢复异常堆栈

    adb logcat | /Users/daijun/Library/Android/sdk/ndk/20.0.5594570/ndk-stack -sym /Users/daijun/Documents/dj_code/jb_imp/opengl/github/DOpenglTest/nativelibrary/build/intermediates/cmake/debug/obj/armeabi-v7a/  
    

    执行后得到的结果如下:

    ********** Crash dump: **********
    Build fingerprint: 'OPPO/PBEM00/PBEM00:10/QKQ1.190918.001/2021060001:user/release-keys'
    #00 0x0000c7b6 /data/app/aom.example.dj.appgl-ds9TsdpSuM_eCCnaRssZOw==/lib/arm/libnative-lib.so (nativeStringInit+50) (BuildId: 5d55b80f27765026e62fbfb60bdfe78ae321f480)
                                                                                                     nativeStringInit
                                                                                                     /Users/daijun/Documents/dj_code/jb_imp/opengl/github/DOpenglTest/nativelibrary/src/main/cpp/native-lib.cpp:36:8
    #01 0x000dc519 /apex/com.android.runtime/lib/libart.so (art_quick_generic_jni_trampoline+40) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    #02 0x000d7bc5 /apex/com.android.runtime/lib/libart.so (art_quick_invoke_stub_internal+68) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    #03 0x0043d75f /apex/com.android.runtime/lib/libart.so (art_quick_invoke_static_stub+246) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    #04 0x000dff95 /apex/com.android.runtime/lib/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+188) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    #05 0x002146f3 /apex/com.android.runtime/lib/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+270) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    #06 0x002108e7 /apex/com.android.runtime/lib/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+738) (BuildId: 1bc1b47bcd2822802d756e5ab4666019)
    

    可以看出出错的位置在
    native-lib.cpp:36:8
    即native-lib.cpp的第36行。

    二、native崩溃捕获机制

    native的异常捕获,开源方案有 coffeecatchbreakpad。普通项目可以继承bugly。
    native异常发生时,CPU通过异常中断的方式,触发异常处理流程。linux把这些中断处理,统一为信号量,可以注册信号量向量进行处理。信号(全称:软中断信号)机制是进程之间相互传递消息的一种方法。

    1、信号机制

    image.png

    函数运行在用户态,当遇到系统调用、中断或是异常的情况时,程序会进入内核态。信号涉及到了这两种状态之间的转换。信号处理机制示意图如上所示。

    信号的处理:信号处理函数是运行在用户态的,调用处理函数前,内核会将当前内核栈的内容备份拷贝到用户栈上。接下来进程返回到用户态中,执行相应的信号处理函数。信号处理函数执行完成后,还需要返回内核态,检查是否还有其它信号未处理。如果所有信号都处理完成,就会将内核栈恢复。

    2、常见信号量类型

    image.png

    3、native crash的捕获

    主要通过注册信号处理函数。通过sigaction()捕获native异常。

    #include <signal.h> 
    int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
    

    详细处理参见文章:


    image.png

    三、集成bugly后的native符号表分析

    未上传so符号表时的出错堆栈如下:


    image.png

    此时由于并未上传符号表,所以并不能还原。

    符号表:
    符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:
    <起始地址> <结束地址> <函数> [<文件名:行号>]

    bugly最新版3.3.4符号表上传工具,需要java 8来执行。所以执行前,确认电脑里已经安装了jdk 1.8,否则会执行错误。

    查看当前Mac已安装jdk目录
    /usr/libexec/java_home -V

    image.png

    执行命令如下:

    java -jar buglyqq-upload-symbol.jar -appid e4c59fc9cf 
                                        -appkey 99bb0e4e-910d-4247-85e3-ea026cef03a2
                                        -bundleid aom.example.dj.appgl
                                        -version 1.0
                                        -platform Android
                                        -inputSymbol /Users/daijun/Documents/dj_code/jb_imp/opengl/github/DOpenglTest/nativelibrary/build/intermediates/cmake/debug/obj/armeabi-v7a/
    

    命令执行成功后,对应的native crash的符号表tab页下,会显示so符号表文件已上传。


    image.png

    出错堆栈的解析结果,跟本地使用ndk-stack的还原结果一致。


    image.png

    四、flutter 符号表获取

    Flutter的引擎部分全部使用C/C++实现,为了减少包大小,所有的SO库在发布时都会去除符号表信息。和其他的JNI崩溃堆栈一样,我们上报的堆栈信息中只能看到内存地址偏移量等信息。

    通过上面的分析知道可以使用ndk-stack来进行还原,前提是得能下载到带有符号表的SO文件。查看自己使用的flutter版本,可以在官方flutter_infra页面直接下载。

    4.1 查看flutter版本
    在终端中执行

    flutter --version
    
    Flutter 1.20.2 • channel stable • https://github.com/flutter/flutter.git
    Framework • revision bbfbf1770c (1 year, 2 months ago) • 2020-08-13 08:33:09
    -0700
    Engine • revision 9d5b21729f
    Tools • Dart 2.9.1
    

    4.2 查找engine版本
    1、在本地的flutter安装目录中,在/bin/internal/engine.version中查看当前版本对应的engine版本。如我的版本是9d5b21729ff53dbf8eadd8bc97e0e30d77abec95。
    2、在flutter仓库中搜索对应的版本,找到对应的文件夹

    image.png

    参考
    https://blog.csdn.net/lqf19921217/article/details/109201295

    image.png
    https://tech.meituan.com/2018/08/09/waimai-flutter-practice.html
    https://github.com/flutter/flutter/wiki/Crashes
    https://blog.csdn.net/qq_30379689/article/details/90813052
    https://console.cloud.google.com/storage/browser/flutter_infra/flutter/

    相关文章

      网友评论

          本文标题:ndk-stack使用及符号表还原

          本文链接:https://www.haomeiwen.com/subject/mefloltx.html