[cocos2dx]利用NDK崩潰日志查找BUG


摘要: 在android上開發c++應用, crash日志都是匯編碼, 很難對應到c++代碼中去. 通過此文, 你可以定位到程序崩潰時的C++代碼, 精確查找問題.



背景介紹

  1. 本文主要內容: 利用android的crash log來對c++開發的android應用進行錯誤定位.

  2. 容易穩定復現的BUG, 一般可以通過斷點調試來解決. 如果測試人員也無法穩定復現, log就成了程序吊定位問題的救命稻草.

  3. 通用操作系統都有自己的日志系統, android也不例外. 救命稻草已經給你了~ ( 怎樣查看android的系統日志 )

  4. 但是, android的系統日志在c++代碼崩潰時, 打印的都是內存地址和寄存器. 比如, 這樣:

06-20 15:54:35.331 23889 23889 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 06-20 15:54:35.331 23889 23889 I DEBUG : Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys' 06-20 15:54:35.331 23889 23889 I DEBUG : Revision: '0' 06-20 15:54:35.331 23889 23889 I DEBUG : pid: 1981, tid: 2020, name: Thread-3399 >>> com.guangyou.ddgame <<< 06-20 15:54:35.331 23889 23889 I DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000028 06-20 15:54:35.431 187 710 D audio_hw_primary: out_set_parameters: enter: usecase(0: deep-buffer-playback) kvpairs: routing=2 06-20 15:54:35.511 23889 23889 I DEBUG : r0 76d94458 r1 00000000 r2 00000000 r3 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : r4 760c1a48 r5 751e2440 r6 00000001 r7 760c1a48 06-20 15:54:35.511 23889 23889 I DEBUG : r8 00000001 r9 76c96f3c sl 76c861c0 fp 76d94444 06-20 15:54:35.511 23889 23889 I DEBUG : ip 00000001 sp 76d94430 lr 75a81bd8 pc 75a81bdc cpsr 600f0010 06-20 15:54:35.511 23889 23889 I DEBUG : d0 746968775f327865 d1 6a6e6169642f675f 06-20 15:54:35.511 23889 23889 I DEBUG : d2 5f6f616978757169 d3 676e702e6e776f6d 06-20 15:54:35.511 23889 23889 I DEBUG : d4 0000000009000000 d5 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d6 0000000000000000 d7 0000000000000000

這密密麻麻的都是些神馬, 是人看的么?

餓. 這個麻… 誰讓你當程序猿! 讓你當! 活該要看天書!

硬着頭皮也要來, 我們就來講講怎么消化天書吧~

怎樣獲取android的系統日志

假設你已經安裝了 Android Develop Tools, 可以成功調用adb. 並打開android開發用機的調試模式, 連接到電腦.

打開命令行, 在命令行輸入: adb logcat. 就可以看到滿屏幕的日志啦.
輸入adb logcat --help可以看到 logcat的用法提示.

這里有兩個參數特別提醒一下, 比較常用:
1. -v XXXX: 用來選擇log輸出樣式, 一般建議 threadtime, 更加詳細.
2. -d: 讓log一次性輸出后馬上完畢. 如果沒有此命令, logcat 工具會一直輸出, 即使更新在界面上.

如果需要保存log到文件, 方便以后查看. 可輸入命令:
adb logcat -v threadtime -d > log.txt

理解NDK的crash log

如果你用c++開發的android應用在運行過程中, c++代碼發生錯誤導致程序崩潰, 系統就會記錄 crash log到上述的系統日志中.

