热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iOSCrash异常日志符号化

异常日志符号化一般情况下如果我们可以通过Xcode来查看异常日志的话,获取到的异常日志都是符号化之后,可以直接查看并定位异常.但是如果在测试阶段需要从

异常日志符号化

一般情况下如果我们可以通过Xcode来查看异常日志的话,获取到的异常日志都是符号化之后,可以直接查看并定位异常.但是如果在测试阶段需要从手机上导出异常日志,或者集成了第三方异常收集但是未能上传符号表到对应的后台等情况下就只能获取到未符号化的异常日志,这时候就需要对异常日志进行符号化.

生成符号表文件的前提


想要进行异常日志的符号化,前提就是保存了打包时生成的.dSYM文件,如果没有保存的话,符号化是不可能了,能靠经验去找了.

  • 在Generate Debug Symbols --> Apple Clang --> Code Generation中,设置Generate Debug Symbols为YES,模式是打开的;
  • 在Build Settings --> Build Options--> Debug Information Format中,将需要产生符号表的模式对应的值设置为DWARF with dsym File,将不需要产生符号表的模式对应值设置为DWARF.默认Debug模式下不产生符号表,Release模式不产生符号表.


符号表的存储位置


在默认情况下,符号表会存储在跟.xcarchive --> dSYMs文件夹下.


异常日志的符号化


准备

  • 新建一个文件夹CrashAnalysis,用来存储需要的文件;
  • 查找symbolicatecrash,并将该工具保存到新创建的文件夹CrashAnalysis中;

Xcode内置了符号化异常日志的工具symbolicatecrash.打开terminal输入下边的指令,通过find命令查找Mac上的symbolicatecrash位置:

find /Applications/Xcode.app -name symbolicatecrash -type f -print | grep iPhoneSimulator

然后将symbolicatecrash复制到CrashAnalysis中.

  • 将异常日志(.crash),符号表(.dSYM),复制到文件夹CrashAnalysis中;

日志符号化

对于异常日志的符号化,分为两种情况进行讨论:

  • 可以获取到完整的.crash系统异常日志,将全部异常日志一次性进行符号化;
  • 不能获取到完整的.crash系统日志(例如自定义异常获取时,只保留了调用堆栈等部分异常信息),只将需要的部分进行符号化.

(1) 将完整的系统异常日志全部符号化

  • 使用dwarfdump命令查看.dSYM文件的UUID;

dwarfdump --uuid xxx.dSYM

  • 查看.crash中的UUID是否与.dSYM中的UUID一致[在Xcode 11.0上发现每次打包会产生三个.dSYM文件,两个文件名以UUID开头,另外一个文件名以工程名开头];
  • 然后使用以下命令符号化日志

./symbolicatecrash xxx.crash xxx.app.dSYM > result.txt

可能会遇到

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

错误提示,如果遇到了,使用

//如果Xcode.app不是默认的名称,修改为自己Xcode名称即可
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

然后再次运行开始的命令,即可得到一个result.txt的符号化文件,在该文件中即可看到符号化之后的异常日志.

(2) 将局部异常日志符号化:

有时候我们并不能获取到完整的crash日志,或者只是想对一部分异常日志进行符号化.这时候也可以使用atos命令来进行.

例如自定义异常捕获方法时,我们只获取到了异常调用堆栈的信息:

0 libsystem_kernel.dylib 0x0000000183d35348 0x183d14000 + 136008
1 libsystem_pthread.dylib 0x0000000183e49354 0x183e46000 + 13140
2 libsystem_c.dylib 0x0000000183ca4fd8 0x183c42000 + 405464
3 libc++abi.dylib 0x0000000183708068 0x183706000 + 8296
4 libc++abi.dylib 0x0000000183708210 0x183706000 + 8720
5 libobjc.A.dylib 0x0000000183730810 0x183728000 + 34832
6 libc++abi.dylib 0x000000018372054c 0x183706000 + 107852
7 libc++abi.dylib 0x00000001837205b8 0x183706000 + 107960
8 libdispatch.dylib 0x0000000183ba105c 0x183ba0000 + 4188
9 libdispatch.dylib 0x0000000183ba86c8 0x183ba0000 + 34504
10 FrontBoardServices 0x00000001868f1a04 0x1868b1000 + 264708
11 FrontBoardServices 0x00000001868f16a8 0x1868b1000 + 263848
12 FrontBoardServices 0x00000001868f1c44 0x1868b1000 + 265284
13 CoreFoundation 0x00000001841c4358 0x1840da000 + 959320
14 CoreFoundation 0x00000001841c42d8 0x1840da000 + 959192
15 CoreFoundation 0x00000001841c3b60 0x1840da000 + 957280
16 CoreFoundation 0x00000001841c1738 0x1840da000 + 948024
17 CoreFoundation 0x00000001840e22d8 0x1840da000 + 33496
18 GraphicsServices 0x0000000185f73f84 0x185f69000 + 44932
19 UIKit 0x000000018d68e880 0x18d61b000 + 473216
20 SymblicateCrashDemo 0x0000000100e77770 0x100e70000 + 30576
21 libdyld.dylib 0x0000000183c0656c 0x183c05000 + 5484

