android studio ndk 调试技巧

Android ndk开发,出现内存溢出或别的问题需要调试时,如何快速定位到源码位置,可以使用addr2line 和 ndk-stack 两个工具。在程序
内容主要分为一下几个部分:

1.Library Symbols (共享库的符号)
2.Analyze Tools (可用到的分析工具)
3.CrashLog – Header 
4.CrashLog – Backtrace(For most crashes)
5.CrashLog – Registers
6.CrashLog – Memory
7.CrashLog – Stack
8.Library Base Address (共享库在内存中基地址)

1.Library Symbols (共享库的符号)
ndk提供了一些工具可以供程序员直接获取到出错的文件,函数以及行数。 但是这部分工具都需要没有去符号的共享库(通常是放在main/obj/local/armeabi-v7a)。而main/libs/armeabi-v7a中的共享库是去掉了符号的,所以直接从设备上抓下来的lib是不能够通过工具来找到对应的符号(而且没有去symbol的库比去掉的空间占用会大许多)。所以如果想要分析一份native crash,那么unstripped lib几乎不可缺少,但是即使是strip过的库也同样会包含少量的symbol。

2.Analyze Tools
即常用的辅助工具
1、addr2line ((ANDROID_NDK)\toolchains\arm-linux-androideabi-4.7\prebuilt\windows\bin)  
 #通过backtrace一栏提供的地址查询对应的符号,可以定位到文件,函数,行数.  
Usage: addr2line –aCfe libs
(trace_address)

2、ndk-stack (android-ndk-r8d\ndk-stack)
#相当于执行多次addr2line, 可以直接针对一份crash log使用,会输出所有backtrace里地址对应的symbol
Usage: ndk-stack –sym (libdirectory)dump (crash_log_file)

3、 objdump (android-ndk-r8d\toolchains\arm-linux-androideabi-4.7\prebuilt\windows\bin)
#Dump the object file. 通过汇编代码定位错误的原因,大部分复杂的问题可以通过这种方式得到解决。
Usage: objdump -S (objfile)> (output_file)

贴上一份crash log ,app crash时,打开android device moniter 查看log 找到 如下log

06-15 14:23:38.335: I/DEBUG(631): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
06-15 14:23:38.335: I/DEBUG(631): Build fingerprint: 'Xiaomi/hermes/hermes:5.0.2/LRX22G/V7.3.2.0.LHMCNDD:user/release-keys'
06-15 14:23:38.335: I/DEBUG(631): Revision: '0'
06-15 14:23:38.335: I/DEBUG(631): ABI: 'arm'
06-15 14:23:38.335: I/DEBUG(631): pid: 30939, tid: 612, name: Thread-221  >>> sdk.live.com.xysdk <<<
06-15 14:23:38.335: I/DEBUG(631): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
06-15 14:23:38.355: V/AudioTrackShared(268): mAvailToClient=1024 stepCount=1024 minimum=1536
06-15 14:23:38.359: I/DEBUG(631): Abort message: 'art/runtime/thread.cc:1115] No pending exception expected: android.media.MediaCodec$CodecException: Error 0x80001001'
06-15 14:23:38.359: I/DEBUG(631):     r0 00000000  r1 00000264  r2 00000006  r3 00000000
06-15 14:23:38.359: I/DEBUG(631):     r4 e0574dd8  r5 00000006  r6 00000000  r7 0000010c
06-15 14:23:38.359: I/DEBUG(631):     r8 00000000  r9 ab3150b0  sl ab7909f8  fp 00000001
06-15 14:23:38.359: I/DEBUG(631):     ip 00000264  sp e0574878  lr f71fa4df  pc f7220094  cpsr 60070010
06-15 14:23:38.359: I/DEBUG(631): backtrace:
06-15 14:23:38.359: I/DEBUG(631):     #00 pc 0003c094  /system/lib/libc.so (tgkill+12)
06-15 14:23:38.359: I/DEBUG(631):     #01 pc 000164db  /system/lib/libc.so (pthread_kill+66)
06-15 14:23:38.359: I/DEBUG(631):     #02 pc 000170a7  /system/lib/libc.so (raise+10)
06-15 14:23:38.359: I/DEBUG(631):     #03 pc 00013997  /system/lib/libc.so (__libc_android_abort+34)
06-15 14:23:38.360: I/DEBUG(631):     #04 pc 000120c8  /system/lib/libc.so (abort+4)
06-15 14:23:38.360: I/DEBUG(631):     #05 pc 002179a9  /system/lib/libart.so (art::Runtime::Abort()+132)
06-15 14:23:38.360: I/DEBUG(631):     #06 pc 000a6e0d  /system/lib/libart.so (art::LogMessage::~LogMessage()+1292)
06-15 14:23:38.360: I/DEBUG(631):     #07 pc 0022883f  /system/lib/libart.so (art::Thread::AssertNoPendingException() const+350)
06-15 14:23:38.360: I/DEBUG(631):     #08 pc 000d3093  /system/lib/libart.so (art::ClassLinker::FindClass(art::Thread*, char const*, art::Handle)+30)
06-15 14:23:38.360: I/DEBUG(631):     #09 pc 000d502d  /system/lib/libart.so (art::ClassLinker::ResolveType(art::DexFile const&, unsigned short, art::Handle, art::Handle)+136)
06-15 14:23:38.360: I/DEBUG(631):     #10 pc 00070ba5  /system/lib/libart.so (_ZN3art11ClassLinker11ResolveTypeEtPNS_6mirror9ArtMethodE.part.112+104)
06-15 14:23:38.360: I/DEBUG(631):     #11 pc 0015f561  /system/lib/libart.so (art::MethodHelper::GetClassFromTypeIdx(unsigned short, bool)+104)
06-15 14:23:38.360: I/DEBUG(631):     #12 pc 0007277f  /system/lib/libart.so (art::CheckMethodArguments(art::mirror::ArtMethod*, unsigned int*)+190)
06-15 14:23:38.360: I/DEBUG(631):     #13 pc 00214d75  /system/lib/libart.so (art::InvokeVirtualOrInterfaceWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408)
06-15 14:23:38.360: I/DEBUG(631):     #14 pc 0019f8e7  /system/lib/libart.so (art::JNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+274)
06-15 14:23:38.360: I/DEBUG(631):     #15 pc 000baedb  /system/lib/libart.so (art::CheckJNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+90)
06-15 14:23:38.360: I/DEBUG(631):     #16 pc 000cd17c  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (_JNIEnv::CallVoidMethod(_jobject*, _jmethodID*, ...)+52)
**06-15 14:23:38.360: I/DEBUG(631):     #17 pc 000d1a78**  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (JMediacodecDecoder::decoder(unsigned char*, int, unsigned int)+128)
06-15 14:23:38.360: I/DEBUG(631):     #18 pc 000d0a38  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (MediaStreamReceiver::VideoDecoderFunc(void*)+124)
06-15 14:23:38.360: I/DEBUG(631):     #19 pc 00015c5b  /system/lib/libc.so (__pthread_start(void*)+30)
06-15 14:23:38.360: I/DEBUG(631):     #20 pc 00013ceb  /system/lib/libc.so (__start_thread+6)

