当前位置: 游戏平台 > 互联网科技 > 正文

崩溃日志分析

时间:2020-03-23 00:18来源:互联网科技
最近一段时间,在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题。简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较

最近一段时间,在iOS开发调试过程中以及上线之后,程序经常会出现崩溃的问题。简单的崩溃还好说,复杂的崩溃就需要我们通过解析Crash文件来分析了,解析Crash文件在iOS开发中是比较常见的。但在跟开发者沟通过程中,云捕小编发觉大家对iOS的应用符号表还不是很清楚。

xcrun atos -o MiniFamilySchool.app.dSYM/Contents/Resources/DWARF/MiniFamilySchool -arch armv7 -l 0x100034000 0x0000000100769c3c

前提

应用崩溃影响用户体验,所以减少iOS应用奔溃是提高应用质量的重要途径。

图片 1

在前面的内容可以知道,符号表的作用是把崩溃中的函数地址解析为函数名等信息。

一、获取iOS应用 crash信息

现在网上有很多关于解析崩溃堆栈信息的符号化的博客,但是大多质量参差不齐,或者有些细节没有注意到。今天总结一下对iOS崩溃符号化的使用和技巧:

如果开发者能够获取到崩溃的函数地址信息,就可以利用符号表分析出具体的出错位置。

1,通过itunes同步

  • 1,iOS设备上的应用闪退时, 操作系统会声称一个崩溃日志, 保存在设备上。
路径是:  设置 -> 隐私 ->诊断与用量 ->诊断与用量数据。在这里可以看到设备上所有的设备崩溃日志.
在“诊断与用量”界面,建议用户选择自动发送,这样可以每天自动发送诊断和用量数据到itunes,来帮助开发者分析崩溃.

图片 2

  • 2,设备与电脑上的ITunes Store同步后, 会将崩溃日志保存在电脑上,崩溃日志保存在以下位置:
Mac OSX :~/Library/Logs/CrashReporter/MobileDevice/ 
可以看到所有和该电脑同步过的设备的崩溃日志(.crash文件)

一.场景

Xcode提供了几个工具来帮助开发者执行函数地址符号化的操作。

2,使用Xcode

  • 1,code的Window菜单下的organizer,然后点击Devices tab,然后选中左边的Device Logs。选中某一个崩溃日志,点击Export Log可导出崩溃日志(.crash文件)