根据异常堆栈的调用信息可以看到,异常日志调用堆栈包含了四列信息:

  • 第一列是调用顺序序号:只不过时机的执行调用顺序是按照序号的逆序相同(栈);
  • 第二列是对应函数所属的Binary Images:包含了系统的库和自定义的库;
  • 第三列是实际调用的函数栈地址:调用的函数在内存中的栈地址(stack address);
  • 第四列是函数栈地址的偏移量表示法:使用函数所在的的Binary Image起始地址+偏移量来表示函数的栈地址.

目之所及,只有调用序号为20的这一行是自己编写代码中的调用,其余的都是系统Binary Image的调用,没有操作权限,所以不是我们关注的信息.

查看出错信息时,使用

atos -o {.dSYM中可执行文件的路径} -l {函数所在Binary Image起始地址} -arch {对应设备使用的指令集} {实际函数栈地址}

对于用例

20 SymblicateCrashDemo 0x0000000100e77770 0x100e70000 + 30576

来说(当前路径是/CrashAnalysis),

  • {.dSYM中可执行文件的路径}:SymblicateCrashDemo.app.dSYM/Contents/Resources/DWARF/SymblicateCrashDemo;
  • {函数所在Binary Image起始地址}:0x100e70000;
  • 所使用测试设备为iPhone XS,所以{对应设备使用的指令集}:arm64(在实际操作中可以获取到当前的设备类型映射到对应的指令集);
  • {实际函数栈地址}:0x0000000100e77770

执行:

atos -o SymblicateCrashDemo.app.dSYM/Contents/Resources/DWARF/SymblicateCrashDemo -l 0x100e70000 -arch arm64 0x0000000100e77770

输出:

__44+[ExceptionHandler registerExceptionHandler]_block_invoke (in SymblicateCrashDemo) (AppDelegate.m:38)

可以知道,出错的代码在Appdelegate实现文件第38行[ExceptionHandler registerExceptionHandler]中.


其他


其实对于局部异常日志符号化,还有一种方法,那就使用 dwarfdump命令,只不过这个命令使用起来比较麻烦.

ASLR (Address space layout randomization):

在iOS中为了防止缓冲区溢出攻击而采用了ASLR技术将可执行文件加载到设备内存.简单来说就是设备每次加载应用可执行文件到内存时,系统都会随机生成一个地址偏移量slide,然后在原来虚拟内存的基础上偏移slide得到得到一个加载可执行文件的起始地址,所以设备每次加载应用的可执行文件到内存的起始地址都是随机的.

在链接时,符号表地址产生了一个实际存储符号的虚拟地址,这个地址存储在应用的可执行文件中,可以使用(mach O文件中load commands中的text段虚拟地址)

otool -arch {设备指令集} -l {应用对应的二进制可执行文件} | grep "segname __TEXT" --after-context=1 | grep "vmaddr"

来进行查看.这个可执行文件在打包时会被存储在符号表的可执行文件中,保存在xxx.app.dSYM/Contents/Resources/DWARF/路径下.

针对用例中:

otool -arch arm64 -l SymblicateCrashDemo.app.dSYM/Contents/Resources/DWARF/SymblicateCrashDemo | grep "segname __TEXT" --after-context=1 | grep "vmaddr"

可以得到:

vmaddr 0x0000000100000000

这个地址就是编译时存储符号表内容的加载地址.

而在设备加载应用可执行文件到内存时会有一个加载起始地址,可以在完整的系统.crash中可以查看(设备加载的第一个Binary Image起始地址):

