IOS Crash Log 分析

Posted lixincishi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IOS Crash Log 分析相关的知识,希望对你有一定的参考价值。

上架AppStroe 被打回来了,原因是:

Your app crashed on iPad running ios 11.3.1 connected to an IPv6 network when we tapped on profile image. 

We have attached detailed crash logs to help troubleshoot this issue.

崩溃日志

技术分享图片

一、Crash文件结构

当程序运行Crash的时候,系统会把运行的最后时刻的运行信息记录下来,存储到一个文件中,也就是我们所说的Crash文件。iOS的Crash日志通常由以下6各部分组成。

1、Process Information(进程信息)

Incident Idnetifier 崩溃报告的唯一标识符,不同的Crash
CrashReporter Key 设备标识相对应的唯一键值(并非真正的设备的UDID,苹果为了保护用户隐私iOS6以后已经无法获取)。通常同一个设备上同一版本的App发生Crash时,该值都是一样的。
Hardware Model 代表发生Crash的设备类型,上图中的“iPad4,4”代表iPad Air
Process 代表Crash的进程名称,通常都是我们的App的名字, []里面是当时进程的ID
Path 可执行程序在手机上的存储位置,注意路径时到XXX.app/XXX,XXX.app其实是作为一个Bundle的,真正的可执行文件其实是Bundle里面的XXX,感兴趣的可以自己查一下相关资料,有机会我后面也会介绍到
Identifier 你的App的Indentifier,通常为“com.xxx.yyy”,xxx代表你们公司的域名,yyy代表某一个App
Version 当前App的版本号,由Info.plist中的两个字段组成,CFBundleShortVersionString and CFBundleVersion
Code Type 当前App的CPU架构
Parent Process 当前进程的父进程,由于iOS中App通常都是单进程的,一般父进程都是launchd

 

 

 

 

 

 

 

2、Basic Information

Date/Time Crash发生的时间,可读的字符串
OS Version 系统版本,()内的数字代表的时Bulid号
Report Version Crash日志的格式,目前基本上都是104,不同的version里面包含的字段可能有不同

 

 

 

3、Exception(非常重要)

Exception Type 异常类型
Exception Subtype: 异常子类型
Crashed Thread 发生异常的线程号

 

 

 

4、Thread Backtrace

技术分享图片

发生Crash的线程的Crash调用栈,从上到下分别代表调用顺序,最上面的一个表示抛出异常的位置,依次往下可以看到API的调用顺序。上图的信息表明本次Crash出现xxxViewController的323行,出错的函数调用为orderCountLoadFailed。

 

5、Thread State

技术分享图片

Crash时发生时刻,线程的状态,通常我们根据Crash栈即可获取到相关信息,这部分一般不用关心。

6、Binary Images

技术分享图片

Crash时刻App加载的所有的库,其中第一行是Crash发生时我们App可执行文件的信息,可以看出为armv7,可执行文件的包得uuid位c0f……cd65,解析Crash的时候dsym文件的uuid必须和这个一样才能完成Crash的符号化解析。

二、常见的Crash类型

1、Watchdog timeout

Exception Code:0x8badf00d, 不太直观,可以读成“eat bad food”,意思是don‘t block main thread

紧接着下面会有一段描述:

Application Specific Information:

com.xxx.yyy   failed to resume in time

对于此类Crash,我们应该去审视自己App初始化时做的事情是否正确,是否在主线程请求了网络,或者其他耗时的事情卡住了正常初始化流程。

通常系统允许一个App从启动到可以相应用户事件的时间最多为5S,如果超过了5S,App就会被系统终止掉。在Launch,resume,suspend,quit时都会有相应的时间要求。在Highlight Thread里面我们可以看到被终止时调用到的位置,xxxAppDelegate加上行号。 

PS. 在连接Xcode调试时为了便于调试,系统会暂时禁用掉Watchdog,所以此类问题的发现需要使用正常的启动模式。

2、User force-quit

Exception Codes: 0xdeadfa11, deadfall

这个强制退出跟我们平时所说的kill掉后台任务操作还不太一样,通常在程序bug造成系统无法响应时可以采用长按电源键,当屏幕出现关机确认画面时按下Home键即可关闭当前程序。

3、Low Memory termination

跟一般的Crash结构不太一样,通常有Free pages,Wired Pages,Purgeable pages,largest process 组成,同事会列出当前时刻系统运行所有进程的信息。

关于Memory warning可以参看我之前写的一篇文章IOS 内存警告 Memory warning level

App在运行过程中,系统内存紧张时通常会先发警告,同时把后台挂起的程序终止掉,最终如果还是内存不够的话就会终止掉当前前台的进程。

