美文网首页
Crash 捕获及堆栈符号化思路

Crash 捕获及堆栈符号化思路

作者: 小凡凡520 | 来源:发表于2018-11-29 09:50 被阅读19次
崩溃捕获

崩溃主要是由于 Mach 异常、Objective-C 异常(NSException)引起的,同时对于 Mach 异常,到了 BSD 层会转换为对应的 Signal 信号,那么我们也可以通过捕获信号,来捕获 Crash 事件。针对 NSException 可以通过注册 NSUncaughtExceptionHandler 捕获异常信息

冲突

在我们自己研发 Crash 收集框架之前,最早肯定都会接入网易云捕、腾讯 Bugly、Fabric 等第三方日志框架来进行崩溃的收集和分析。如果多个 Crash 收集框架存在时,往往会存在冲突

不管是对于 Signal 捕获还是 NSException 捕获都会存在 handler 覆盖的问题,正确的做法应该是先判断是否有前者已经注册了 handler,如果有则应该把这个 handler 保存下来,在自己处理完自己的 handler 之后,再把这个 handler 抛出去,供前面的注册者处理

堆栈收集

你可以直接用系统的方法获取当前线程堆栈,也可以使用 PLCrashRepoter 获取所有线程堆栈

堆栈符号解析
堆栈符号化还原有四种常见的方法
1.symbolicatecrash
2.mac 下的 atos 工具
3.linux 下的 atos 的替代品 [atosl](https://link.jianshu.com?t=https://github.com/facebookarchive/atosl)
4.通过 dSYM 文件提取地址和符号的对应关系,进行符号还原

以上方案都有对应的应用场景,对于线上的 Crash 堆栈符号还原,主要采用的还是后三种方案。atos 和 atosl 的使用方法很类似,以下是 atos 的一个示例

atos -o MonitorExample 0x0000000100062ac4  ARM-64 -l 0x100058000

// 还原结果
-[GYRootViewController tableView:cellForRowAtIndexPath:] (in GYMonitorExample) (GYRootViewController.m:41)

使用第四个方案,提取 dSYM 的符号表,可以自己研发工具,也可以直接使用 bugly 和 网易云捕提供的工具,下面是提取出来的符号表。第一列是起始内存地址,第二列是结束地址,第三列是对应的函数名、文件名以及行号

a840    a854    -[GYRootViewController tableView:cellForRowAtIndexPath:] GYRootViewController.m:41
a854    a858    -[GYRootViewController tableView:cellForRowAtIndexPath:] GYRootViewController.m:42
a858    a87c    -[GYRootViewController tableView:cellForRowAtIndexPath:] GYRootViewController.m:42
a87c    a894    -[GYRootViewController tableView:cellForRowAtIndexPath:] GYRootViewController.m:42
a894    a8a0    -[GYRootViewController tableView:cellForRowAtIndexPath:] GYRootViewController.m:42
aa3c    aa80    -[GYFilePreviewViewController initWithFilePath:] GYRootViewController.m:21
aa80    aaa8    -[GYFilePreviewViewController initWithFilePath:] GYFilePreviewViewController.m:23
aaa8    aab8    -[GYFilePreviewViewController initWithFilePath:] GYFilePreviewViewController.m:23
aab8    aabc    -[GYFilePreviewViewController initWithFilePath:] GYFilePreviewViewController.m:24
aabc    aac8    -[GYFilePreviewViewController initWithFilePath:] GYFilePreviewViewController.m:24

因为程序每次启动基地址都会变化,所以上面提到的地址是相对偏移地址,在我们获取到崩溃堆栈地址后,可以根据堆栈中的偏移地址来与符号表中的地址来做匹配,进而找到堆栈所对应的函数符号。比如下面的第四行,偏移为 43072 转换为十六进制就是 a840,用 a840 去上面的符号表中找对应关系,会发现对应着 -[GYRootViewController tableView:cellForRowAtIndexPath:],基于这种方式,就可以将堆栈地址完全还原为函数符号啦

UUID

我们的应用存在多个版本,并且支持多种不同的架构,那么如何找到与崩溃日志对应的符号表呢?就是依靠 UUID,只有当崩溃日志的 UUID 与 dSYM 的 UUID 一致时,才能得到正确的解析结果

dSYM 的 UUID 获取方法

xcrun dwarfdump --uuid <dSYM文件>

应用内获取 UUID 的方法

#import <mach-o/ldsyms.h>

NSString *executableUUID()
{
    const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1);
    for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) {
        if (((const struct load_command *)command)->cmd == LC_UUID) {
            command += sizeof(struct load_command);
            return [NSString stringWithFormat:@"%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
                    command[0], command[1], command[2], command[3],
                    command[4], command[5],
                    command[6], command[7],
                    command[8], command[9],
                    command[10], command[11], command[12], command[13], command[14], command[15]];
        } else {
            command += ((const struct load_command *)command)->cmdsize;
        }
    }
    return nil;
    }
系统库符号化

上面只是提取到了我们应用中 dSYM 中的符号表,对于系统库还是无能为力的,比如 UIKit 就没有办法将其地址符号化,想要将动态库符号化,需要先获取系统库的符号文件。提取系统符号文件可以从 iOS 固件中获取,也可以从 Github 上开源项目中找到对应系统的符号文件

相关文章

  • iOS Crash 流程化0:概览

    Ref:iOS Crash 捕获及堆栈符号化思路剖析 iOS Crash 流程化:概览崩溃捕获Mach 异常捕获U...

  • Crash 捕获及堆栈符号化思路

    崩溃捕获 崩溃主要是由于 Mach 异常、Objective-C 异常(NSException)引起的,同时对于 ...

  • iOS Crash 捕获及堆栈符号化思路剖析

    最近在做 Crash 分析方面的工作,发现 iOS 的崩溃捕获和堆栈符号化虽然已经有很多资料可以参考,但是没有比较...

  • crash文件符号化攻略

    根据 .crash文件符号化堆栈信息,这个操作你可能并不陌生,详细可以看.crash文件符号化 下面?总结一下主要...

  • iOS Crash问题

    本文就捕获iOS Crash、Crash日志组成、Crash日志符号化、异常信息解读、常见的Crash五部分介绍。...

  • iOS 应用质量监控方案选型报告

    期望: 捕获线上crash日志实时上传,提供crash堆栈可视化分析,以及对卡顿,电量,内存,场景切换及影响用户数...

  • iOS实现Crash捕获与堆栈符号化

    在应用程序开发过程中,最棘手的问题莫过于crash。已经上线的crash无法看到崩溃现场,只能通过crash日志进...

  • iOS Crash从捕获到符号化解析分析

    目的 探索iOS Crash分类及捕获流程 了解Crash文件结构及段含义 了解Mach-o文件结构 分析Cras...

  • iOS闪退监控方案

    实现方案 基本思路:日志捕获采用 KSCrash,捕获的日志上传服务器,然后在服务器对日志进行符号化。 KSCra...

  • crash捕获及处理

    一、crash类型 1.OC层面的crash 1.1 普通类型 NSArray 越界 NSCache key或va...

网友评论

      本文标题:Crash 捕获及堆栈符号化思路

      本文链接:https://www.haomeiwen.com/subject/urlxcqtx.html