热门标签 | 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

 


推荐阅读
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
  • 为了确保iOS应用能够安全地访问网站数据,本文介绍了如何在Nginx服务器上轻松配置CertBot以实现SSL证书的自动化管理。通过这一过程,可以确保应用始终使用HTTPS协议,从而提升数据传输的安全性和可靠性。文章详细阐述了配置步骤和常见问题的解决方法,帮助读者快速上手并成功部署SSL证书。 ... [详细]
  • 在多堆石子游戏中,通过分析Nim博弈策略,探讨了如何在限定时间和内存条件下实现最优解。本文详细研究了石子游戏中的数学原理和算法优化方法,旨在为参与者提供有效的策略指导。具体而言,文章讨论了不同堆数下的Nim值计算及其应用,帮助玩家在复杂的博弈环境中取得优势。 ... [详细]
  • iOS开发中常用的设备标识符(IDFA、IDFV、MAC地址、UDID、openUDID)及其应用场景
    在iOS开发过程中,了解并合理使用各种设备标识符对于数据统计和用户分析至关重要。本文详细介绍了几种常用的设备标识符及其应用场景:IDFA(广告标识符)用于广告追踪和归因;IDFV(供应商标识符)适用于同一应用或同一开发者旗下的应用内识别用户;MAC地址和UDID(唯一设备标识符)虽然已被弃用,但在某些历史场景下仍有参考价值;而openUDID作为一种开源解决方案,提供了一种替代UDID的方法。这些标识符各有特点,开发者应根据具体需求选择合适的标识符。 ... [详细]
  • WinMain 函数详解及示例
    本文详细介绍了 WinMain 函数的参数及其用途,并提供了一个具体的示例代码来解析 WinMain 函数的实现。 ... [详细]
  • 解决问题:1、批量读取点云las数据2、点云数据读与写出3、csf滤波分类参考:https:github.comsuyunzzzCSF论文题目ÿ ... [详细]
  • 在软件开发过程中,经常需要将多个项目或模块进行集成和调试,尤其是当项目依赖于第三方开源库(如Cordova、CocoaPods)时。本文介绍了如何在Xcode中高效地进行多项目联合调试,分享了一些实用的技巧和最佳实践,帮助开发者解决常见的调试难题,提高开发效率。 ... [详细]
  • 本项目通过Python编程实现了一个简单的汇率转换器v1.02。主要内容包括:1. Python的基本语法元素:(1)缩进:用于表示代码的层次结构,是Python中定义程序框架的唯一方式;(2)注释:提供开发者说明信息,不参与实际运行,通常每个代码块添加一个注释;(3)常量和变量:用于存储和操作数据,是程序执行过程中的重要组成部分。此外,项目还涉及了函数定义、用户输入处理和异常捕获等高级特性,以确保程序的健壮性和易用性。 ... [详细]
  • 基于Net Core 3.0与Web API的前后端分离开发:Vue.js在前端的应用
    本文介绍了如何使用Net Core 3.0和Web API进行前后端分离开发,并重点探讨了Vue.js在前端的应用。后端采用MySQL数据库和EF Core框架进行数据操作,开发环境为Windows 10和Visual Studio 2019,MySQL服务器版本为8.0.16。文章详细描述了API项目的创建过程、启动步骤以及必要的插件安装,为开发者提供了一套完整的开发指南。 ... [详细]
  • 在C#编程中,数值结果的格式化展示是提高代码可读性和用户体验的重要手段。本文探讨了多种格式化方法和技巧,如使用格式说明符、自定义格式字符串等,以实现对数值结果的精确控制。通过实例演示,展示了如何灵活运用这些技术来满足不同的展示需求。 ... [详细]
  • 在《ChartData类详解》一文中,我们将深入探讨 MPAndroidChart 中的 ChartData 类。本文将详细介绍如何设置图表颜色(Setting Colors)以及如何格式化数据值(Formatting Data Values),通过 ValueFormatter 的使用来提升图表的可读性和美观度。此外,我们还将介绍一些高级配置选项,帮助开发者更好地定制和优化图表展示效果。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 本文详细介绍了Oracle数据库中的表空间及其分区技术。表空间作为Oracle数据库的一个逻辑单元,每个数据库可包含一个或多个表空间,每个表空间则关联一个或多个数据文件。通过合理的表空间管理和分区策略,可以显著提升数据库的性能和管理效率。文章还总结了实际应用中的最佳实践,为读者提供了宝贵的参考。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
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社区 版权所有