当接受到内存警告的事后,我们应该释放尽可能多的内存,Crash其实也可以看做是对App的一种保护。

4、Crash due to bugs

因为程序bug导致的Crash通常千奇百怪,很难一概而论。大部分情况通过Crash日志就可以定位出问题,当然也不排除部分疑难杂症看半天都不值问题出在哪儿。这个就只能看功底了,一点点找,总是能发现蛛丝马迹。是在看不出来时还可以求助于Google大神,总有人遇到和你一样的Bug 

三、常见的Exception Type & Exception Code

1、Exception Type

1)EXC_BAD_ACCESS

此类型的Excpetion是我们最长碰到的Crash,通常用于访问了不改访问的内存导致。一般EXC_BAD_ACCESS后面的"()"还会带有补充信息。

SIGSEGV: 通常由于重复释放对象导致,这种类型在切换了ARC以后应该已经很少见到了。

SIGABRT:  收到Abort信号退出,通常Foundation库中的容器为了保护状态正常会做一些检测,例如插入nil到数组中等会遇到此类错误。

SEGV:(Segmentation  Violation),代表无效内存地址,比如空指针,未初始化指针,栈溢出等;

SIGBUS:总线错误,与 SIGSEGV 不同的是,SIGSEGV 访问的是无效地址,而 SIGBUS 访问的是有效地址,但总线访问异常(如地址对齐问题)

SIGILL:尝试执行非法的指令,可能不被识别或者没有权限

2)EXC_BAD_INSTRUCTION

此类异常通常由于线程执行非法指令导致

3)EXC_ARITHMETIC

除零错误会抛出此类异常

2、Exception Code

0xbaaaaaad 此种类型的log意味着该Crash log并非一个真正的Crash,它仅仅只是包含了整个系统某一时刻的运行状态。通常可以通过同时按Home键和音量键,可能由于用户不小心触发
0xbad22222 当VOIP程序在后台太过频繁的激活时,系统可能会终止此类程序
0x8badf00d 这个前面已经介绍了,程序启动或者恢复时间过长被watch dog终止
0xc00010ff 程序执行大量耗费CPU和GPU的运算,导致设备过热,触发系统过热保护被系统终止
0xdead10cc 程序退到后台时还占用系统资源,如通讯录被系统终止
0xdeadfa11 前面也提到过,程序无响应用户强制关闭

  

三、获取Crash的途径

1、本机

通过xCode连接测试机器,直接在Device中即可读取到该机器上发生的所有Crash log。

2、itunes connect

通过itunes connect后台获取到用户上报的Crash日志。

3、第三方的Crash收集系统

有很多优秀的第三方Crash收集系统大大的方便了我们收集Crash,甚至还带了符号化Crash日志的功能。比较常用的有CrashlyticsFlurry等。

三、Xcode自带工具symbolicatecrash解析iOS Crash文件

 

一、找到.app文件和.app.dSYM文件

 

  • 在桌面创建一个crash文件夹,然后Xcode->Window->Organizer找到Archives找到App->右击Show in 
    Finder

  • 复制.app和.app.dSYM到crash夹文件:右击.xcarchive文件->显示包内容 
    在dSYMs文件夹中找到.app.dSYM 
    在Products->Applications文件夹中找到*.app

 

二、找到symbolicatecrash

 

  • 1 find /Applications/Xcode.app -name symbolicatecrash -type f

 

  • 稍等一会就会有路径输出,这个路径就是symbolicatecrash的路径

 

  • 1 /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

 

  • 用命令将symbolicatecrash拷贝到桌面的crash文件夹里面,与.app和.app.dSYM放一起(手动找到symbolicatecrash,拷贝出来也行)

 

  • cp /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash /Users/你的电脑名称/Desktop/crash

 

三、执行symbolicatecrash

 

  • 打开终端用命令切换到桌面的crash目录下:

 

  • cd /Users/你的电脑名称/Desktop/crash

 

  • 执行命令

 

  • 1 ./symbolicatecrash /Users/angelseahappiness/Desktop/crash/Control_2014-01-13-111838_Lynns-iPad3.crash /Users/angel/Desktop/crash/Control.app.dSYM > Control_symbol.crash

 

  • 这时候终端有可能会出现:

 

  • 1 Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.

 

  • 输入命令:

 

  • export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"

 

    • 再执行,这时候终端将会进行处理了
    • 将终端完成以后,在crash文件夹里面会多出一个文件Control_symbol.crash:这个就是最终的文件,可以查看bug所在的位置。

 

 因为上面的崩溃日志看不懂查看都是十六进制的地址不知道是哪里出了问题

 

