摘要: 在android上開發c++應用, crash日誌都是彙編碼, 很難對應到c++代碼中去. 經過此文, 你能夠定位到程序崩潰時的C++代碼, 精確查找問題.android
本文主要內容: 利用android的crash log來對c++開發的android應用進行錯誤定位. c++
容易穩定復現的BUG, 通常能夠經過斷點調試來解決. 若是測試人員也沒法穩定復現, log就成了程序吊定位問題的救命稻草. json
通用操做系統都有本身的日誌系統, android也不例外. 救命稻草已經給你了~ ( 怎樣查看android的系統日誌 ) api
可是, android的系統日誌在c++代碼崩潰時, 打印的都是內存地址和寄存器. 好比, 這樣:app
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
這密密麻麻的都是些神馬, 是人看的麼?函數
餓. 這個麻… 誰讓你當程序猿! 讓你當! 活該要看天書! 工具
硬着頭皮也要來, 咱們就來說講怎麼消化天書吧~oop
假設你已經安裝了 Android Develop Tools, 能夠成功調用adb
. 並打開android開發用機的調試模式, 鏈接到電腦.測試
打開命令行, 在命令行輸入: adb logcat
. 就能夠看到滿屏幕的日誌啦.
輸入adb logcat --help
能夠看到 logcat
的用法提示. ui
這裏有兩個參數特別提醒一下, 比較經常使用:
1. -v XXXX
: 用來選擇log輸出樣式, 通常建議 threadtime
, 更加詳細.
2. -d
: 讓log一次性輸出後立刻完畢. 若是沒有此命令, logcat
工具會一直輸出, 即便更新在界面上.
若是須要保存log到文件, 方便之後查看. 可輸入命令:
adb logcat -v threadtime -d > log.txt
若是你用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++代碼.
上面的一些信息能簡單的幫你定位如下問題. 若是信息量還不夠大的話, 那就還有最後一招: 還原歷史.
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
ndk-stack
會分析此文件.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.