欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android解讀Native崩潰棧信息的方法詳解

 更新時間:2023年11月19日 08:40:47   作者:Tans5  
大部分的 Android 開發(fā)者使用的主要語言都是 Kotlin / Java,他們的崩潰棧信息非常清晰,也非常好定位到問題,本文小編給大家介紹了Android如何解讀Native崩潰棧信息,需要的朋友可以參考下

大部分的 Android 開發(fā)者使用的主要語言都是 Kotlin / Java,他們的崩潰棧信息非常清晰,也非常好定位到問題,如果是線上的崩潰通常還會對類名進行混淆,還需要一個混淆文件對堆棧翻譯一下就能夠得到源碼中的類名。
但是很多人對 C/C++ 的崩潰棧就無能為力了,今天這篇文章就來扒一扒 Native 的崩潰棧信息。

Native 崩潰棧信息

我們經(jīng)常能夠看到有類似下面的 Native 崩潰信息:

Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 17356 (tMediaPlayerDec), pid 15253 (ediaplayer.demo)
pid: 15253, tid: 17356, name: tMediaPlayerDec  >>> com.tans.tmediaplayer.demo <<<

#01 pc 000000000001bd2c  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#02 pc 000000000001ba98  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#03 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#04 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#05 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#06 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#07 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so
#08 pc 000000000001cf08  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (Java_com_tans_tmediaplayer_tMediaPlayer_decodeNative+52) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#11 pc 000000000000952c  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/base.apk!classes5.dex] (com.tans.tmediaplayer.tMediaPlayer.decodeNativeInternal$tmediaplayer_debug+0)
#13 pc 00000000000057f6  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/base.apk!classes5.dex] (com.tans.tmediaplayer.tMediaPlayerDecoder$decoderHandler$2$1.dispatchMessage+850)

Native 中的崩潰是通過系統(tǒng)信號來實現(xiàn)的,比如我們上面的異常信號就是 SIGABRT,Android 的進程在啟動時就會添加一個 SignalCatcher,來捕獲信號,不同的信號有不同的處理方式,SIGABRT 就是會直接退出程序,也就是我們常說的崩潰,Android 中還有一個非常重要的信號就是 SIGQUIT,在 Android 中表示發(fā)生了 ANR,默認的處理邏輯是 dump 棧信息和內(nèi)存 GC 相關(guān)的信息到本地文件。
好了這里說得有點遠了,回到上面的問題,我們剛開始看到上面的數(shù)據(jù)可能有點懵逼,pc 后面有一串 16 進制的數(shù)字表示程序計數(shù)器的位置 (簡單理解就是執(zhí)行的機器碼對應(yīng)的位置),后面的文件表示崩潰的棧中相關(guān)的 .so 動態(tài)鏈接庫。但是你又要說了,這一串地址誰能夠看出什么問題?????? 你先不要急,通常線上的用戶崩潰看到的棧是這樣的,因為 AndroidRelease 包默認會抹掉一部分叫做符號表的東西,如果你看過我上面的文章你就會豁然開朗,這個符號表描述了指令地址和對應(yīng)方法或者變量的映射(方法名,全局變量名都是符號),通常我們用的別人的 .so 包也會抹掉符號表(這可能就是不想讓你看,起到了一個混淆作用),少了一個表在線上的運行中性能會更加好(至少這部分內(nèi)存不用消耗了)。

通常我們自己打的 Debug 包就沒有抹掉符號表,如果是有符號表信息,我們看到的上面異常信息通常是下面這樣的:

Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 17356 (tMediaPlayerDec), pid 15253 (ediaplayer.demo)
pid: 15253, tid: 17356, name: tMediaPlayerDec  >>> com.tans.tmediaplayer.demo <<<

#01 pc 000000000001bd2c  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::parseDecodeAudioFrameToBuffer(tMediaDecodeBuffer*)+464) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#02 pc 000000000001ba98  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+1076) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#03 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+532) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#04 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+532) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#05 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+532) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#06 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+532) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#07 pc 000000000001b878  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (tMediaPlayerContext::decode(tMediaDecodeBuffer*)+532) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#08 pc 000000000001cf08  /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/lib/arm64/libtmediaplayer.so (Java_com_tans_tmediaplayer_tMediaPlayer_decodeNative+52) (BuildId: 58ab2061a06db613d9c3ca66a214872ad88636f7)
#11 pc 000000000000952c  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/base.apk!classes5.dex] (com.tans.tmediaplayer.tMediaPlayer.decodeNativeInternal$tmediaplayer_debug+0)
#13 pc 00000000000057f6  [anon:dalvik-classes5.dex extracted in memory from /data/app/~~fIT1aTQ88Pxdg1-7Ax4AXQ==/com.tans.tmediaplayer.demo-8WVpgXB0od_2YBBfM4FnZQ==/base.apk!classes5.dex] (com.tans.tmediaplayer.tMediaPlayerDecoder$decoderHandler$2$1.dispatchMessage+850)

你看這里就有調(diào)用所對應(yīng)的方法了,因為我這里的 decode() 方法是遞歸調(diào)用的,所以你看到上面的棧中有多個,方法后面還有一個 +532 表示該地址離方法開始的地址的偏移量,如果你的 .so 文件里面還有 debug 信息,這個 +532 能夠定位到某一行 C \ C++ 源碼,其實就是每條指令都映射了某一行代碼。

