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

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

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

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

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

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)用所對(duì)應(yīng)的方法了,因?yàn)槲疫@里的 decode() 方法是遞歸調(diào)用的,所以你看到上面的棧中有多個(gè),方法后面還有一個(gè) +532 表示該地址離方法開始的地址的偏移量,如果你的 .so 文件里面還有 debug 信息,這個(gè) +532 能夠定位到某一行 C \ C++ 源碼,其實(shí)就是每條指令都映射了某一行代碼。

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

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

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

它解壓后如下:

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

那么我們?cè)趺磁袛嘁粋€(gè) .so 文件是不是有符號(hào)表呢?可以通過 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 就表示有符號(hào)表。

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

stripped 就表示沒有符號(hào)表。

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

符號(hào)表

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

我們可以通過 readelf -s [elf file] 讀取符號(hào)表:

以下是有符號(hào)表的數(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
  // ...

如果沒有本地符號(hào)表就只有以下信息(少了 .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
   // ...

我們?cè)賮砜纯瓷厦娴哪莻€(gè)崩潰棧地址 000000000001bd2c,我在 反編譯 .text 代碼(.text Section 就是用來存儲(chǔ)代碼的,通過 objdump --dissassemble --section=.text [elf file] 命令可以反編譯機(jī)器碼到匯編) 后找到了這個(gè)地址所在的方法:

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>

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

最后

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

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

相關(guān)文章

最新評(píng)論