![](https://upload-images.jianshu.io/upload_images/1290895-886c9f44545ded5f.png)
  • 2,通过Xcode 获取appStore上架应用的crash信息。
![](https://upload-images.jianshu.io/upload_images/1290895-cfe497d68d1279e2.png)

当我们收集iOS的崩溃信息时,获取到的崩溃堆栈一般是如下的形式,全是十六进制的内存地址形式:

例如,崩溃问题的函数地址堆栈如下:

3,其他方式获取部分堆栈信息

  • 1,通过代码获取应用的crash堆栈信息,然后下次启动时上传服务器获得日志信息。
  • 2,通过友盟等第三方SDK拿到应用crash部分堆栈信息。
    这种方式获取的应用信息都只有部分堆栈信息

图片 3

错误地址堆栈

二,获取应用的符号表

这样的格式我们很难看出实际含义,无法定位问题代码,只有将它们转化为可读的形式才有意义:

3  CoreFoundation           0x254b5949 0x253aa000 + 1096008
4  CoreFoundation           0x253e6b68 _CF_forwarding_prep_0 + 24
5  SuperSDKTest             0x0010143b 0x000ef000 + 74808

1,日志文件

获取日志信息后,需要对堆栈调用信息分析

图片 4

crash调用堆栈信息如图,有4列:第1列是栈顺序;第2列是二进制包名;第3列是运行地址;第四列是函数的动态加载地址,即加号前面的地址。

图片 5

符号化堆栈

2,dSYM文件

在Xcode每次Archives的是都会生成dSYM文件,所有每次打包的时候的都需要保留包文件。点击.xcarchive文件,显示包含内容,在该目录下有生成的dSYM文件。dSYM文件也是Mach-o格式,Mach-O格式全称为Mach Object文件格式的缩写,是mac上可执行文件的格式,类似于windows上的PE格式 (Portable Executable ), Linux上的elf格式 (Executable and Linking Format)。
Mach-O可以分为3个部分

  • (1)Header
  • (2)Segment
  • (3)section
    header后面是segment,然后再跟着section,而一个segment是可以包含多个section的。MachOview工具可以可视化查看Mach-O文件格式,我们把dSYM文件放入可视化工具:
![](https://upload-images.jianshu.io/upload_images/1290895-817730e6ff3cc19b.png)

该dSYM文件包含armv7和arm64两种架构的符号表。其中arm64的偏移地址时835520

如上所示,我们一眼就能看明白,这次崩溃发生在ViewController.m文件的68行,对应的方法是rangeException。那么这样的符号化又是如何实现的呢?

3   CoreFoundation          0x254b5949 <redacted> + 712
4   CoreFoundation          0x253e6b68 _CF_forwarding_prep_0 + 24
5   SuperSDKTest            0x0010143b -[ViewController didTriggerClick:] + 58

3,UUID

每一个可执行程序都有一个build UUID来唯一标识。Crash日志包含发生crash的这个应用(app)的 build UUID以及crash发生的时候,应用加载的所有库文件的[build UUID]。UUID用来确定二进制包唯一标识

  • 查看日志文件的UUID
localhost:Test guogh$ grep "crashTest arm64" crashTest2017.crash 
0x1000cc000 - 0x1000d3fff crashTest arm64  <87f22ef6f56d3c7fac969d3416cd328a> /var/containers/Bundle/Application/13B84A6F-FB06-484B-8573-9390559A4A71/crashTest.app/crashTest

或者

localhost:Test guogh$ grep --after-context=2 "Binary Images:" crashTest2017.crash 
Binary Images:
0x1000cc000 - 0x1000d3fff crashTest arm64  <87f22ef6f56d3c7fac969d3416cd328a> /var/containers/Bundle/Application/13B84A6F-FB06-484B-8573-9390559A4A71/crashTest.app/crashTest
0x100124000 - 0x100153fff dyld arm64  <f54ed85a94253887886a8028e20ed8ba> /usr/lib/dyld

其中 0x1000cc000 就是模块的加载地址。

  • 查看二进制文件的UUID,dSYM文件
localhost:Test guogh$ xcrun dwarfdump --uuid dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest 
UUID: 6D16D164-DA42-31C8-8890-94895DB43C47 (armv7) dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest
UUID: 87F22EF6-F56D-3C7F-AC96-9D3416CD328A (arm64) dSYMs/crashTest.app.dSYM/Contents/Resources/DWARF/crashTest

或者appName.app/appName文件

localhost:Test guogh$ xcrun dwarfdump --uuid Products/Applications/crashTest.app/crashTest 
UUID: 6D16D164-DA42-31C8-8890-94895DB43C47 (armv7) Products/Applications/crashTest.app/crashTest
UUID: 87F22EF6-F56D-3C7F-AC96-9D3416CD328A (arm64) Products/Applications/crashTest.app/crashTest

需要三者的UUID的匹配才能正确的符号化。即都是:87F22EF6-F56D-3C7F-AC96-9D3416CD328A

我们知道,开发者在使用Xcode开发调试App时,一旦遇到崩溃问题,开发者可以直接使用Xcode的调试器定位分析崩溃堆栈。但如果App发布上线,用户的手机发生了崩溃,我们就只能通过分析系统记录的崩溃日志来定位问题,在这份崩溃日志文件中,会指出App出错的函数内存地址,关键的问题,崩溃日志中只有地址,类似 0x2312e92f这种,这看起来岂不是相当头疼,那怎么办呢?

说明:

三,符号化iOS Crash堆栈

我们拿到的crash信息是堆栈调用信息,所有信息都是16进制的内存地址,不能分析应用crash的原因,需要符号化才能分析。

幸好有dSYM文件的存在,它是帮助苦逼的码农有效定位bug问题的重要途径。崩溃堆栈里的函数地址可以借助dSYM文件来找到具体的文件名、函数名和行号信息的。实际上,在使用Xcode的Organizer查看崩溃日志时,就是根据本地存储的.dSYM文件进行了符号化的操作。

大部分情况下,开发者能获取到的都是错误地址堆栈,需要利用符号表进一步符号化才能分析定位问题。

1,使用Xcode

对于已经上架了appStore的应用的来说,crash文件通过用户上传到苹果服务器,Xcode可以直接下载下来,看到堆栈符号化的堆栈信息就和开发调试一样方便。

图片 6

二.Xcode符号化工具

部分情况下,开发者也可以利用backtrace看到符号化堆栈,可以大概定位出错的函数、但却不知道具体的位置。通过利用符号表信息,也是可以进一步得到具体的出错位置的。

2, symbolicatecrash

symbolicatecrash是Xcode带的独立工具,可以拷贝出来使用。查找位置

localhost:~ guogh$ find /Applications/Xcode.app -name symbolicatecrash -type f
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash

如果提示Error: "DEVELOPER_DIR" is not defined ,则执行
export DEVELOPER_DIR=/Applications/Xcode.app

把symbolicatecrash和奔溃日志,APP对应的.dSYM文件放在同一文件夹下,执行如下命令:

Symbolicatecrash + 崩溃日志.crash + APP对应的.dSYM文件 + > + 输出到的文件,
或者
Symbolicatecrash + 崩溃日志.crash + appName.app/appName + > + 输出到的文件,
如:
localhost:Test guogh$ ./symbolicatecrash crashTest2017.crash Products/Applications/crashTest.app/crashTest > aa.log

符号化前

Last Exception Backtrace:
0   CoreFoundation                  0x1843391b8 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x182d7055c objc_exception_throw + 56
2   CoreFoundation                  0x1842147f4 -[__NSArrayI objectAtIndex:] + 184
3   crashTest                       0x1000d0904 0x1000cc000 + 18692
4   crashTest                       0x1000d0864 0x1000cc000 + 18532
5   UIKit                           0x18a1ee924 -[UIViewController loadViewIfRequired] + 1056
6   UIKit                           0x18a1ee4ec -[UIViewController view] + 28
7   UIKit                           0x18a1f4c98 -[UIWindow addRootViewControllerViewIfPossible] + 76
8   UIKit                           0x18a1f2138 -[UIWindow _setHidden:forced:] + 272

symbolicatecrash 符号化后

Last Exception Backtrace:
0   CoreFoundation                  0x1843391b8 __exceptionPreprocess + 124
1   libobjc.A.dylib                 0x182d7055c objc_exception_throw + 56
2   CoreFoundation                  0x1842147f4 -[__NSArrayI objectAtIndex:] + 184
3   crashTest                       0x1000d0904 -[ViewController crashTest] (ViewController.m:29)
4   crashTest                       0x1000d0864 -[ViewController viewDidLoad] (ViewController.m:22)
5   UIKit                           0x18a1ee924 -[UIViewController loadViewIfRequired] + 1056
6   UIKit                           0x18a1ee4ec -[UIViewController view] + 28
7   UIKit                           0x18a1f4c98 -[UIWindow addRootViewControllerViewIfPossible] + 76
8   UIKit                           0x18a1f2138 -[UIWindow _setHidden:forced:] + 272

可以看到第3,4行已经符号化了,显示了哪个文件具体行数,对应代码

图片 7

查看源码,找出代码crash的原因就容易的多了。但使用symbolicatecrash工具有很大的限制

  • 只能分析官方格式的崩溃日志,需要从具体的设备中导出,获取和操作都不是很方便
  • 符号化的结果也是没有具体的行号信息的,也经常会出现符号化失败的情况。
  • 实际上, Xcode的Organizer内置了symbolicatecrash工具,所以开发者才可以直接看到符号化的崩溃堆栈日志。

Xcode本身也提供了几个工具来帮助开发者执行函数地址符号化的操作

目前,许多崩溃监控服务都显示backtrace符号化堆栈,增加了可读性,但分析定位问题时,仍然要进一步符号化处理。

3,使用命令行工具atos

命令格式:

 atos -o executable -arch architecture -l loadAddress address 

说明:

  • executable dYSM文件或二进制执行文件appName.app/appName
  • loadAddress 表示函数的动态加载地址,对应崩溃地址堆栈中 + 号前面的地址,即0x1000cc000
  • address 表示运行时地址、对应崩溃地址堆栈中第一个地址,即0x1000d0904 ,实际上,崩溃地址堆栈中+号前后的地址相加即是运行时地址,即0x1000cc000 + 18692= 0x1000d0904
  • 执行命令查询地址的符号,可以看到如下结果:
-[ViewController crashTest] (in crashTest) (ViewController.m:29)

1、symbolicatecrash

崩溃信息的UUID

四,总结

本文分析了如何获取用户的.crash文件,以及如何符号化的方法,对于分析应用crash很适用。

symbolicatecrash是一个将堆栈地址符号化的脚本,输入参数是苹果官方格式的崩溃日志及本地的.dSYM文件,

0xef000 - 0x17efff SuperSDKTest armv7 <38d66f9734ca3843a2bf628bb9015a8b> /var/mobile/.../SuperSDKTest.app/SuperSDKTest
下面,利用两个工具来进行一下符号化的尝试:

执行方式如下:

1、symbolicatecrash

Symbolicatecrash + 崩溃日志 + APP对应的.dSYM文件 + > + 输出到的文件,

symbolicatecrash是一个将堆栈地址符号化的脚本,输入参数是苹果官方格式的崩溃日志及本地的.dSYM文件,执行方式如下:

但使用symbolicatecrash工具有很大的限制

$ symbolicatecrash XX.crash [XX.app.dSYM] > xx.sym.crash# 如果输入.dSYM参数,将只解析系统库对应的符号
使用symbolicatecrash工具的限制就在于只能分析官方格式的崩溃日志,需要从具体的设备中导出,获取和操作都不是很方便,而且,符号化的结果也是没有具体的行号信息的,也经常会出现符号化失败的情况。
实际上Xcode的Organizer内置了symbolicatecrash工具,所以开发者才可以直接看到符号化的错误日志。

只能分析官方格式的崩溃日志,需要从具体的设备中导出,获取和操作都不是很方便

2、atos

符号化的结果也是没有具体的行号信息的,也经常会出现符号化失败的情况。

更普遍的情况是,开发者能获取到错误堆栈信息,而使用atos工具就是把地址对应的具体符号信息找到。

实际上, Xcode的Organizer内置了symbolicatecrash工具,所以开发者才可以直接看到符号化的崩溃堆栈日志。

atos实际是一个可以把地址转换为函数名(包括行号)的工具,它的执行方式如下:

2、atos

$ xcrun atos -o executable -arch architecture -l loadAddress
address ...
说明:

更普遍的情况是,开发者能获取到错误堆栈信息,而使用atos工具就是把地址对应的具体符号信息找到。它是一个可以把地址转换为函数名的工具,

loadAddress 表示函数的动态加载地址,对应崩溃地址堆栈中 + 号前面的地址,即0x000ef000

执行方式如下:

address 表示运行时地址、对应崩溃地址堆栈中第一个地址,即0x0010143b

atos -o executable -arch architecture -l loadAddress address

实际上,崩溃地址堆栈中+号前后的地址相加即是运行时地址,即0x000ef000 + 74808 = 0x0010143b

说明:

执行命令查询地址的符号,可以看到如下结果:

loadAddress 表示函数的动态加载地址,对应崩溃地址堆栈中 + 号前面的地址,即0x00048000

$ xcrun atos -o SuperSDKTest.app.dSYM/Contents/Resources/DWARF/SuperSDKTest -arch armv7 -l 0x000ef000
0x0010143b
-[ViewController didTriggerClick:] (in SuperSDKTest) (ViewController.m:35)
开发者在具体的运用中,是可以通过编写一个脚本来实现符号化错误地址堆栈的。

address 表示运行时地址、对应崩溃地址堆栈中第一个地址,即0x0004fbed ,实际上,崩溃地址堆栈中+号前后的地址相加即是运行时地址,即0x00048000+ 31720= 0x0004fbed

执行命令查询地址的符号,可以看到如下结果:

编辑:互联网科技 本文来源:崩溃日志分析

关键词: