详解没有dSYM文件 如何解析iOS崩溃日志
Xcode支持崩溃日志自动符号化,前提是本地有当时Build/Archive生成的dSYM文件,iOS崩溃日志符号化后,可以帮助开发者更好的定位问题,但如果dSYM文件丢失或拿到的崩溃日志不是标准的crash log,如何定位crash呢,笔者结过尝试发现一样可以定位到具体函数。
在无dSYM文件情况下,之所以无法解析出崩溃地址对应的函数名,是因为Xcode在导出ipa时会去除Symbol Table(符号表)的非系统符号部分。这时address无法对应函数名,所以无法确定是在哪个函数或block中出了问题。因此解析日志的关键是要恢复符号表,国内已有大神做过研究 杨君的小黑屋,本文基于此完成解析目标。
我们以测试程序CrashTest的崩溃为例,介绍一下具体解析步骤
如图,

我们拿到了崩溃日志,这是一个arm64架构的崩溃日志,从最后的backtrace我们知道程序在访问数组元素时异常终止,但由于本地没有对应的dSYM文件,Xcode没有将红框内3,4两行符号化为具体的函数名,本文的工作就是要将这2行符号化
开始之前,先解释一下这几行地址的含义

栈:左边这一列是崩溃时的调用栈地址(虚拟内存地址)
基址:基址指向的地址是CrashTest这个模块加载到内存中的起始地址
偏移:左边栈地址 = 基址 + 偏移 (注意是10进制的)
什么?你拿到的崩溃日志不是这样的! (老司机请绕过)
像这样,只有一堆地址
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: Last Exception Backtrace:
(0x186e9de48 0x1975dc0e4 0x186d83a54 0x10000c00c 0x10000bf7c 0x18b6810f8 0x18b66a22c 0x18b680a94 0x18b680720 0x18b679c74 0x18b64d38c 0x18b8ec1b4 0x18b64b8f4 0x186e560e8 0x186e5538c 0x186e5343c 0x186d811f4 0x18ff0f5a4 0x18b6b2784 0x10000c574 0x197c4aa08) Thread name: Dispatch queue: com.apple.main-thread
Thread Crashed:
libsystem_kernel.dylib 0x0000000197d63270 0x197d48000 +
libsystem_pthread.dylib 0x0000000197e01224 0x197dfc000 +
libsystem_c.dylib 0x0000000197cdab14 0x197c78000 +
libc++abi.dylib 0x0000000196dad414 0x196dac000 +
libc++abi.dylib 0x0000000196dccb88 0x196dac000 +
libobjc.A.dylib 0x00000001975dc3bc 0x1975d4000 +
libc++abi.dylib 0x0000000196dc9bb0 0x196dac000 +
libc++abi.dylib 0x0000000196dc9738 0x196dac000 +
libobjc.A.dylib 0x00000001975dc290 0x1975d4000 +
CoreFoundation 0x0000000186d812a0 0x186d78000 +
GraphicsServices 0x000000018ff0f5a0 0x18ff04000 +
UIKit 0x000000018b6b2780 0x18b63c000 +
CrashTest 0x000000010000c570 0x100004000 +
libdyld.dylib 0x0000000197c4aa04 0x197c48000 +
没有关系,其实和上面是一样的,我们来找找基址和偏移
往下找到 Binary Images段,这里显示的就是崩溃程序当时加载的所有库的快照
Binary Images:
0x100004000 - 0x10000ffff CrashTest arm64 <5fc8820b297631d087e5e665b261ed0c> /var/mobile/Containers/Bundle/Application/D8F09771-5B65--A19C-CE77DAF32623/CrashTest.app/CrashTest // 这里第一行便是我们要找的
0x120070000 - 0x120097fff dyld arm64 <f958ba064181388a9658f927da42e9e7> /usr/lib/dyld
0x185678000 - 0x18580bfff AVFoundation arm64 <0c542593e3613f82b7e860cb5beeeed6> /System/Library/Frameworks/AVFoundation.framework/AVFoundation
0x18580c000 - 0x185870fff libAVFAudio.dylib arm64 <c9d296cb28c73570aaf8355b05f1adee> /System/Library/Frameworks/AVFoundation.framework/libAVFAudio.dylib
0x1858b4000 - 0x1858b4fff Accelerate arm64 <e9ba7838f51634a7b59ed392be50e86f> /System/Library/Frameworks/Accelerate.framework/Accelerate
0x1858cc000 - 0x185aebfff vImage arm64 <da44067fc79931c7aef1b7e88bf82a83> /System/Library/Frameworks/Accelerate.framework/Frameworks/vImage.framework/vImage
0x185aec000 - 0x185b93fff libBLAS.dylib arm64 <e5276e7784ef34a4baca480264978ea0> /System/Library/Frameworks/Accelerate.framework/Frameworks/vecLib.framework/libBLAS.dylib
然后找到我们的应用 CrashTest
0x100004000 - 0x10000ffff CrashTest arm64 <5fc8820b297631d087e5e665b261ed0c> /var/mobile/Containers/Bundle/Application/D8F09771-5B65-4403-A19C-CE77DAF32623/CrashTest.app/CrashTest
我们看到行首有个地址区间 0x100004000 - 0x10000ffff , 这便是崩溃程序的内存区,起始地址(基址)为 0x100004000,OK基址找到了。
然后我们再看看崩溃时的栈
Last Exception Backtrace:
(0x186e9de48 0x1975dc0e4 0x186d83a54 0x10000c00c 0x10000bf7c 0x18b6810f8 0x18b66a22c 0x18b680a94 0x18b680720 0x18b679c74 0x18b64d38c 0x18b8ec1b4 0x18b64b8f4 0x186e560e8 0x186e5538c 0x186e5343c 0x186d811f4 0x18ff0f5a4 0x18b6b2784 0x10000c574 0x197c4aa08)
其中位于地址区间 0x100004000 - 0x10000ffff 的,有2个 0x10000c00c 0x10000bf7c,这就是崩溃程序的调用栈,其余地址为系统库函数调用栈。
OK开始动手
1. 下载符号恢复工具
修改权限
chmod a+x restore-symbol
2. 恢复符号
我们拿到的崩溃日志来自arm64机器,所以先将二进制文件 CrashTest.app/CrashTest 瘦身 (必须正确选择目标CPU架构类型,否则解析出来也是错的)
lipo -thin arm64 CrashTest -output CrashTest-arm64
接着用工具恢复符号表
./restore-symbol -o CrashTest-symbol CrashTest-arm64
现在我们得到了一个恢复了符号表的二时制文件 CrashTest-symbol
3. 使用苹果自带命令行工具atos,将崩溃地址解析成具体函数
atos -arch arm64 -o CrashTest-symbol -l 0x100030000 0x100034340 0x1000342b0
# 简单解释一下这个命令,atos -arch CPU架构 -o 进制文件 -l 起始地址 ...一系列内存地址
# -l 后面跟的是模块的起始地址,再后面可以罗列很多地址,该命令会依次解析出具体函数
得到如下输出
-[ViewController getChild:] (in CrashTest-symbol) +
-[ViewController crashOnFunc:] (in CrashTest-symbol) +
至此,完成了解析。
本篇涉及的崩溃是普通函数中的崩溃,如果崩溃发生在block中,则需要借住反编译工具,请参考 恢复二进制文件中的block符号表
PS:再多说一点,上面的解析输出我们看到在函数后面有一个 + 64, 这个+ 64、+ 44是什么意思呢,我开始也不太明白,仔细观察Hopper/IDA解析出来的的汇编代码,才明白原来这也是个偏移,是指调用地址相对于函数的起始地址的偏移,并非.m文件中的代码行数。
PS2: 当然还有更直接的方法,用Hopper打开二进制文件,然后根据崩溃偏移量,直接定位到汇编代码
详解没有dSYM文件 如何解析iOS崩溃日志的更多相关文章
- iOS崩溃日志ips文件解析
iOS崩溃日志ips文件解析 一 简介 测试组的同事在进行稳定性测试时,通常会遇到一些崩溃,然后他们会将这些崩溃日志(一般是ips格式的文件)反馈给开发进行分析,但是这些ips文件中的内容通常是如下 ...
- SpringBoot Profile使用详解及配置源码解析
在实践的过程中我们经常会遇到不同的环境需要不同配置文件的情况,如果每换一个环境重新修改配置文件或重新打包一次会比较麻烦,Spring Boot为此提供了Profile配置来解决此问题. Profile ...
- Spring配置文件详解 – applicationContext.xml文件路径
Spring配置文件详解 – applicationContext.xml文件路径 Java编程 spring的配置文件applicationContext.xml的默 ...
- iOS 崩溃日志分析(个人总结,最实用)
iOS 崩溃日志分析(个人总结,最实用) 要分析奔溃日志需要三个文件:crash日志,symbolicatecrash分析工具,.dSYM符号集 0. 在桌面创建一个crash文件夹 1. 需要Xco ...
- 常用获取Android崩溃日志和IOS崩溃日志的几种方法
一:前言 在日常测试app时,经常会遇到崩溃问题,测试快速抓取到崩溃日志可以有效方便开发进行定位,快速解决问题所在测试做到测试分析,定位是非常重要的,这也是判断一个测试能力指标的一大维度. 二:And ...
- iOS崩溃日志
今天看crash report ,有这样两个crash: 调用 stopUpdatingLocation 函数的是一个CLLocationManager 类型的对象,为什么报错的时候会把这个对象转成N ...
- extern的使用详解(多文件编程)——C语言
extern——关键字 extern是C语言中的一个关键字,一般用在变量名前或函数名前,作用是用来说明“此变量/函数是在别处定义的,要在此处引用”,extern这个关键字大部分读者应该是在变量的存储类 ...
- 如何看iOS崩溃日志
重点:Triggered by Thread这句话后边的线程号,快速定位问题出现在那个线程,是否是你的锅:Triggered by Thread所指的线程表示导致异常.崩溃的线程 下边内容转自简书 简 ...
- iOS 崩溃日志 Backtrace的符号化
iOS的崩溃日志配合dsym文件可以找到崩溃时的backtrace,这是解决崩溃的最重要的信息. 如果是在同一台mac上打包, 导入crash log时候会自动将backtrace符号化,可以看到方法 ...
随机推荐
- 给定一个整数,求解该整数最少能用多少个Fib数字相加得到
一,问题描述 给定一个整数N,求解该整数最少能用多少个Fib数字相加得到 Fib数列,就是如: 1,1,2,3,5,8,13.... Fib数列,满足条件:Fib(n)=Fib(n-1)+Fib(n- ...
- charles https抓包 (安卓安装证书)
的Android APP使用的都是http请求,之后改成了https,就出现了以下情况,无法正常读取抓取的内容 下面阐述一下,正确的安装步骤,为出现类似情况的朋友提供一个参考: 1.第一步: 最后点击 ...
- 针对Jigsaw勒索软件的解锁工具
针对Jigsaw勒索软件的解锁工具 据了解, 用户的计算机系统一旦感染了勒索软件Jigsaw,如果用户没有在一个小时之内支付赎金(0.4个比特币,价值约为150美金),那么恶意软件将会把系统中的上千份 ...
- keepalived启动不成功,状态一直是inactive(dead) 的解决办法以及keepalived高版本没有rc.d目录,虚拟VIP无法访问问题
安装配置教程我就不说了,网上很多,这里只给出我遇到的两个坑: 1 rc.d目录 ,kp在1.4版本之后rc.d要去解压之后的源码包里去找,make之后的目录里面没有了,我使用的是2.0.13最新版本, ...
- MySQL binlog导入失败
一个同事问我,说他用innobackupex恢复数据后用mysqlbinlog导入增量数据时,发现数据没有导入进去并且也没有报错. mysqlbinlog /u01/mysql_py/database ...
- Spring bean 配置
1.传统的创建对象的方式:JedisMall tardition=new JedisMall(); 这样是在程序运行时创建,表示当前模块已经不知不觉和new出的对象耦合了,而我们通常都是更高层次的抽象 ...
- Densenet-Tensorflow
在寻找densnet网络的时候,我发现了一个结构清晰完整的网络代码,在此作备份. https://github.com/taki0112/Densenet-Tensorflow Densenet-Te ...
- Archlinux系统配置学习笔记(一)
本文档是有关Archlinux系统配置的学习笔记,参考和学习的是Archlinux官方网站上的相应文档:General Recommendations. 这里的配置主要是针对按照官方网站上的文档刚刚完 ...
- hdu 5427(排序水题)
排序 年轻的排前面 名字中可能有空格 Sample Input21FancyCoder 19962FancyCoder 1996xyz111 1997 Sample OutputFancyCoderx ...
- 解决连不上dl.google.com和dl-ssl.google.com
http://ping.chinaz.com/ 开发android遇到的最大问题就是Google被墙了,而我们的sdk又需要通过dl.google.com和dl-ssl.google.com去下载一些 ...