3.Crash Log - Header
信息头,包含当前系统版本有关的信息,如果是做平台级的开发,这将有助于定位当前的系统的开发版本。

I/DEBUG(631): Build fingerprint: 'Xiaomi/hermes/hermes:5.0.2/LRX22G/V7.3.2.0.LHMCNDD:user/release-keys'
06-15 14:23:38.335: I/DEBUG(631): Revision: '0'
06-15 14:23:38.335: I/DEBUG(631): ABI: 'arm'
06-15 14:23:38.335: I/DEBUG(631): pid: 30939, tid: 612, name: Thread-221  >>> sdk.live.com.xysdk <<<

4.CrashLog – Backtrace(For most crashes)
看上面log

06-15 14:23:38.359: I/DEBUG(631): backtrace:
06-15 14:23:38.359: I/DEBUG(631):     #00 pc 0003c094  /system/lib/libc.so (tgkill+12)
06-15 14:23:38.359: I/DEBUG(631):     #01 pc 000164db  /system/lib/libc.so (pthread_kill+66)
06-15 14:23:38.359: I/DEBUG(631):     #02 pc 000170a7  /system/lib/libc.so (raise+10)
06-15 14:23:38.359: I/DEBUG(631):     #03 pc 00013997  /system/lib/libc.so (__libc_android_abort+34)

从上面这份backtrace可以看到包含一个pc地址和后面的symbol。部分错误可以通过只看这里的symbol发现问题所在。而如果想要更准确的定位,则需要借助ndk工具。 查看 pc d1a78

$  ~/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-addr2line -aCfe obj/local/armeabi-v7a/libxiaoyao_live.so d1a78
0x000d1a78
如下是输出结果:定位到源码的位置
JMediacodecDecoder::decoder(unsigned char*, int, unsigned int)
/Users/apple/ycWorkSpace/workspace/kakaPushTemp/XYsdk/app/src/main/jni/src/android/mediacodec/JMediacodecDecoder.cpp:191

ndk-stack:

~/Library/Android/sdk/ndk-bundle/ndk-stack -sym obj/local/armeabi-v7a/libxiaoyao_live.so -dump ~/log.txt 

其分析结果如下:

********** Crash dump: **********
Build fingerprint: 'Xiaomi/hermes/hermes:5.0.2/LRX22G/V7.3.2.0.LHMCNDD:user/release-keys'
pid: 30939, tid: 612, name: Thread-221  >>> sdk.live.com.xysdk <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Stack frame #00 pc 0003c094  /system/lib/libc.so (tgkill+12)
Stack frame #01 pc 000164db  /system/lib/libc.so (pthread_kill+66)
Stack frame #02 pc 000170a7  /system/lib/libc.so (raise+10)
Stack frame #03 pc 00013997  /system/lib/libc.so (__libc_android_abort+34)
Stack frame #04 pc 000120c8  /system/lib/libc.so (abort+4)
Stack frame #05 pc 002179a9  /system/lib/libart.so (art::Runtime::Abort()+132)
Stack frame #06 pc 000a6e0d  /system/lib/libart.so (art::LogMessage::~LogMessage()+1292)
Stack frame #07 pc 0022883f  /system/lib/libart.so (art::Thread::AssertNoPendingException() const+350)
Stack frame #08 pc 000d3093  /system/lib/libart.so (art::ClassLinker::FindClass(art::Thread*, char const*, art::Handle)+30)
Stack frame #09 pc 000d502d  /system/lib/libart.so (art::ClassLinker::ResolveType(art::DexFile const&, unsigned short, art::Handle, art::Handle)+136)
Stack frame #10 pc 00070ba5  /system/lib/libart.so (_ZN3art11ClassLinker11ResolveTypeEtPNS_6mirror9ArtMethodE.part.112+104)
Stack frame #11 pc 0015f561  /system/lib/libart.so (art::MethodHelper::GetClassFromTypeIdx(unsigned short, bool)+104)
Stack frame #12 pc 0007277f  /system/lib/libart.so (art::CheckMethodArguments(art::mirror::ArtMethod*, unsigned int*)+190)
Stack frame #13 pc 00214d75  /system/lib/libart.so (art::InvokeVirtualOrInterfaceWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, std::__va_list)+408)
Stack frame #14 pc 0019f8e7  /system/lib/libart.so (art::JNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+274)
Stack frame #15 pc 000baedb  /system/lib/libart.so (art::CheckJNI::CallVoidMethodV(_JNIEnv*, _jobject*, _jmethodID*, std::__va_list)+90)
Stack frame #16 pc 000cd17c  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (_JNIEnv::CallVoidMethod(_jobject*, _jmethodID*, ...)+52): Routine _JNIEnv::CallVoidMethod(_jobject*, _jmethodID*, ...) at /Users/apple/Library/Android/sdk/ndk-bundle/platforms/android-17/arch-arm/usr/include/jni.h:650
Stack frame #17 pc 000d1a78  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (JMediacodecDecoder::decoder(unsigned char*, int, unsigned int)+128): Routine JMediacodecDecoder::decoder(unsigned char*, int, unsigned int) at /Users/apple/ycWorkSpace/workspace/kakaPushTemp/XYsdk/app/src/main/jni/src/android/mediacodec/JMediacodecDecoder.cpp:191
Stack frame #18 pc 000d0a38  /data/app/sdk.live.com.xysdk-1/lib/arm/libxiaoyao_live.so (MediaStreamReceiver::VideoDecoderFunc(void*)+124): Routine MediaStreamReceiver::VideoDecoderFunc(void*) at /Users/apple/ycWorkSpace/workspace/kakaPushTemp/XYsdk/app/src/main/jni/src/android/look/networkStreamReceiver/MediaStreamReceiver.cpp:230
Stack frame #19 pc 00015c5b  /system/lib/libc.so (__pthread_start(void*)+30)
Stack frame #20 pc 00013ceb  /system/lib/libc.so (__start_thread+6)

5.CrashLog – Registers
寄存器信息,可以通过这部分信息基本确定系统为什么会错。

06-15 14:23:38.359: I/DEBUG(631):     r0 00000000  r1 00000264  r2 00000006  r3 00000000
06-15 14:23:38.359: I/DEBUG(631):     r4 e0574dd8  r5 00000006  r6 00000000  r7 0000010c
06-15 14:23:38.359: I/DEBUG(631):     r8 00000000  r9 ab3150b0  sl ab7909f8  fp 00000001
06-15 14:23:38.359: I/DEBUG(631):     ip 00000264  sp e0574878  lr f71fa4df  pc f7220094  cpsr 60070010

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

 ~/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-objdump -S obj/local/armeabi-v7a/objs/xiaoyao_live/android/mediacodec/JMediacodecDecoder.o > ~/demo

反汇编,把.o 文件反编译为.s 文件
基本上配合log 及 addr2line 工具就可以定位到问题位置。

你可能感兴趣的:(android,NDK)