分析需要用到在上传应用时的.app 和。dSYM 文件。切记每次发送新版本都要保留这两个文件,不然没有办法解析Crash Log的,可以先把这两个文件拷贝到桌面的某一个文件夹中,然后把.crash的文件也拷贝的同一个文件夹下。

这一解析过程需要使用Symbolicatecrash来完成,首先要找到Symbolicatecrash文件

Symbolicatecrash文件独立于Xcode,可以拷到刚才放crash log的文件夹中使用,在开始解析之前需要先进行一些校验:

1. 查看xx.app文件的uuid的方法,在命令行中输入:

$ 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可以成功

{"app_name":"MHdoctor","timestamp":"2018-05-22 11:08:48.28 -0700","app_version":"1.3.0","slice_uuid":"d19af238-ed08-32c2-9882-d9d17f4a3add","adam_id":1110258767,"build_version":"1.9","bundleID":"com.md.MHdoctor","share_with_app_devs":false,"is_first_party":false,"bug_type":"109","os_version":"iPhone OS 11.3.1 (15E302)","incident_id":"12CC75F6-9064-4A47-9D7E-E9B6B4D0D69E","name":"MHdoctor"}
Incident Identifier: 12CC75F6-9064-4A47-9D7E-E9B6B4D0D69E
CrashReporter Key: 467949c45077b22197dba2880a7275a842d5dbf8
Hardware Model: xxx1
Process: MHdoctor [4393]
Path: /private/var/containers/Bundle/Application/B3AF5423-5751-4EFF-B9E6-44F5FA6CFEBA/MHdoctor.app/MHdoctor
Identifier: com.md.MHdoctor
Version: 1.9 (1.3.0)
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Coalition: com.md.MHdoctor [2305]


Date/Time: 2018-05-22 11:08:48.1360 -0700
Launch Time: 2018-05-22 11:07:56.9302 -0700
OS Version: iPhone OS 11.3.1 (15E302)
Baseband Version: n/a
Report Version: 104

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0

Application Specific Information:
abort() called

Filtered syslog:
None found

Last Exception Backtrace:
0 CoreFoundation 0x18108ad8c 0x180f45000 + 1334668
1 libobjc.A.dylib 0x1802445ec 0x18023c000 + 34284
2 CoreFoundation 0x18108abf8 0x180f45000 + 1334264
3 Foundation 0x181a7afa0 0x1819bd000 + 778144
4 UIKit 0x18ac806e0 0x18ac14000 + 444128
5 MHdoctor 0x102f9451c UserDataViewController.imageViewTouch() + 3589404 (UserDataViewController.swift:466)
6 MHdoctor 0x102f95410 @objc UserDataViewController.viewDidLoad+ 3593232 () + 27
7 UIKit 0x18ae3a750 0x18ac14000 + 2254672
8 UIKit 0x18b3a72a4 0x18ac14000 + 7942820
9 UIKit 0x18af9ce6c 0x18ac14000 + 3706476
10 UIKit 0x18ae397a8 0x18ac14000 + 2250664
11 UIKit 0x18b398ac4 0x18ac14000 + 7883460
12 UIKit 0x18ae33540 0x18ac14000 + 2225472
13 UIKit 0x18ae33078 0x18ac14000 + 2224248
14 UIKit 0x18ae328dc 0x18ac14000 + 2222300
15 UIKit 0x18ae31238 0x18ac14000 + 2216504
16 UIKit 0x18b612c0c 0x18ac14000 + 10480652
17 UIKit 0x18b6151b8 0x18ac14000 + 10490296
18 UIKit 0x18b60e258 0x18ac14000 + 10461784

 

这时候发现之前的一些行首为项目名 后面的地址变成的方面调用+行号。

解析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 MHdoctor.app.DSYM

//输出结果:
----------------------------------------------------------------------
 File: TestTransform.app.DSYM/Contents/Resources/DWARF/
MHdocto
(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/MHdoctor/MHdoctor/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/MHdoctor/MHdoctor/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/MHdoctor/MHdoctor‘ 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/
MHdocto
.app/
MHdocto
0xc132 //输出结果: __29-[ViewController aaaaaaaaaa:]_block_invoke (in
MHdocto
) (ViewController.m:193)

 




































































以上是关于IOS Crash Log 分析的主要内容,如果未能解决你的问题,请参考以下文章

iOS Crash收集与分析详解(基础篇)

android crash日志怎么分析

crash日志的分析

iOS Crash上传

深入理解iOS Crash Log

分析iOS Crash文件:符号化iOS Crash文件的3种方法