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 函式之前,所以增加非空判斷
其它: