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:  0Last Exception Backtrace:
(0x186e9de48 0x1975dc0e4 0x186d83a54 0x10000c00c 0x10000bf7c 0x18b6810f8 0x18b66a22c 0x18b680a94 0x18b680720 0x18b679c74 0x18b64d38c 0x18b8ec1b4 0x18b64b8f4 0x186e560e8 0x186e5538c 0x186e5343c 0x186d811f4 0x18ff0f5a4 0x18b6b2784 0x10000c574 0x197c4aa08)Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib            0x0000000197d63270 0x197d48000 + 111216
1   libsystem_pthread.dylib           0x0000000197e01224 0x197dfc000 + 21028
2   libsystem_c.dylib                 0x0000000197cdab14 0x197c78000 + 404244
3   libc++abi.dylib                   0x0000000196dad414 0x196dac000 + 5140
4   libc++abi.dylib                   0x0000000196dccb88 0x196dac000 + 134024
5   libobjc.A.dylib                   0x00000001975dc3bc 0x1975d4000 + 33724
6   libc++abi.dylib                   0x0000000196dc9bb0 0x196dac000 + 121776
7   libc++abi.dylib                   0x0000000196dc9738 0x196dac000 + 120632
8   libobjc.A.dylib                   0x00000001975dc290 0x1975d4000 + 33424
9   CoreFoundation                    0x0000000186d812a0 0x186d78000 + 37536
10  GraphicsServices                  0x000000018ff0f5a0 0x18ff04000 + 46496
11  UIKit                             0x000000018b6b2780 0x18b63c000 + 485248
12  CrashTest                         0x000000010000c570 0x100004000 + 34160
13  libdyld.dylib                     0x0000000197c4aa04 0x197c48000 + 10756

没有关系,其实和上面是一样的,我们来找找基址和偏移

往下找到 Binary Images段,这里显示的就是崩溃程序当时加载的所有库的快照

Binary Images:
0x100004000 - 0x10000ffff CrashTest arm64  <5fc8820b297631d087e5e665b261ed0c> /var/mobile/Containers/Bundle/Application/D8F09771-5B65-4403-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) + 64
-[ViewController crashOnFunc:] (in CrashTest-symbol) + 44

至此,完成了解析。

本篇涉及的崩溃是普通函数中的崩溃,如果崩溃发生在block中,则需要借住反编译工具,请参考 恢复二进制文件中的block符号表

PS:再多说一点,上面的解析输出我们看到在函数后面有一个 + 64, 这个+ 64、+ 44是什么意思呢,我开始也不太明白,仔细观察Hopper/IDA解析出来的的汇编代码,才明白原来这也是个偏移,是指调用地址相对于函数的起始地址的偏移,并非.m文件中的代码行数。

附件:

本篇使用的DEMO

参考 & 感谢

  杨君的小黑屋 http://blog.imjun.net/posts/restore-symbol-of-iOS-app/

  

iOS-详解没有dSYM文件 如何解析iOS崩溃日志相关推荐

  1. 技术揭秘之详解回收站删除文件恢复

    |=------------------------------------------------------------------------=| |=--------------=[技术揭秘之 ...

  2. vue单文件props写法_详解Vue 单文件组件的三种写法

    详解Vue 单文件组件的三种写法 JS构造选项写法 export defaul { data, methods, ...} JS class写法 @Component export default c ...

  3. 详解HTTP的文件上传全过程(RFC1867协议)

    详解HTTP的文件上传全过程:RFC1867协议 HTTP请求头 HTTP请求体 什么是 multipart/form-data 上传文件信息的内容组成 原生Node实现客户端上传文件 原生Golan ...

  4. FreeMarker基本语法详解及模板文件的组成(二)

    海浪上次给大家分享了FreeMarker基本语法详解及模板文件的组成(一)海浪今天继续分享FreeMarker基本语法详解及模板文件的组成(二) 3.2 输出变量值<?xml:namespace ...

  5. python怎么导入文件-Python文件如何引入?详解引入Python文件步骤

    python基本语法--引入Python文件 1.新建python文件 :在同目录lib下创建mylib.py和loadlib.py两个文件 2.在mylib.py文件中创建一个Hello的类 并且给 ...

  6. linux rm命令参数及用法详解---linux删除文件或目录命令

    http://www.linuxso.com/command/rm.html linux下rm命令使用详解---linux删除文件或目录命令 用户可以用rm命令删除不需要的文件.该命令的功能为删除一个 ...

  7. python怎么读写文件-手机上怎么写pythonPython文件读写详解及设置文件的字符编码...

    文件读写操作在各种编程语言中都是比较重要的部分,也是很常用的部分,今天就来详细说一下python对文件的读写操作,以及需要注意的点. 一. python打开文件 代码如下:f = open(" ...

  8. 详解DNS服务、DNS解析、DNS劫持和污染

    简介 DNS(全称:Domain Name System,中文:域名系统)是互联网的一项服务.它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网.1 前言 要想弄清楚 D ...

  9. 【Android NDK 开发】NDK C/C++ 代码崩溃调试 - Tombstone 报错信息日志文件分析 ( 获取 tombstone_0X 崩溃日志信息 )

    文章目录 一.崩溃信息描述 二.手机命令行操作 三.电脑命令行操作 四.Tombstone 内容 Tombstone 报错信息日志文件被保存在了 /data/tombstones/ 目录下 , 先 R ...

  10. DTS文件详解,DTS文件解析

    一.什么是DTS?为什么要引入DTS? DTS即Device Tree Source 设备树源码, Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF). 在L ...

最新文章

  1. 我在兰亭这三年之我接触的郭去疾
  2. 网络电视视频服务器所放位置,pptv网络电视中多屏互动服务器删除的具体操作步骤...
  3. (~最新合集~)计算机网络谢希仁第七版 第五章课后答案
  4. CG-CTF-Web-单身一百年
  5. SkyWalking学习笔记(CentOS环境)
  6. 五子棋c语言算杀算法,c语言 五子棋危险判断 求大神解释啊
  7. Java从入门到精通 第23章 文件IO操作
  8. 商城开发-用户管理模块(2)
  9. matlab按图像边缘抠图_Adobe Photoshop入门教程:零基础学会PS抠图拼贴
  10. 【#1】小甲鱼新版python学习笔记
  11. 3-11 查询水果价格
  12. CSS改变table内置tbody滚动条
  13. 2 创造你的物理世界(1)
  14. Excel表格多个工作表数据汇总求和
  15. 容器服务ACK+容器网络文件系统CNFS快速搭建NGINX网站(体验有礼)
  16. 12星座大全 ^__^
  17. 星星之火-36:LTE载波载波的间隔是15K, 载波波的带宽是多少? 15K还是30K?
  18. 《程序员的修炼之道——从小工到专家》读书笔记
  19. python邮箱爆破_企业邮箱爆破脚本
  20. pycharm运行os.system出现�����ڲ����ⲿ���Ҳ���ǿ����еij��� ���������ļ���

热门文章

  1. Python中的 SciPy 样条曲线插值
  2. 即拿即用-Android单线程断点下载
  3. android 模拟 ns手柄,Joy-Con Droid可将Android智能机变身为任天堂Switch的手柄
  4. opmanager邮件告警配置
  5. linux运行海康,海康摄像头SDK在Linux、windows下的兼容问题(二)已解决
  6. LeetCode周赛
  7. 交叉编译工具链的安装和配置过程
  8. ESP8266学习笔记(7)——JSON接口使用
  9. 计算机网络实验(二)2交换机的基本配置与管理
  10. 资源共享——《嵌入式Linux应用开发完全手册》韦东山 PDF电子档下载