Android 的打包過程中如果你希望 Release 包也不要移除符號表信息,可以通過在 build.gradle 中添加以下配置來避免符號表被移除:

// ...
packagingOptions {
    doNotStrip "*/arm64-v8a/*.so"
    doNotStrip "*/armeabi-v7a/*.so"
    doNotStrip "*/x86/*.so"
    doNotStrip "*/x86_64/*.so"
}
// ...

如果符號表被移除了那我們不是永遠都不知道崩潰的方法是什么了?當然不是,被移除的符號會被保存到另外的文件中,線上的崩潰可以通過這個文件再次翻譯成對應(yīng)的方法。以下就是符號文件對應(yīng)的路徑:

它解壓后如下:

他們也是 ELF 格式的文件,每個都對應(yīng)了一個 .so 庫。

那么我們怎么判斷一個 .so 文件是不是有符號表呢?可以通過 file 命令查看:

libtmediaplayer.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=58ab2061a06db613d9c3ca66a214872ad88636f7, with debug_info, not stripped

not stripped 就表示有符號表。

libtmediaplayer.so: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=58ab2061a06db613d9c3ca66a214872ad88636f7, stripped

stripped 就表示沒有符號表。

Tips: 如果你上架的應(yīng)用沒有這個符號表,Google Play 還會提醒你上傳,Google Play 是可以幫你捕獲 Native 崩潰的,它需要符號表解析這些地址信息。

符號表

我們了解 ELF 文件就知道,我們上面說的符號表就是本地符號表對應(yīng)的就是 .symtab Section,這個表對我們的程序運行沒有任何的影響,我們調(diào)用本地方法都是通過地址直接跳轉(zhuǎn),而不需要本地符號表。
還有一個符號表是 .dynsym,它是動態(tài)鏈接的符號表,這個表是供 ld.so 使用的,因為這里面的符號都是暴露給其他的程序調(diào)用的,ld.so 需要通過這個表去查詢暴露給其他程序的符號的地址,所以不能刪除。

我們可以通過 readelf -s [elf file] 讀取符號表:

以下是有符號表的數(shù)據(jù):

Symbol table '.dynsym' contains 447 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   // ...
   441: 000000000001c494    40 FUNC    GLOBAL DEFAULT   15 Java_com_tans_tmediaplayer_tMediaPlayer_durationNative
   442: 000000000001cac4   136 FUNC    GLOBAL DEFAULT   15 Java_com_tans_tmediaplayer_tMediaPlayer_getVideoFrameUBytesNative
   // ...

Symbol table '.symtab' contains 2470 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
  // ...
  2067: 000000000001ae20  2116 FUNC    GLOBAL DEFAULT   15 _ZN19tMediaPlayerContext29parseDecodeVideoFrameToBufferEP18tMediaDecodeBuffer
  // ...
  2086: 000000000001bef4    36 FUNC    WEAK   DEFAULT   15 _ZN18tMediaDecodeBufferC2Ev
  2087: 000000000001bf18    28 FUNC    WEAK   DEFAULT   15 _ZN17tMediaAudioBufferC2Ev
  2088: 000000000001bf34    80 FUNC    WEAK   DEFAULT   15 _ZN17tMediaVideoBufferC2Ev
  2089: 000000000001bf84   360 FUNC    GLOBAL DEFAULT   15 _Z16freeDecodeBufferP18tMediaDecodeBuffer
  2090: 000000000001c0ec   336 FUNC    GLOBAL DEFAULT   15 _ZN19tMediaPlayerContext7releaseEv
  // ...

如果沒有本地符號表就只有以下信息(少了 .symtab):

Symbol table '.dynsym' contains 447 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
   // ...
   441: 000000000001c494    40 FUNC    GLOBAL DEFAULT   15 Java_com_tans_tmediaplayer_tMediaPlayer_durationNative
   442: 000000000001cac4   136 FUNC    GLOBAL DEFAULT   15 Java_com_tans_tmediaplayer_tMediaPlayer_getVideoFrameUBytesNative
   // ...

我們再來看看上面的那個崩潰棧地址 000000000001bd2c,我在 反編譯 .text 代碼(.text Section 就是用來存儲代碼的,通過 objdump --dissassemble --section=.text [elf file] 命令可以反編譯機器碼到匯編) 后找到了這個地址所在的方法:

000000000001bb5c: 
   1bb5c: ff 83 01 d1  	sub	sp, sp, #96
   // ...
   1bd2c: 11 7a 00 94  	bl	0x3a570 <abort@plt>
   1bd30: 44 79 00 94  	bl	0x3a240 <__stack_chk_fail@plt>

方法的指令有點長,我省略了大部分,我們看到 1bd2c 處調(diào)用了 abort() 方法,這個方法就是用來發(fā)送 SIGABORT 的,這是我測試時添加的,我們再來看看 1bb5c 在符號表中對應(yīng)的是哪個符號,正好就是 _ZN19tMediaPlayerContext29parseDecodeVideoFrameToBufferEP18tMediaDecodeBuffer 方法,哈哈。

最后

本篇文章介紹了符號表,還通過崩潰棧中的地址,在符號表中去查詢到了我們對應(yīng)的方法,希望你對 Native 的崩潰信息和符號表有一個全新的認識。

以上就是Android解讀Native崩潰棧信息的方法詳解的詳細內(nèi)容,更多關(guān)于Android解讀Native崩潰棧信息的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論