在ios開發過程當中,常常會遇到應用在開發過程當中或者本身測試時不會有問題。而在安裝到別人設備上,或者上傳應用商店被別人下載的時候,老是被抱怨程序不按期的crash,真的很使人懊惱!ios
獲取 iOS crash logc++
這時iOS crash log 派上用場了,程序的大多數crash都會記錄在用戶的手機中,獲取crash log的方法有兩種:xcode
1. 用戶把設備鏈接到電腦上,打開xcode-window-organizer,選中Devices-當前鏈接設備-Device Log,就能夠查看全部當前設備的crash log,這個時候打開每一份crash的時候,發現這些文件的部分地址都會被轉換成,類名,方法名和行號等。設備上的日誌只用剛剛查看過都會被同步到organizer種,在LIBRARY下的Device Log能夠查看app
2. 若是你的應用已經上架,那麼開發者能夠經過iTunes Connect(Manage Your Applications - View Details - Crash Reports)獲取用戶的crash日誌。不過這並非100%有效的,並且大多數開發者並不依賴於此,由於這須要用戶設備贊成上傳相關信息,詳情可參見iOS: Providing Apple with diagnostics and usage information摘要。iphone
解析ios Crash Log(解析所有文件)ide
若是在Itunes Connect 獲得的Log文件打開查看都是十六進制的地址svn
Incident Identifier: 70B8BA67-3342-4354-8EC5-23B361C5A02A CrashReporter Key: 457198753f9cf1ae3862aef8ce49127acfd84425 Hardware Model: iPod5,1 Process: TestTransform [510] Path: /var/mobile/Applications/037726D5-5DAA-4E02-9CD1-68E0865CF4CF/TestTransform.app/TestTransform Identifier: com.TestTransform Version: 1.0 (1.0) Code Type: ARM (Native) Parent Process: launchd [1] Date/Time: 2014-04-10 09:57:27.961 +0800 OS Version: iOS 7.1 (11D167) Report Version: 104 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Triggered by Thread: 2 Last Exception Backtrace: (0x2e71dfce 0x38e66cca 0x2e654ac4 0x57130 0x3934e82e 0x39355ad2 0x39355d24 0x39490bce 0x39490a94) Thread 0: 0 libsystem_kernel.dylib 0x39416a58 0x39416000 + 2648 1 libsystem_kernel.dylib 0x39416854 0x39416000 + 2132 2 CoreFoundation 0x2e6e8896 0x2e64a000 + 649366 3 CoreFoundation 0x2e6e7002 0x2e64a000 + 643074 4 CoreFoundation 0x2e651f4a 0x2e64a000 + 32586 5 CoreFoundation 0x2e651d2e 0x2e64a000 + 32046 6 GraphicsServices 0x3357365e 0x3356a000 + 38494 7 UIKit 0x30f9d168 0x30f2f000 + 450920 8 TestTransform 0x00061c5c 0x4f000 + 76892 9 libdyld.dylib 0x39373ab4 0x39372000 + 6836 Thread 1: 0 libsystem_kernel.dylib 0x39416808 0x39416000 + 2056 1 libdispatch.dylib 0x39358078 0x3934d000 + 45176 2 libdispatch.dylib 0x39357dfe 0x3934d000 + 44542 Thread 2 Crashed: 0 libsystem_kernel.dylib 0x394291f0 0x39416000 + 78320 1 libsystem_pthread.dylib 0x39493792 0x39490000 + 14226 2 libsystem_c.dylib 0x393d9fd8 0x39391000 + 298968 3 libc++abi.dylib 0x38708cd2 0x38708000 + 3282 4 libc++abi.dylib 0x387216e0 0x38708000 + 104160 5 libobjc.A.dylib 0x38e66f62 0x38e63000 + 16226 6 libc++abi.dylib 0x3871f1c4 0x38708000 + 94660 7 libc++abi.dylib 0x3871ea18 0x38708000 + 92696 8 libobjc.A.dylib 0x38e66d9e 0x38e63000 + 15774 9 CoreFoundation 0x2e654ac4 0x2e64a000 + 43716 10 TestTransform 0x00057132 0x4f000 + 33074 11 libdispatch.dylib 0x3934e830 0x3934d000 + 6192 12 libdispatch.dylib 0x39355ad2 0x3934d000 + 35538 13 libdispatch.dylib 0x39355d24 0x3934d000 + 36132 14 libsystem_pthread.dylib 0x39490bd0 0x39490000 + 3024 15 libsystem_pthread.dylib 0x39490a94 0x39490000 + 2708 Thread 3: 0 libsystem_kernel.dylib 0x39429c70 0x39416000 + 81008 1 libsystem_pthread.dylib 0x39490bda 0x39490000 + 3034 2 libsystem_pthread.dylib 0x39490a94 0x39490000 + 2708 Thread 2 crashed with ARM Thread State (32-bit): r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x393ccaa9 r4: 0x00000006 r5: 0x001c5000 r6: 0x00000000 r7: 0x001c41a4 r8: 0x16e261d0 r9: 0x00000001 r10: 0x00000000 r11: 0x00000000 ip: 0x00000148 sp: 0x001c4198 lr: 0x39493797 pc: 0x394291f0 cpsr: 0x00000010 Binary Images: 0x4f000 - 0x62fff TestTransform armv7 <12a331e98ea13836b33483de64c3b1fc> /var/mobile/Applications/037726D5-5DAA-4E02-9CD1-68E0865CF4CF/TestTransform.app/TestTransform 0x2bec3000 - 0x2bee3fff dyld armv7 <651a31c39f71311f965f8ac44de02c88> /usr/lib/dyld 0x2d6e1000 - 0x2d6e1fff Accelerate armv7 <0424978b39f037a7b3bf9aad5b34a5b3> /System/Library/Frameworks/Accelerate.framework/Accelerate ......
若是想查看文件的廬山真面目,須要找出在上傳應用時所發送的.app和.DSYM文件,切記每次發送新版本都要保留這兩個文件,否則沒有辦法解析Crash Log的。能夠先把這兩個文件拷貝到桌面的某一個文件夾中,而後把.crash的文件也拷貝的同一個文件夾下。函數
這一解析過程須要使用Symbolicatecrash來完成,首先要找到Symbolicatecrash文件,xcode5.0在
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/
Symbolicatecrash文件獨立於Xcode,能夠拷到剛纔放crash log的文件夾中使用,在開始解析以前須要先進行一些校驗:
1. 查看xx.app文件的uuid的方法,在命令行中輸入:oop
$ dwarfdump --uuid xxx.app/xxx (xxx工程名)
2. 查看xx.app.dSYM文件的uuid的方法,在命令行輸入:測試
$ dwarfdump --uuid xxx.app.dSYM (xxx工程名)
3.查看.crash的uuid,位於crash日誌中的Binary Images:中的第一行。如:armv7s <13760bde0d073f1eb4d596c3df753f4b>
只有三者的uuid相同才能解析.crash文件,而後在命令行輸入:
$ ./symbolicatecrash xxx.crash xxx.app.dSYM > test.log
這樣能夠將.crash日誌轉換成test.log,test.log便可讀的函數文件。
輸入上述命令可能會出現Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 53.這個錯誤。
若是出現上述錯誤,輸入命令:export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer,
而後繼續執行./symbolicatecrash xxx.crash xxx.app.dSYM > test.log能夠成功
解析後的Crash Log爲:
Incident Identifier: 70B8BA67-3342-4354-8EC5-23B361C5A02A CrashReporter Key: 457198753f9cf1ae3862aef8ce49127acfd84425 Hardware Model: iPod5,1 Process: TestTransform [510] Path: /var/mobile/Applications/037726D5-5DAA-4E02-9CD1-68E0865CF4CF/TestTransform.app/TestTransform Identifier: com.TestTransform Version: 1.0 (1.0) Code Type: ARM (Native) Parent Process: launchd [1] Date/Time: 2014-04-10 09:57:27.961 +0800 OS Version: iOS 7.1 (11D167) Report Version: 104 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Triggered by Thread: 2 Last Exception Backtrace: 0 CoreFoundation 0x2e71dfce __exceptionPreprocess + 126 1 libobjc.A.dylib 0x38e66cca objc_exception_throw + 34 2 CoreFoundation 0x2e654ac4 -[__NSArrayI objectAtIndex:] + 172 3 TestTransform 0x00057130 __29-[ViewController aaaaaaaaaa:]_block_invoke (ViewController.m:193) 4 libdispatch.dylib 0x3934e82e _dispatch_call_block_and_release + 6 5 libdispatch.dylib 0x39355ad2 _dispatch_root_queue_drain + 218 6 libdispatch.dylib 0x39355d24 _dispatch_worker_thread2 + 52 7 libsystem_pthread.dylib 0x39490bce _pthread_wqthread + 294 8 libsystem_pthread.dylib 0x39490a94 start_wqthread + 4 Thread 0: 0 libsystem_kernel.dylib 0x39416a58 mach_msg_trap + 20 1 libsystem_kernel.dylib 0x39416854 mach_msg + 44 2 CoreFoundation 0x2e6e8896 __CFRunLoopServiceMachPort + 150 3 CoreFoundation 0x2e6e7002 __CFRunLoopRun + 850 4 CoreFoundation 0x2e651f4a CFRunLoopRunSpecific + 518 5 CoreFoundation 0x2e651d2e CFRunLoopRunInMode + 102 6 GraphicsServices 0x3357365e GSEventRunModal + 134 7 UIKit 0x30f9d168 UIApplicationMain + 1132 8 TestTransform 0x00061c5c main (main.m:16) 9 libdyld.dylib 0x39373ab4 start + 0 Thread 1: 0 libsystem_kernel.dylib 0x39416808 kevent64 + 24 1 libdispatch.dylib 0x39358078 _dispatch_mgr_invoke + 228 2 libdispatch.dylib 0x39357dfe _dispatch_mgr_thread$VARIANT$mp + 34 Thread 2 Crashed: 0 libsystem_kernel.dylib 0x394291f0 __pthread_kill + 8 1 libsystem_pthread.dylib 0x39493792 pthread_kill + 54 2 libsystem_c.dylib 0x393d9fd8 abort + 72 3 libc++abi.dylib 0x38708cd2 abort_message + 70 4 libc++abi.dylib 0x387216e0 default_terminate_handler() + 248 5 libobjc.A.dylib 0x38e66f62 _objc_terminate() + 190 6 libc++abi.dylib 0x3871f1c4 std::__terminate(void (*)()) + 76 7 libc++abi.dylib 0x3871ea18 __cxa_throw + 112 8 libobjc.A.dylib 0x38e66d9e objc_exception_throw + 246 9 CoreFoundation 0x2e654ac4 -[__NSArrayI objectAtIndex:] + 172 10 TestTransform 0x00057132 __29-[ViewController aaaaaaaaaa:]_block_invoke (ViewController.m:193) 11 libdispatch.dylib 0x3934e830 _dispatch_call_block_and_release + 8 12 libdispatch.dylib 0x39355ad2 _dispatch_root_queue_drain + 218 13 libdispatch.dylib 0x39355d24 _dispatch_worker_thread2 + 52 14 libsystem_pthread.dylib 0x39490bd0 _pthread_wqthread + 296 15 libsystem_pthread.dylib 0x39490a94 start_wqthread + 4 Thread 3: 0 libsystem_kernel.dylib 0x39429c70 __workq_kernreturn + 8 1 libsystem_pthread.dylib 0x39490bda _pthread_wqthread + 306 2 libsystem_pthread.dylib 0x39490a94 start_wqthread + 4 Thread 2 crashed with ARM Thread State (32-bit): r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x393ccaa9 r4: 0x00000006 r5: 0x001c5000 r6: 0x00000000 r7: 0x001c41a4 r8: 0x16e261d0 r9: 0x00000001 r10: 0x00000000 r11: 0x00000000 ip: 0x00000148 sp: 0x001c4198 lr: 0x39493797 pc: 0x394291f0 cpsr: 0x00000010 Binary Images: 0x4f000 - 0x62fff TestTransform armv7 <12a331e98ea13836b33483de64c3b1fc> /var/mobile/Applications/037726D5-5DAA-4E02-9CD1-68E0865CF4CF/TestTransform.app/TestTransform 0x2bec3000 - 0x2bee3fff dyld armv7 <651a31c39f71311f965f8ac44de02c88> /usr/lib/dyld 0x2d6e1000 - 0x2d6e1fff Accelerate armv7 <0424978b39f037a7b3bf9aad5b34a5b3> /System/Library/Frameworks/Accelerate.framework/Accelerate ......
這時候發現以前的一些行首爲項目名 後面的地址變成的方面調用+行號。
解析ios Crash Log(根據地址解析內容)
此外,還能夠在上面三個uuid對應的狀況下解析某一個地址的內容
$ xcrun atos -o xxx.app/xxx -arch armv7 0x38ad42f9 0x38ad42f9 0x38ad42f9(多個16進制地址,使用空格分開)---方法一 $ dwarfdump -–lookup 0x000036d2 -–arch armv6 xxx.app.dSYM ---方法二
若是根據以上方法操做,均提示找不到地址的話,可使用必殺了:
好比查找如下內容所對應的地址:
(當前代碼行地址 = 當前地址 + 地址偏移量,地址偏移量爲十進制數值,公式是這樣寫的,但不知道具體表達是否是這個意思,若是相同的crash,相同位置後面的地址偏移量相同,前面兩個數值可能會有變更)
10 TestTransform 0x00057132 0x4f000 + 33074
1.先說第一種比較簡單的方法利用 "當前地址" 和 "當前代碼行地址"
$ xcrun atos -o TestTransform.app/TestTransform -l 0x3d000 0x0004fc5c //輸出結果: baidudeMacBook-Pro:1 baidu$ xcrun atos -o /Users/baidu/Desktop/1/TestTransform.app/TestTransform -l 0x3d000 0x0004fc5c got symbolicator for /Users/baidu/Desktop/1/TestTransform.app/TestTransform, base address 4000 main (in TestTransform) (main.m:16)
2. 第二種相對複雜一點,涉及到地址的偏移,使用首先查看起始地址,即便每次iOS app啓動都會加載(main module)主模塊在不一樣的內存地址,可是dSYM文件假設你的main module加載在地址0x1000(大多數狀況是這個,也有0x4000的)。
獲取此地址的方法:
$ otool -arch armv7 -l /Users/cnstar-tech/crash/xxx.app/xxx | grep -B 1 -A 10 "LC_SEGM" | grep -B 3 -A 8 "__TEXT"
調用以上方法返回結果以下:
Load command 1 cmd LC_SEGMENT cmdsize 600 segname __TEXT vmaddr 0x00004000 vmsize 0x00014000 fileoff 0 filesize 81920 maxprot 0x00000005 initprot 0x00000005 nsects 8 flags 0x0
看到vmaddr顯示爲0x00004000。
而後查看 "TestTransform 0x00057132 0x4f000 + 33074" 使用 起始地址+地址偏移量如:
0x4000 + 33074 = 0xc132 (注意:前面爲前面爲16進制後面爲10進制相加,要都轉換成10進制相加,把得出的結果轉換成16進制)
就可使用 "0xc132" 地址查看內容了:
//方法一: $ dwarfdump --lookup 0xc132 --arch armv7 TestTransform.app.DSYM //輸出結果: ---------------------------------------------------------------------- File: TestTransform.app.DSYM/Contents/Resources/DWARF/TestTransform (armv7) ---------------------------------------------------------------------- Looking up address: 0x000000000000c132 in .debug_info... found! 0x00003947: Compile Unit: length = 0x00007b6e version = 0x0002 abbr_offset = 0x00000000 addr_size = 0x04 (next CU at 0x0000b4b9) 0x00003952: TAG_compile_unit [1] * AT_producer( "Apple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)" ) AT_language( DW_LANG_ObjC ) AT_name( "/Users/baidu/Desktop/TestTransform/TestTransform/ViewController.m" ) AT_low_pc( 0x0000a950 ) AT_stmt_list( 0x0000089f ) AT_comp_dir( "/Users/baidu/Desktop/TestTransform" ) AT_APPLE_major_runtime_vers( 0x02 ) 0x00003c22: TAG_subprogram [39] * AT_name( "__29-[ViewController aaaaaaaaaa:]_block_invoke" ) AT_decl_file( "/Users/baidu/Desktop/TestTransform/TestTransform/ViewController.m" ) AT_decl_line( 191 ) AT_prototyped( 0x01 ) AT_APPLE_isa( 0x01 ) AT_accessibility( DW_ACCESS_public ) AT_low_pc( 0x0000c09c ) AT_high_pc( 0x0000c182 ) AT_frame_base( r7 ) 0x00003c46: TAG_lexical_block [34] * AT_low_pc( 0x0000c0d6 ) AT_high_pc( 0x0000c17e ) Line table dir : '/Users/baidu/Desktop/TestTransform/TestTransform' Line table file: 'ViewController.m' line 193, column 0 with start address 0x000000000000c11e Looking up address: 0x000000000000c132 in .debug_frame... found! 0x00000160: FDE length: 0x0000000c CIE_pointer: 0x00000000 start_addr: 0x0000c09c __29-[ViewController aaaaaaaaaa:]_block_invoke range_size: 0x000000e6 (end_addr = 0x0000c182) Instructions: 0x0000c09c: CFA=4294967295+4294967295 //方法二: $ xcrun atos -o /Users/baidu/Desktop/1/TestTransform.app/TestTransform 0xc132 //輸出結果: __29-[ViewController aaaaaaaaaa:]_block_invoke (in TestTransform) (ViewController.m:193)
分析ios Crash Log:
Incident Identifier:當前crash的 id,能夠區分不一樣的crash事件
CrashReporter Key: 當前設備的id,能夠判斷crash在某一設備上出現的頻率
Hardware Model: 設備型號
Process: 當前應用的名稱,後面中括號中爲當前的應用在系統中的進程id
Path: 當前應用在設備中的路徑
Identifier: bundle id
Version: 應用版本號
Code Type: (還不清楚)
Date/Time: crash事件 時間
OS Version: 當前系統版本
Exception Type: 異常類型
Exception Codes: 異常出錯的代碼(常見代碼有如下幾種)
0x8badf00d錯誤碼:Watchdog超時,意爲「ate bad food」。
0xdeadfa11錯誤碼:用戶強制退出,意爲「dead fall」。
0xbaaaaaad錯誤碼:用戶按住Home鍵和音量鍵,獲取當前內存狀態,不表明崩潰。
0xbad22222錯誤碼:VoIP應用(由於太頻繁?)被iOS幹掉。
0xc00010ff錯誤碼:由於太燙了被幹掉,意爲「cool off」。
0xdead10cc錯誤碼:由於在後臺時仍然佔據系統資源(好比通信錄)被幹掉,意爲「dead lock」。
Triggered by Thread: 在某一個線程出了問題致使crash,Thread 0 爲主線程、其它的都爲子線程
Last Exception Backtrace: 最後異常回溯,通常根據這個代碼就能找到crash的具體問題
Crash Log分類:
若是全部的CrashLog已經被採集下來了,爲了不重複解決相同的bug,這個時候就須要全部的CrashLog分類,經過上面已有的信息,就能夠對CrashLog作以下的分類控制:
1. 經過設備id查找當前設備上出現的crash(經過CrashReporter Key);
2. 查找全部在iphone5上出現的crash(經過Hardware Model);
3. 查找全部在ios7.1上出現的crash(經過OS Version);
4. 查找全部在應用1.0版本上出現的crash(經過 Version);
5. 查看在某一個時間段內出現的crash(經過 Date/Time);
6. 查找全部由於內存問題出現的crash (經過 Exception Type);
7. 查找在主線程出現crash的問題(Triggered by Thread == 0);
8. 對上述條件的組合查詢;
固然作主要的時對crash的分類,判斷兩個crash是否是屬於同一個(或同一類)crash:
1. 經過Triggered by Thread字段判斷當前兩個crash是否是同時都在主線程(或同時都在子線程);
2. 判斷當前兩個crash的Exception Type和Exception Codes是否相同;
3. 若是有Last Exception Backtrace:字段,執行 4. 5 步;
4. 能夠先判斷Last Exception Backtrace:棧上的行數是否是同樣(若是在解析以前,每一行用一個地址表示),不同則認爲不是同一個crash;
解析前:
Last Exception Backtrace: (0x2e71dfce 0x38e66cca 0x2e654ac4 0x57130 0x3934e82e 0x39355ad2 0x39355d24 0x39490bce 0x39490a94)
解析後:
Last Exception Backtrace: 0 CoreFoundation 0x2e71dfce __exceptionPreprocess + 126 1 libobjc.A.dylib 0x38e66cca objc_exception_throw + 34 2 CoreFoundation 0x2e654ac4 -[__NSArrayI objectAtIndex:] + 172 3 TestTransform 0x00057130 __29-[ViewController aaaaaaaaaa:]_block_invoke (ViewController.m:193) 4 libdispatch.dylib 0x3934e82e _dispatch_call_block_and_release + 6 5 libdispatch.dylib 0x39355ad2 _dispatch_root_queue_drain + 218 6 libdispatch.dylib 0x39355d24 _dispatch_worker_thread2 + 52 7 libsystem_pthread.dylib 0x39490bce _pthread_wqthread + 294 8 libsystem_pthread.dylib 0x39490a94 start_wqthread + 4
5. 先由第一個地址開始比較逐個比較(通常最開始幾行和最後幾行都是調用系統函數,因此地址都是同樣的),直到發現某一個地址不同,使用dwarfdump命令分別將兩個地址解析。獲得兩個crash當前調用的方法名稱和分別位於文件的行號,經過獲得的信息在進行比較,而後終止比較,若是同樣,則認爲當前兩個crash爲同一緣由,對比結束;6. 若是沒有Last Exception Backtrace:字段,執行 7. 8. 步;7. 先經過Triggered by Thread字段找到兩個crashLog分別對應的棧,比較棧上的行數是否是同樣,不同則認爲不是同一個crash;8. 每一行對應一個地址,先由第一個地址開始比較(通常最開始幾行和最後幾行都是調用系統函數,因此地址都是同樣的),直到發現某一個地址不同,使用dwarfdump命令分別將兩個地址解析。獲得兩個crash當前調用的方法名稱和分別位於文件的行號,經過獲得的信息在進行比較,而後終止比較,若是同樣,則認爲當前兩個crash爲同一緣由,對比結束;