...
Binary Images:
0x100e70000 - 0x100f53fff SymblicateCrashDemo arm64 <02162b5d77623cd9b937e2633b497b2e> /var/containers/Bundle/Application/0DF5E4BF-6B77-4EC1-982F-1FCC2C2E0642/SymblicateCrashDemo.app/SymblicateCrashDemo
...

所以&#xff0c;有以上两个地址可以得到在加载时产生的随机偏移量slide&#xff1a;

0x100e70000 - 0x0000000100000000 &#61; 0x0000000000e70000

而实际的调用函数地址为0x0000000100e77770&#xff0c;所以可以得到在符号表中的地址&#xff1a;

0x0000000100e77770-0x0000000000e70000 &#61; 0x00000000100007770

上述slide的值也可以在加载时通过代码获取&#xff1a;

//该方法包含在mach-o/dyld.h声明中,使用时需要引入#import
intptr_t slide_address &#61; _dyld_get_image_vmaddr_slide(0);

最后使用&#xff1a;

dwarfdump --arch {设备对应的指令集} --lookup {函数在符号表中的地址} {符号表(.dSYM文件)}

dwarfdump --arch arm64 --lookup 0x00000000100007770 SymblicateCrashDemo.app.dSYM

得到结果&#xff1a;

0x00075e5a: Compile Unit: length &#61; 0x000005a2 version &#61; 0x0004 abbr_offset &#61; 0x0000 addr_size &#61; 0x08 (next unit at 0x00076400)0x00075e65: DW_TAG_compile_unitDW_AT_producer ("Apple clang version 11.0.0 (clang-1100.0.33.8)")DW_AT_language (DW_LANG_ObjC)DW_AT_name ("/Users/ericydong/Desktop/Exercises/CrashDemo/CrashDemo/AppDelegate.m")DW_AT_stmt_list (0x00011e29)DW_AT_comp_dir ("/Users/ericydong/Desktop/Exercises/CrashDemo")DW_AT_GNU_pubnames (true)DW_AT_APPLE_optimized (true)DW_AT_APPLE_major_runtime_vers (0x02)DW_AT_low_pc (0x00000001000076a8)DW_AT_high_pc (0x0000000100007998)0x00075fac: DW_TAG_subprogramDW_AT_low_pc (0x0000000100007708)DW_AT_high_pc (0x000000010000781c)DW_AT_frame_base (DW_OP_reg29 W29)DW_AT_call_all_calls (true)DW_AT_name ("__44&#43;[ExceptionHandler registerExceptionHandler]_block_invoke")DW_AT_decl_file ("/Users/ericydong/Desktop/Exercises/CrashDemo/CrashDemo/AppDelegate.m")DW_AT_decl_line (33)DW_AT_prototyped (true)DW_AT_APPLE_optimized (true)
Line info: file &#39;AppDelegate.m&#39;, line 38, column 39, start line 33

 


推荐阅读
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • MVC设计模式的介绍和演化过程
    本文介绍了MVC设计模式的基本概念和原理,以及在实际项目中的演化过程。通过分离视图、模型和控制器,实现了代码的解耦和重用,提高了项目的可维护性和可扩展性。详细讲解了分离视图、分离模型和分离控制器的具体步骤和规则,以及它们在项目中的应用。同时,还介绍了基础模型的封装和控制器的命名规则。该文章适合对MVC设计模式感兴趣的读者阅读和学习。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • Redis API
    安装启动最简启动命令行输入验证动态参数启动配置文件启动常用配置通用命令keysbdsize计算key的总数exists判断是否存在delkeyvalue删除指定的keyvalue成 ... [详细]
  • 本文介绍了使用readlink命令获取文件的完整路径的简单方法,并提供了一个示例命令来打印文件的完整路径。共有28种解决方案可供选择。 ... [详细]
  • 面试经验分享:华为面试四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试
    最近有朋友去华为面试,面试经历包括四轮电话面试、一轮笔试、一轮主管视频面试、一轮hr视频面试。80%的人都在第一轮电话面试中失败,因为缺乏基础知识。面试问题涉及 ... [详细]
  • 本文详细介绍了在Linux虚拟化部署中进行VLAN配置的方法。首先要确认Linux系统内核是否已经支持VLAN功能,然后配置物理网卡、子网卡和虚拟VLAN网卡的关系。接着介绍了在Linux配置VLAN Trunk的步骤,包括将物理网卡添加到VLAN、检查添加的VLAN虚拟网卡信息以及重启网络服务等。最后,通过验证连通性来确认配置是否成功。 ... [详细]
author-avatar
Opera2502898747
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有