下面是我正在開發的游戲一次崩潰后, 截取的日志( 插個廣告, 全名斗地主下載地址: http://sj.ddwan.com )

06-20 15:54:35.331 23889 23889 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 06-20 15:54:35.331 23889 23889 I DEBUG : Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys' 06-20 15:54:35.331 23889 23889 I DEBUG : Revision: '0' 06-20 15:54:35.331 23889 23889 I DEBUG : pid: 1981, tid: 2020, name: Thread-3399 >>> com.guangyou.ddgame <<< 06-20 15:54:35.331 23889 23889 I DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000028 06-20 15:54:35.431 187 710 D audio_hw_primary: out_set_parameters: enter: usecase(0: deep-buffer-playback) kvpairs: routing=2 06-20 15:54:35.511 23889 23889 I DEBUG : r0 76d94458 r1 00000000 r2 00000000 r3 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : r4 760c1a48 r5 751e2440 r6 00000001 r7 760c1a48 06-20 15:54:35.511 23889 23889 I DEBUG : r8 00000001 r9 76c96f3c sl 76c861c0 fp 76d94444 06-20 15:54:35.511 23889 23889 I DEBUG : ip 00000001 sp 76d94430 lr 75a81bd8 pc 75a81bdc cpsr 600f0010 06-20 15:54:35.511 23889 23889 I DEBUG : d0 746968775f327865 d1 6a6e6169642f675f 06-20 15:54:35.511 23889 23889 I DEBUG : d2 5f6f616978757169 d3 676e702e6e776f6d 06-20 15:54:35.511 23889 23889 I DEBUG : d4 0000000009000000 d5 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d6 0000000000000000 d7 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d8 0000000000000000 d9 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d10 0000000000000000 d11 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d12 0000000000000000 d13 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d14 0000000000000000 d15 0000000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d16 c3c3c3c3c3c3c3c3 d17 c3c3c3c3c3c3c3c3 06-20 15:54:35.511 23889 23889 I DEBUG : d18 41c7ddc227000000 d19 3ff0000000000000 06-20 15:54:35.511 23889 23889 I DEBUG : d20 3f811110896efbb2 d21 3fd7096611460fdb 06-20 15:54:35.511 23889 23889 I DEBUG : d22 c0176a8ee0000000 d23 bfc5230c760b0605 06-20 15:54:35.511 23889 23889 I DEBUG : d24 0000000000000000 d25 3fc7922925a107e2 06-20 15:54:35.511 23889 23889 I DEBUG : d26 3fdaa0f8fab43e33 d27 3fb43ad076b251ab 06-20 15:54:35.511 23889 23889 I DEBUG : d28 3fa15cb6bdc3c156 d29 3ec6cd878c3b46a7 06-20 15:54:35.511 23889 23889 I DEBUG : d30 3f65f3b6b9b97e01 d31 3ef99342e0ee5069 06-20 15:54:35.511 23889 23889 I DEBUG : scr 20000012 06-20 15:54:35.511 23889 23889 I DEBUG : 06-20 15:54:35.511 23889 23889 I DEBUG : backtrace: 06-20 15:54:35.511 23889 23889 I DEBUG : #00 pc 0089cbdc /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::Texture2D::getContentSize() const+32) 06-20 15:54:35.511 23889 23889 I DEBUG : #01 pc 0088f8dc /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::Sprite::setTexture(std::string const&)+128) 06-20 15:54:35.511 23889 23889 I DEBUG : #02 pc 007863dc /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::ui::Button::loadTextureDisabled(std::string const&, cocos2d::ui::Widget::TextureResType)+336) 06-20 15:54:35.511 23889 23889 I DEBUG : 06-20 15:54:35.511 23889 23889 I DEBUG : stack: 06-20 15:54:35.511 23889 23889 I DEBUG : 76d943f0 00000001 06-20 15:54:35.511 23889 23889 I DEBUG : 76d943f4 4006bc0d /system/lib/libc.so (free+12) 06-20 15:54:35.511 23889 23889 I DEBUG : 76d943f8 76a72c54 06-20 15:54:35.511 23889 23889 I DEBUG : 76d943fc 75eca614 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94400 751c23c8 [anon:libc_malloc] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94404 751c23c8 [anon:libc_malloc] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94408 751c23c8 [anon:libc_malloc] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9440c 75a749b4 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::Sprite::setTexture(cocos2d::Texture2D*)+128) 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94410 0000003d 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94414 00e8efc8 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94418 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9441c 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94420 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94424 76d94458 [stack:2020] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94428 00000020 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9442c 76d94444 [stack:2020] 06-20 15:54:35.511 23889 23889 I DEBUG : #00 76d94430 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94434 76d94458 [stack:2020] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94438 76a66184 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9443c 760c1a48 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94440 76d9447c [stack:2020] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94444 75a748e0 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::Sprite::setTexture(std::string const&)+132) 06-20 15:54:35.511 23889 23889 I DEBUG : #01 76d94448 76d944ec [stack:2020] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9444c 793ff0e8 [anon:libc_malloc] 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94450 76a72c54 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94454 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94458 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9445c 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94460 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94464 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d94468 00000000 06-20 15:54:35.511 23889 23889 I DEBUG : 76d9446c 00000000 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94470 7b91dcf8 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94474 78ce6c50 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94478 76d944b4 [stack:2020] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d9447c 7596b3e0 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocos2d::ui::Button::loadTextureDisabled(std::string const&, cocos2d::ui::Widget::TextureResType)+340) 06-20 15:54:35.521 23889 23889 I DEBUG : #02 76d94480 00000001 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94484 00000000 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94488 76d944ec [stack:2020] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d9448c 793fe780 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94490 76d944f0 [stack:2020] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94494 793ff0e8 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94498 00000001 06-20 15:54:35.521 23889 23889 I DEBUG : 76d9449c 4006bc0d /system/lib/libc.so (free+12) 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944a0 76a72c54 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944a4 75eca614 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944a8 78ce6c50 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944ac 78ce6c50 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944b0 76d9455c [stack:2020] 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944b4 75924e54 /data/app-lib/com.guangyou.ddgame-1/libcocos2dcpp.so (cocostudio::ButtonReader::setPropsFromJsonDictionary(cocos2d::ui::Widget*, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> > const&)+752) 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944b8 00000000 06-20 15:54:35.521 23889 23889 I DEBUG : 76d944bc 78ce6c50 [anon:libc_malloc] 06-20 15:54:35.521 23889 23889 I DEBUG : 06-20 15:54:35.521 23889 23889 I DEBUG : memory near r0: 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94438 76a66184 760c1a48 76d9447c 75a748e0 06-20 15:54:35.521 23889 23889 I DEBUG : 76d94448 76d944ec 793ff0e8 76a72c54 00000000 ... 06-20 15:54:35.521 23889 23889 I DEBUG : 06-20 15:54:35.521 23889 23889 I DEBUG : memory near r4: 06-20 15:54:35.521 23889 23889 I DEBUG : 760c1a28 760811c8 75ee318c 75ee3194 75ee319c 06-20 15:54:35.521 23889 23889 I DEBUG : 760c1a38 4006d091 75f9a1f4 75f4ee5c 75e8ea0c ...

下面來逐行解讀:
1. ndk crash log以*** *** *** *** ***開始.
2. 第一行Build fingerprint: 'google/razorg/deb:4.4.2/KOT49H/937116:user/release-keys' 指明了運行的Android版本, 如果您有多份crash dump的話這個信息就比較有用了.
3. 接着一行顯示的是當前的線程id(pid)和進程id(tid). 如果當前崩潰的線程是主線程的話, pid和tid會是一樣的~
4. 第四行, 顯示的是unix信號. 這里的signal 11, 即SIGSEGV, 表示段錯誤, 是最常見的信號.(什么是unix信號, 什么是SIGSEGV)
5. 接下來的部分是系統寄存器的dump信息.

符號 解釋
rX(X=[0~9]) 代表整數寄存器
dX(X=[0~31]) 是浮點指針寄存器
fp (or r11) 指向當前正在執行的函數的堆棧底.
ip (or r12) 一個寄存器, 我也沒弄明白是干啥的.
sp (or r13) 當前正在執行的函數的堆棧頂.(跟fp相對應)
lr (or r14) link register. 簡單來說, 當當前指令執行完了,
就會從這個寄存器獲取地址, 來知道需要返回
到哪里繼續執行.
pc (or r15) program counter. 存放下一條指令的地址
cpsr Current Program Status Register. 表示當前
運行環境和狀態的一些字節位.

6. Crash dump還包含PC之前和之后的一些內存字段.
7. 最后, 是崩潰時的調用堆棧. 如果你執行的是debug版本, 還能還原一些c++代碼.

利用ndk-stack定位崩潰代碼

上面的一些信息能簡單的幫你定位以下問題. 如果信息量還不夠大的話, 那就還有最后一招: 還原歷史.

Android NDK自從版本R6開始, 提供了一個工具ndk-stack( 在目錄{ndk_root}/中 ). 這個工具能自動分析dump下來的crash log, 將崩潰時的調用內存地址和c++代碼一行一行對應起來.

我們先看一下用法, 執行命令ndk-stack --help

Usage: ndk-stack -sym <path> [-dump <path>] -sym Contains full path to the root directory for symbols. -dump Contains full path to the file containing the crash dump. This is an optional parameter. If ommited, ndk-stack will read input data from stdin
  • -dump參數很容易理解, 即dump下來的log文本文件. ndk-stack會分析此文件.
  • -sym參數就是你android項目下,編譯成功之后,obj目錄下的文件.

下面我們就來示范一下:

$ adb logcat | ndk-stack -sym ./obj/local/armeabi ********** Crash dump: ********** Build fingerprint: 'htc_wwe/htc_bravo/bravo:2.3.3/ GRI40/96875.1:user/release-keys' pid: 1723, tid: 1743 >>> com.packtpub.droidblaster <<< signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0000000c Stack frame #00 pc 00010a2c /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine update in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/TimeService.cpp:25 Stack frame #01 pc 00009fcc /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine onStep in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/DroidBlaster.cpp:53 Stack frame #02 pc 0000a348 /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine run in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/EventLoop.cpp:49 Stack frame #03 pc 0000f994 /data/data/com.packtpub.droidblaster/lib/libdroidblaster.so: Routine android_main in /home/packt/Project/Chapter11/DroidBlaster_Part11/jni/Main.cpp:31 ...

熟悉的代碼出現啦~~

Written with StackEdit.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM