以下部分包括本機崩潰的常見類型、對示例崩潰轉儲的分析以及對墓碑的討論。每種崩潰類型都包含示例debuggerd
輸出,其中突出顯示了關鍵證據,以幫助您區分特定類型的崩潰。
中止
中止很有趣,因為它們是故意的。有許多不同的中止方法(包括調用abort(3)
、使assert(3)
失敗、使用 Android 特定的致命日誌記錄類型之一),但都涉及調用abort
。 abort
調用使用 SIGABRT 向調用線程發出信號,因此在libc.so
中顯示“abort”的幀加上 SIGABRT 是要在debuggerd
輸出中查找以識別這種情況的內容。
可能有一個明確的“中止消息”行。您還應該查看logcat
輸出以查看該線程在故意殺死自己之前記錄了什麼,因為與assert(3)
或高級致命日誌記錄工具不同, abort(3)
不接受消息。
當前版本的 Android 內聯tgkill(2)
系統調用,因此它們的堆棧是最容易閱讀的,對 abort(3) 的調用位於最頂部:
pid: 4637, tid: 4637, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 0000121d r2 00000006 r3 00000008 r4 0000121d r5 0000121d r6 ffb44a1c r7 0000010c r8 00000000 r9 00000000 r10 00000000 r11 00000000 ip ffb44c20 sp ffb44a08 lr eace2b0b pc eace2b16 backtrace: #00 pc 0001cb16 /system/lib/libc.so (abort+57) #01 pc 0001cd8f /system/lib/libc.so (__assert2+22) #02 pc 00001531 /system/bin/crasher (do_action+764) #03 pc 00002301 /system/bin/crasher (main+68) #04 pc 0008a809 /system/lib/libc.so (__libc_init+48) #05 pc 00001097 /system/bin/crasher (_start_main+38)
舊版本的 Android 在原始中止調用(此處為第 4 幀)和實際發送信號(此處為第 0 幀)之間遵循了一條複雜的路徑。在 32 位 ARM 上尤其如此,它將__libc_android_abort
(此處為第 3 幀)添加到其他平台的raise
/ pthread_kill
/ tgkill
序列中:
pid: 1656, tid: 1656, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010 backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher
您可以使用crasher abort
重現此類崩潰的實例。
純空指針解引用
這是經典的原生崩潰,雖然它只是下一個崩潰類型的特例,但值得單獨提及,因為它通常需要最少的思考。
在下面的示例中,即使崩潰函數位於libc.so
中,因為字符串函數只是對它們給出的指針進行操作,所以您可以推斷strlen(3)
是使用空指針調用的;這個崩潰應該直接交給調用代碼的作者。在這種情況下,幀#01 是錯誤的調用者。
pid: 25326, tid: 25326, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 r0 00000000 r1 00000000 r2 00004c00 r3 00000000 r4 ab088071 r5 fff92b34 r6 00000002 r7 fff92b40 r8 00000000 r9 00000000 sl 00000000 fp fff92b2c ip ab08cfc4 sp fff92a08 lr ab087a93 pc efb78988 cpsr 600d0030 backtrace: #00 pc 00019988 /system/lib/libc.so (strlen+71) #01 pc 00001a8f /system/xbin/crasher (strlen_null+22) #02 pc 000017cd /system/xbin/crasher (do_action+948) #03 pc 000020d5 /system/xbin/crasher (main+100) #04 pc 000177a1 /system/lib/libc.so (__libc_init+48) #05 pc 000010e4 /system/xbin/crasher (_start+96)
您可以使用crasher strlen-NULL
重現此類崩潰的實例。
低地址空指針解引用
在許多情況下,故障地址不會是 0,而是其他一些低數字。特別是兩位或三位地址非常常見,而六位地址幾乎可以肯定不是空指針取消引用——這需要 1MiB 的偏移量。當您的代碼取消引用空指針時,通常會發生這種情況,就好像它是一個有效的結構一樣。常用函數是fprintf(3)
(或任何其他採用 FILE* 的函數)和readdir(3)
,因為代碼通常無法檢查fopen(3)
或opendir(3)
調用是否首先成功。
這是readdir
的示例:
pid: 25405, tid: 25405, name: crasher >>> crasher <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc r0 0000000c r1 00000000 r2 00000000 r3 3d5f0000 r4 00000000 r5 0000000c r6 00000002 r7 ff8618f0 r8 00000000 r9 00000000 sl 00000000 fp ff8618dc ip edaa6834 sp ff8617a8 lr eda34a1f pc eda618f6 cpsr 600d0030 backtrace: #00 pc 000478f6 /system/lib/libc.so (pthread_mutex_lock+1) #01 pc 0001aa1b /system/lib/libc.so (readdir+10) #02 pc 00001b35 /system/xbin/crasher (readdir_null+20) #03 pc 00001815 /system/xbin/crasher (do_action+976) #04 pc 000021e5 /system/xbin/crasher (main+100) #05 pc 000177a1 /system/lib/libc.so (__libc_init+48) #06 pc 00001110 /system/xbin/crasher (_start+96)
這裡崩潰的直接原因是pthread_mutex_lock(3)
試圖訪問地址 0xc(幀 0)。但是pthread_mutex_lock
所做的第一件事是取消引用它所給定的pthread_mutex_t*
的state
元素。如果查看源代碼,您可以看到該元素位於結構中的偏移量 0 處,這告訴您pthread_mutex_lock
被賦予了無效指針 0xc。從第 1 幀中,您可以看到它是由readdir
給定的,它從給定的DIR*
中提取mutex_
字段。查看該結構,您可以看到mutex_
位於struct DIR
的偏移量sizeof(int) + sizeof(size_t) + sizeof(dirent*)
處,在 32 位設備上為 4 + 4 + 4 = 12 = 0xc,所以你發現了錯誤:調用者向readdir
傳遞了一個空指針。此時您可以將堆棧粘貼到堆棧工具中,以找出在 logcat 中發生這種情況的位置。
struct DIR { int fd_; size_t available_bytes_; dirent* next_; pthread_mutex_t mutex_; dirent buff_[15]; long current_pos_; };
在大多數情況下,您實際上可以跳過此分析。足夠低的故障地址通常意味著您可以跳過堆棧中的任何libc.so
幀並直接指責調用代碼。但並非總是如此,這就是您提出令人信服的案例的方式。
您可以使用crasher fprintf-NULL
或crasher readdir-NULL
重現這種崩潰的實例。
強化失敗
FORTIFY 失敗是當 C 庫檢測到可能導致安全漏洞的問題時發生的中止的一種特殊情況。許多 C 庫函數得到了強化;他們需要一個額外的參數來告訴他們緩衝區實際上有多大,並在運行時檢查您嘗試執行的操作是否真正適合。這是一個示例,其中代碼嘗試將read(fd, buf, 32)
入實際上只有 10 個字節長的緩衝區...
pid: 25579, tid: 25579, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'FORTIFY: read: prevented 32-byte write into 10-byte buffer' r0 00000000 r1 000063eb r2 00000006 r3 00000008 r4 ff96f350 r5 000063eb r6 000063eb r7 0000010c r8 00000000 r9 00000000 sl 00000000 fp ff96f49c ip 00000000 sp ff96f340 lr ee83ece3 pc ee86ef0c cpsr 000d0010 backtrace: #00 pc 00049f0c /system/lib/libc.so (tgkill+12) #01 pc 00019cdf /system/lib/libc.so (abort+50) #02 pc 0001e197 /system/lib/libc.so (__fortify_fatal+30) #03 pc 0001baf9 /system/lib/libc.so (__read_chk+48) #04 pc 0000165b /system/xbin/crasher (do_action+534) #05 pc 000021e5 /system/xbin/crasher (main+100) #06 pc 000177a1 /system/lib/libc.so (__libc_init+48) #07 pc 00001110 /system/xbin/crasher (_start+96)
您可以使用crasher fortify
重現此類崩潰的實例。
-fstack-protector 檢測到堆棧損壞
編譯器的-fstack-protector
選項將檢查插入到具有堆棧緩衝區的函數中,以防止緩衝區溢出。默認情況下,此選項對平台代碼啟用,但不適用於應用程序。啟用此選項後,編譯器將指令添加到函數序言以將隨機值寫入堆棧上的最後一個局部變量,並將指令添加到函數尾聲以將其讀回並檢查它是否未更改。如果該值發生更改,它會被緩衝區溢出覆蓋,因此結尾調用__stack_chk_fail
來記錄消息併中止。
pid: 26717, tid: 26717, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'stack corruption detected' r0 00000000 r1 0000685d r2 00000006 r3 00000008 r4 ffd516d8 r5 0000685d r6 0000685d r7 0000010c r8 00000000 r9 00000000 sl 00000000 fp ffd518bc ip 00000000 sp ffd516c8 lr ee63ece3 pc ee66ef0c cpsr 000e0010 backtrace: #00 pc 00049f0c /system/lib/libc.so (tgkill+12) #01 pc 00019cdf /system/lib/libc.so (abort+50) #02 pc 0001e07d /system/lib/libc.so (__libc_fatal+24) #03 pc 0004863f /system/lib/libc.so (__stack_chk_fail+6) #04 pc 000013ed /system/xbin/crasher (smash_stack+76) #05 pc 00001591 /system/xbin/crasher (do_action+280) #06 pc 00002219 /system/xbin/crasher (main+100) #07 pc 000177a1 /system/lib/libc.so (__libc_init+48) #08 pc 00001144 /system/xbin/crasher (_start+96)
您可以通過回溯中存在__stack_chk_fail
和特定的中止消息來將此與其他類型的中止區分開來。
您可以使用crasher smash-stack
重現此類崩潰的實例。
來自不允許的系統調用的 Seccomp SIGSYS
seccomp系統(特別是 seccomp-bpf)限制對系統調用的訪問。有關面向平台開發人員的 seccomp 的更多信息,請參閱博文 Seccomp filter in Android O 。調用受限系統調用的線程將收到帶有代碼 SYS_SECCOMP 的 SIGSYS 信號。系統調用號將與架構一起顯示在原因行中。重要的是要注意系統調用號因體系結構而異。例如, readlinkat(2)
系統調用在 x86 上是 305,但在 x86-64 上是 267。 arm 和 arm64 上的索書號再次不同。因為系統調用號因體系結構而異,所以使用堆棧跟踪來找出不允許的系統調用通常比在標頭中查找系統調用號更容易。
pid: 11046, tid: 11046, name: crasher >>> crasher <<< signal 31 (SIGSYS), code 1 (SYS_SECCOMP), fault addr -------- Cause: seccomp prevented call to disallowed arm system call 99999 r0 cfda0444 r1 00000014 r2 40000000 r3 00000000 r4 00000000 r5 00000000 r6 00000000 r7 0001869f r8 00000000 r9 00000000 sl 00000000 fp fffefa58 ip fffef898 sp fffef888 lr 00401997 pc f74f3658 cpsr 600f0010 backtrace: #00 pc 00019658 /system/lib/libc.so (syscall+32) #01 pc 00001993 /system/bin/crasher (do_action+1474) #02 pc 00002699 /system/bin/crasher (main+68) #03 pc 0007c60d /system/lib/libc.so (__libc_init+48) #04 pc 000011b0 /system/bin/crasher (_start_main+72)
您可以通過信號線上的SYS_SECCOMP
和原因線上的描述來區分不允許的系統調用和其他崩潰。
您可以使用crasher seccomp
重現此類崩潰的實例。
僅執行內存違規(僅限 Android 10)
僅對於 Android 10 中的 arm64,二進製文件和庫的可執行段被映射到內存中僅執行(不可讀),作為針對代碼重用攻擊的強化技術。此緩解措施與其他緩解措施的相互作用很差,後來被刪除。
使代碼不可讀會導致有意和無意讀取標記為僅執行的內存段以拋出帶有代碼SEGV_ACCERR
的SIGSEGV
。這可能是由於錯誤、漏洞、與代碼混合的數據(例如文字池)或有意的內存自省而發生的。
編譯器假定代碼和數據沒有混合,但手寫彙編可能會出現問題。在許多情況下,這些可以通過簡單地將常量移動到.data
部分來解決。如果對可執行代碼段絕對需要代碼自省,則應首先調用mprotect(2)
將代碼標記為可讀,然後在操作完成後再次將其標記為不可讀。
pid: 2938, tid: 2940, name: crasher64 >>> crasher64 <<< signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x5f2ced24a8 Cause: execute-only (no-read) memory access error; likely due to data in .text. x0 0000000000000000 x1 0000005f2cecf21f x2 0000000000000078 x3 0000000000000053 x4 0000000000000074 x5 8000000000000000 x6 ff71646772607162 x7 00000020dcf0d16c x8 0000005f2ced24a8 x9 000000781251c55e x10 0000000000000000 x11 0000000000000000 x12 0000000000000014 x13 ffffffffffffffff x14 0000000000000002 x15 ffffffffffffffff x16 0000005f2ced52f0 x17 00000078125c0ed8 x18 0000007810e8e000 x19 00000078119fbd50 x20 00000078125d6020 x21 00000078119fbd50 x22 00000b7a00000b7a x23 00000078119fbdd8 x24 00000078119fbd50 x25 00000078119fbd50 x26 00000078119fc018 x27 00000078128ea020 x28 00000078119fc020 x29 00000078119fbcb0 sp 00000078119fba40 lr 0000005f2ced1b94 pc 0000005f2ced1ba4 backtrace: #00 pc 0000000000003ba4 /system/bin/crasher64 (do_action+2348) #01 pc 0000000000003234 /system/bin/crasher64 (thread_callback+44) #02 pc 00000000000e2044 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+36) #03 pc 0000000000083de0 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64)
您可以通過原因行將僅執行內存違規與其他崩潰區分開來。
您可以使用crasher xom
重現此類崩潰的實例。
fdsan 檢測到錯誤
Android 的 fdsan 文件描述符清理程序有助於捕捉文件描述符的常見錯誤,例如使用後關閉和雙重關閉。有關調試(和避免)此類錯誤的更多詳細信息,請參閱fdsan 文檔。
pid: 32315, tid: 32315, name: crasher64 >>> crasher64 <<< signal 35 (), code -1 (SI_QUEUE), fault addr -------- Abort message: 'attempted to close file descriptor 3, expected to be unowned, actually owned by FILE* 0x7d8e413018' x0 0000000000000000 x1 0000000000007e3b x2 0000000000000023 x3 0000007fe7300bb0 x4 3033313465386437 x5 3033313465386437 x6 3033313465386437 x7 3831303331346538 x8 00000000000000f0 x9 0000000000000000 x10 0000000000000059 x11 0000000000000034 x12 0000007d8ebc3a49 x13 0000007fe730077a x14 0000007fe730077a x15 0000000000000000 x16 0000007d8ec9a7b8 x17 0000007d8ec779f0 x18 0000007d8f29c000 x19 0000000000007e3b x20 0000000000007e3b x21 0000007d8f023020 x22 0000007d8f3b58dc x23 0000000000000001 x24 0000007fe73009a0 x25 0000007fe73008e0 x26 0000007fe7300ca0 x27 0000000000000000 x28 0000000000000000 x29 0000007fe7300c90 sp 0000007fe7300860 lr 0000007d8ec2f22c pc 0000007d8ec2f250 backtrace: #00 pc 0000000000088250 /bionic/lib64/libc.so (fdsan_error(char const*, ...)+384) #01 pc 0000000000088060 /bionic/lib64/libc.so (android_fdsan_close_with_tag+632) #02 pc 00000000000887e8 /bionic/lib64/libc.so (close+16) #03 pc 000000000000379c /system/bin/crasher64 (do_action+1316) #04 pc 00000000000049c8 /system/bin/crasher64 (main+96) #05 pc 000000000008021c /bionic/lib64/libc.so (_start_main)
您可以通過回溯中fdsan_error
的存在和特定的中止消息來將此與其他類型的中止區分開來。
您可以使用crasher fdsan_file
或crasher fdsan_dir
此類崩潰的實例。
調查崩潰轉儲
如果您現在沒有正在調查的特定崩潰,則平台源包含一個用於測試debuggerd
的工具,稱為 crasher。如果您在system/core/debuggerd/
中使用mm
,您將在您的路徑上同時獲得一個crasher
和一個crasher64
(後者允許您測試 64 位崩潰)。根據您提供的命令行參數,Crasher 可能會以多種有趣的方式崩潰。使用crasher --help
查看當前支持的選擇。
為了在故障轉儲中介紹不同的部分,讓我們通過這個示例故障轉儲:
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys' Revision: '0' ABI: 'arm' pid: 1656, tid: 1656, name: crasher >>> crasher <<< signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'some_file.c:123: some_function: assertion "false" failed' r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010 backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher Tombstone written to: /data/tombstones/tombstone_06 *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
如果您正在搜索日誌以查找本機崩潰,則帶有空格的星號行會很有幫助。除了在原生崩潰開始時,字符串“*** ***”很少出現在日誌中。
Build fingerprint: 'Android/aosp_flounder/flounder:5.1.51/AOSP/enh08201009:eng/test-keys'
指紋可讓您準確識別崩潰發生在哪個構建上。這與ro.build.fingerprint
系統屬性完全相同。
Revision: '0'
修訂是指硬件而不是軟件。這通常是不用的,但可以幫助您自動忽略已知由壞硬件引起的錯誤。這與ro.revision
系統屬性完全相同。
ABI: 'arm'
ABI 是 arm、arm64、x86 或 x86-64 之一。這對於上面提到的stack
腳本最有用,因此它知道要使用什麼工具鏈。
pid: 1656, tid: 1656, name: crasher >>> crasher <<<
此行標識進程中崩潰的特定線程。在這種情況下,它是進程的主線程,因此進程 ID 和線程 ID 匹配。第一個名字是線程名,>>>和<<<包圍的名字是進程名。對於應用程序,進程名稱通常是完全限定的包名稱(例如 com.facebook.katana),這在提交錯誤或嘗試在 Google Play 中查找應用程序時很有用。 pid 和 tid 在查找崩潰前的相關日誌行時也很有用。
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
這一行告訴您接收到了哪個信號 (SIGABRT),以及更多關於它是如何接收的 (SI_TKILL)。 debuggerd
報告的信號有 SIGABRT、SIGBUS、SIGFPE、SIGILL、SIGSEGV 和 SIGTRAP。信號特定代碼根據特定信號而變化。
Abort message: 'some_file.c:123: some_function: assertion "false" failed'
並非所有崩潰都會有中止消息行,但中止會有。這是從該 pid/tid 的致命 logcat 輸出的最後一行自動收集的,在故意中止的情況下,可能會解釋程序為什麼會自行終止。
r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8 r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010
寄存器轉儲顯示接收信號時 CPU 寄存器的內容。 (這部分在 ABI 之間差異很大。)它們的用處將取決於確切的崩潰。
backtrace: #00 pc 00042c98 /system/lib/libc.so (tgkill+12) #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32) #02 pc 0001bb87 /system/lib/libc.so (raise+10) #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34) #04 pc 000168e8 /system/lib/libc.so (abort+4) #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16) #06 pc 00018d35 /system/lib/libc.so (__assert2+20) #07 pc 00000f21 /system/xbin/crasher #08 pc 00016795 /system/lib/libc.so (__libc_init+44) #09 pc 00000abc /system/xbin/crasher
回溯向您顯示崩潰時我們在代碼中的位置。第一列是幀號(匹配 gdb 的樣式,其中最深的幀為 0)。 PC 值是相對於共享庫的位置而不是絕對地址。下一列是映射區域的名稱(通常是共享庫或可執行文件,但可能不適用於 JIT 編譯代碼)。最後,如果符號可用,則顯示 PC 值對應的符號,以及該符號的偏移量(以字節為單位)。您可以將它與objdump(1)
結合使用來查找相應的彙編指令。
讀墓碑
Tombstone written to: /data/tombstones/tombstone_06
這告訴你debuggerd
在哪裡寫了額外的信息。 debuggerd
將保留最多 10 個墓碑,循環通過數字 00 到 09 並根據需要覆蓋現有的墓碑。
墓碑包含與故障轉儲相同的信息,以及一些額外信息。例如,它包括所有線程(不僅僅是崩潰線程)、浮點寄存器、原始堆棧轉儲和圍繞寄存器地址的內存轉儲的回溯。最有用的是它還包括一個完整的內存映射(類似於/proc/ pid /maps
)。下面是一個來自 32 位 ARM 進程崩潰的帶註釋示例:
memory map: (fault address prefixed with --->) --->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (BuildId: b9527db01b5cf8f5402f899f64b9b121)
這裡有兩點需要注意。首先是這一行以“--->”為前綴。當您的崩潰不僅僅是空指針取消引用時,這些映射最有用。如果故障地址很小,則可能是空指針取消引用的某種變體。否則,查看故障地址周圍的地圖通常可以為您提供有關發生了什麼的線索。通過查看地圖可以識別的一些可能的問題包括:
- 讀/寫超過內存塊的末尾。
- 在內存塊開始之前讀/寫。
- 嘗試執行非代碼。
- 跑出堆棧的末尾。
- 嘗試寫入代碼(如上例所示)。
第二點要注意的是,可執行文件和共享庫文件將在 Android 6.0 及更高版本中顯示 BuildId(如果存在),因此您可以準確地看到哪個版本的代碼崩潰了。自 Android 6.0 起,平台二進製文件默認包含 BuildId; NDK r12 及更高版本也會自動將-Wl,--build-id
傳遞給鏈接器。
ab163000-ab163fff r-- 3000 1000 /system/xbin/crasher ab164000-ab164fff rw- 0 1000 f6c80000-f6d7ffff rw- 0 100000 [anon:libc_malloc]
在 Android 上,堆不一定是單個區域。堆區域將被標記為[anon:libc_malloc]
。
f6d82000-f6da1fff r-- 0 20000 /dev/__properties__/u:object_r:logd_prop:s0 f6da2000-f6dc1fff r-- 0 20000 /dev/__properties__/u:object_r:default_prop:s0 f6dc2000-f6de1fff r-- 0 20000 /dev/__properties__/u:object_r:logd_prop:s0 f6de2000-f6de5fff r-x 0 4000 /system/lib/libnetd_client.so (BuildId: 08020aa06ed48cf9f6971861abf06c9d) f6de6000-f6de6fff r-- 3000 1000 /system/lib/libnetd_client.so f6de7000-f6de7fff rw- 4000 1000 /system/lib/libnetd_client.so f6dec000-f6e74fff r-x 0 89000 /system/lib/libc++.so (BuildId: 8f1f2be4b37d7067d366543fafececa2) (load base 0x2000) f6e75000-f6e75fff --- 0 1000 f6e76000-f6e79fff r-- 89000 4000 /system/lib/libc++.so f6e7a000-f6e7afff rw- 8d000 1000 /system/lib/libc++.so f6e7b000-f6e7bfff rw- 0 1000 [anon:.bss] f6e7c000-f6efdfff r-x 0 82000 /system/lib/libc.so (BuildId: d189b369d1aafe11feb7014d411bb9c3) f6efe000-f6f01fff r-- 81000 4000 /system/lib/libc.so f6f02000-f6f03fff rw- 85000 2000 /system/lib/libc.so f6f04000-f6f04fff rw- 0 1000 [anon:.bss] f6f05000-f6f05fff r-- 0 1000 [anon:.bss] f6f06000-f6f0bfff rw- 0 6000 [anon:.bss] f6f0c000-f6f21fff r-x 0 16000 /system/lib/libcutils.so (BuildId: d6d68a419dadd645ca852cd339f89741) f6f22000-f6f22fff r-- 15000 1000 /system/lib/libcutils.so f6f23000-f6f23fff rw- 16000 1000 /system/lib/libcutils.so f6f24000-f6f31fff r-x 0 e000 /system/lib/liblog.so (BuildId: e4d30918d1b1028a1ba23d2ab72536fc) f6f32000-f6f32fff r-- d000 1000 /system/lib/liblog.so f6f33000-f6f33fff rw- e000 1000 /system/lib/liblog.so
通常,共享庫具有三個相鄰的條目。一種是可讀可執行的(代碼),一種是只讀的(只讀數據),一種是可讀寫的(可變數據)。第一列顯示映射的地址範圍,第二列顯示權限(在通常的 Unix ls(1)
樣式中),第三列顯示文件的偏移量(十六進制),第四列顯示區域的大小(十六進制),第五列是文件(或其他區域名稱)。
f6f34000-f6f53fff r-x 0 20000 /system/lib/libm.so (BuildId: 76ba45dcd9247e60227200976a02c69b) f6f54000-f6f54fff --- 0 1000 f6f55000-f6f55fff r-- 20000 1000 /system/lib/libm.so f6f56000-f6f56fff rw- 21000 1000 /system/lib/libm.so f6f58000-f6f58fff rw- 0 1000 f6f59000-f6f78fff r-- 0 20000 /dev/__properties__/u:object_r:default_prop:s0 f6f79000-f6f98fff r-- 0 20000 /dev/__properties__/properties_serial f6f99000-f6f99fff rw- 0 1000 [anon:linker_alloc_vector] f6f9a000-f6f9afff r-- 0 1000 [anon:atexit handlers] f6f9b000-f6fbafff r-- 0 20000 /dev/__properties__/properties_serial f6fbb000-f6fbbfff rw- 0 1000 [anon:linker_alloc_vector] f6fbc000-f6fbcfff rw- 0 1000 [anon:linker_alloc_small_objects] f6fbd000-f6fbdfff rw- 0 1000 [anon:linker_alloc_vector] f6fbe000-f6fbffff rw- 0 2000 [anon:linker_alloc] f6fc0000-f6fc0fff r-- 0 1000 [anon:linker_alloc] f6fc1000-f6fc1fff rw- 0 1000 [anon:linker_alloc_lob] f6fc2000-f6fc2fff r-- 0 1000 [anon:linker_alloc] f6fc3000-f6fc3fff rw- 0 1000 [anon:linker_alloc_vector] f6fc4000-f6fc4fff rw- 0 1000 [anon:linker_alloc_small_objects] f6fc5000-f6fc5fff rw- 0 1000 [anon:linker_alloc_vector] f6fc6000-f6fc6fff rw- 0 1000 [anon:linker_alloc_small_objects] f6fc7000-f6fc7fff rw- 0 1000 [anon:arc4random _rsx structure] f6fc8000-f6fc8fff rw- 0 1000 [anon:arc4random _rs structure] f6fc9000-f6fc9fff r-- 0 1000 [anon:atexit handlers] f6fca000-f6fcafff --- 0 1000 [anon:thread signal stack guard page]
從 Android 5.0 開始,C 庫命名了大部分匿名映射區域,因此神秘區域減少了。
f6fcb000-f6fccfff rw- 0 2000 [stack:5081]
名為[stack: tid ]
的區域是給定線程的堆棧。
f6fcd000-f702afff r-x 0 5e000 /system/bin/linker (BuildId: 84f1316198deee0591c8ac7f158f28b7) f702b000-f702cfff r-- 5d000 2000 /system/bin/linker f702d000-f702dfff rw- 5f000 1000 /system/bin/linker f702e000-f702ffff rw- 0 2000 f7030000-f7030fff r-- 0 1000 f7031000-f7032fff rw- 0 2000 ffcd7000-ffcf7fff rw- 0 21000 ffff0000-ffff0fff r-x 0 1000 [vectors]
您看到的是[vector]
還是[vdso]
取決於架構。 ARM 使用[vector]
,而所有其他架構使用[vdso]
。