1. 程式人生 > >so 動態庫崩潰問題定位(addr2line與objdump)

so 動態庫崩潰問題定位(addr2line與objdump)

一、需求分析

so 的崩潰並不像 Java 程式碼那麼好定位,我們通常看到的就只是 so 中的一大段崩潰的堆疊資訊。那麼我們怎麼通過這個堆疊資訊來定位我們的問題呢?

二、addr2line

1. 介紹

Addr2line 工具(它是標準的 GNU Binutils 中的一部分)是一個可以將指令的地址和可執行映像轉換成檔名、函式名和原始碼行數的工具。
一般適用於 debug 版本或帶有 symbol 資訊的庫。

2. 工具位置

我們下載的 NDK 裡面已經預設有了這個工具,對應的路徑如下,其中 .. 表示你的 NDK 安裝的路徑(每個人的可能都不一樣)

Windows:
32位:..\ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin\arm-linux-androideabi-addr2line.exe
64位:..\ndk-bundle\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\aarch64-linux-android-addr2line.exe
Linux:


32位:../android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-addr2line
64位:../android-ndk-r16b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-addr2line

當然我們也可以把這個路徑配置到環境變數中去。

3. 指令釋義

4. 使用示例

5. 實際應用

例如出現瞭如下崩潰:

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4d42d8b4
    r0 ead025fc  r1 ead025f0  r2 ead025fd  r3 4d42d8a4
    r4 efba899c  r5 ead025fc  r6 ead0263c  r7 efba8984
    r8 ead00000  r9 ead00000  sl ead025fc  fp 00000001
    ip 00000000  sp ee5ff348  lr 0007ffff  pc efb5e15e  cpsr 800f0030

backtrace:
    #00 pc 0005915e  /system/lib/libc.so (arena_dalloc_bin_locked_impl+345)
    #01 pc 00058ffd  /system/lib/libc.so (je_arena_dalloc_bin_junked_locked+12)
    #02 pc 0007ae27  /system/lib/libc.so (je_tcache_bin_flush_small+366)
    #03 pc 0007ac5b  /system/lib/libc.so (je_tcache_event_hard+58)
    #04 pc 0006a505  /system/lib/libc.so (je_malloc+636)
    #05 pc 00339c7f  /vendor/lib/libstfaceunlock.so
    #06 pc 00282064  /vendor/lib/libstfaceunlock.so
    #07 pc 001fc094  /vendor/lib/libstfaceunlock.so
    #08 pc 002056b0  /vendor/lib/libstfaceunlock.so
    #09 pc 002809d8  /vendor/lib/libstfaceunlock.so
    #10 pc 00103f58  /vendor/lib/libstfaceunlock.so
    #11 pc 00105398  /vendor/lib/libstfaceunlock.so
    #12 pc 001062c4  /vendor/lib/libstfaceunlock.so
    #13 pc 000a4f14  /vendor/lib/libstfaceunlock.so
    #14 pc 0007957c  /vendor/lib/libstfaceunlock.so
    #15 pc 00023d2c  /vendor/lib/libstfaceunlock.so (cv_face_create_tracker+424)

我們就可以把每個段地址翻譯成具體的程式碼:

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x4d42d8b4
    r0 ead025fc  r1 ead025f0  r2 ead025fd  r3 4d42d8a4
    r4 efba899c  r5 ead025fc  r6 ead0263c  r7 efba8984
    r8 ead00000  r9 ead00000  sl ead025fc  fp 00000001
    ip 00000000  sp ee5ff348  lr 0007ffff  pc efb5e15e  cpsr 800f0030

backtrace:
    #00 pc 0005915e  /system/lib/libc.so (arena_dalloc_bin_locked_impl+345)
    #01 pc 00058ffd  /system/lib/libc.so (je_arena_dalloc_bin_junked_locked+12)
    #02 pc 0007ae27  /system/lib/libc.so (je_tcache_bin_flush_small+366)
    #03 pc 0007ac5b  /system/lib/libc.so (je_tcache_event_hard+58)
    #04 pc 0006a505  /system/lib/libc.so (je_malloc+636)
    #05 pc 00339c7f  /vendor/lib/libstfaceunlock.so --> /usr/local/google/buildbot/src/android/master-ndk/toolchain/gcc/gcc-4.9/libstdc++-v3/libsupc++/new_op.cc:56
    #06 pc 00282064  /vendor/lib/libstfaceunlock.so --> google::protobuf::internal::StringTypeHandlerBase::New()
    #07 pc 001fc094  /vendor/lib/libstfaceunlock.so --> caffe::LayerParameter::MergePartialFromCodedStream(google::protobuf::io::CodedInputStream*)
    #08 pc 002056b0  /vendor/lib/libstfaceunlock.so --> caffe::NetParameter::MergePartialFromCodedStream(google::protobuf::io::CodedInputStream*)
    #09 pc 002809d8  /vendor/lib/libstfaceunlock.so --> google::protobuf::MessageLite::ParseFromCodedStream(google::protobuf::io::CodedInputStream*)
    #10 pc 00103f58  /vendor/lib/libstfaceunlock.so --> ReadProtoFromBinaryResource(protector::ModelResource&, google::protobuf::MessageLite*)
    #11 pc 00105398  /vendor/lib/libstfaceunlock.so --> protector::CaffeModel::Init(protector::TarModelResource&, std::string const&, protector::NetConfig, bool
    #12 pc 001062c4  /vendor/lib/libstfaceunlock.so --> protector::ModelLoader::LoadByName(std::string const&, bool) const
    #13 pc 000a4f14  /vendor/lib/libstfaceunlock.so --> stsdk::detection::DetectorHunter::Init(protector::ModelLoader&)
    #14 pc 0007957c  /vendor/lib/libstfaceunlock.so --> __appProtect_cv_common_detection_hunter_create_start
    #15 pc 00023d2c  /vendor/lib/libstfaceunlock.so (cv_face_create_tracker+424)

三、objdump

1. 介紹

objdump 是 gcc 工具,用來檢視編譯後目標檔案的組成。

2. 工具位置

我們下載的 NDK 裡面同樣預設有了這個工具,對應的路徑如下,其中 .. 表示你的 NDK 安裝的路徑(每個人的可能都不一樣)

Windows:
32位:..\ndk-bundle\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin\arm-linux-androideabi-objdump.exe
64位:..\ndk-bundle\toolchains\aarch64-linux-android-4.9\prebuilt\windows-x86_64\bin\aarch64-linux-android-objdump.exe
Linux:
32位:../android-ndk-r16b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-objdump
64位:../android-ndk-r16b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-objdump

當然我們也可以把這個路徑配置到環境變數中去。

3. 指令釋義

4. 使用示例

通常我們會把輸出重定向到一個文字檔案中去,使用語法如下:

arm-linux-androideabi-objdump -d 庫檔案 > 輸出檔案

開啟檔案,檢視彙編執行順序,找到 23098 地址段

通過 backtrace 地址裡的彙編段和偏移量在上面的彙編順序裡找到對應彙編命令

這裡的方法名不容易看懂,可以使用 c++filt 命令找到實際的程式碼段可以更方面定位程式碼

然後找到具體的程式碼

判斷是在 gen_statistics 函式之前,所以增加非空判斷

其它: