首页 > 技术文章 > 写一个自动解析 ios crash 日志的脚本(python)

shanshan-test 2021-03-11 23:36 原文

符号表是什么

  • 符号表就是指在Xcode项目编译后,在编译生成的二进制文件.app的同级目录下生成的同名的.dSYM文件。
    .dSYM文件其实是一个目录,在子目录中包含了一个16进制的保存函数地址映射信息的中转文件,所有Debug的symbols都在这个文件中(包括文件名、函数名、行号等),所以也称之为调试符号信息文件。
    一般地,Xcode项目每次编译后,都会生成一个新的.dSYM文件。因此,App的每一个发布版本,都需要备份一个对应的.dSYM文件,以便后续调试定位问题。

符号表的作用

  • 在Xcode开发调试App时,一旦遇到崩溃问题,开发者可以直接使用Xcode的调试器定位分析。
    但如果App发布上线,开发者不可能进行调试,只能通过分析系统记录的崩溃日志来定位问题,在这份崩溃日志文件中,会指出App出错的函数内存地址,而这些函数地址是可以在.dSYM文件中找到具体的文件名、函数名和行号信息的。

atos工具(可以把地址转换为函数名(包括行号))

atos [-arch 架构名] [-o 符号表] [-l 模块地址] [方法地址]
  • 架构名:可以是 armv6,armv7,armv7s。可以参考:https://www.jianshu.com/p/f9eeeecff8d8,大佬们在一起收集哦
  • 模块地址: 表示函数的动态加载地址,对应崩溃地址堆栈中 + 号前面的地址,即0x000ef000
  • 方法地址: 表示运行时地址、对应崩溃地址堆栈中第一个地址,即0x0010143b
  • 符号表:XXX.app.dSYM/Contents/Resources/DWARF/XXX 这里的 XXX 就是你的 appName

来编写我们的自动解析脚本吧

import os
import sys
import time

default_appName = "/Contents/Resources/DWARF/CCTVVideo"


def atos(dsym_dir_path, crash_file_path, arm_str="arm64"):
    """
    自动解析ios crash日志
    :param dsym_dir_path:
    :param crash_file_path:
    :param arm_str:
    :return:
    """
    dsym_dir_path = dsym_dir_path + default_appName
    str_time = time.strftime('%Y-%m-%d_%H:%M:%S', time.localtime(time.time()))
    # 读取 crash 文件,正常写入到result中,如果遇到需要解析的堆栈,需要解析后,将解析后的内容再写到result文件中
    with open(crash_file_path, 'r')as fr:
        for i in fr:
            list_i = i.split()
            with open(str(str_time) + "result.crash", 'a+')as fw:
                # 判断有加号,而且分割后第三个元素和第四个元素是 0x 开头
                if "+" in i and list_i[2].startswith("0x") and list_i[3].startswith("0x"):
                    atos_result = os.popen(
                        f"atos -arch {arm_str} -o {dsym_dir_path} -l {list_i[3]} {list_i[2]}").read()
                    new_line_list = str(i.split('0x')[0]) + str(atos_result)
                    fw.write(new_line_list)
                else:
                    fw.write(i)


def check_params():
    "注意:堆栈信息的文件名不要有空格"
    try:
        assert sys.argv[1].endswith(".app.dSYM")  # 判断是否是符号表
        assert os.access(sys.argv[2], os.R_OK)  # 判断是否可读
        if len(sys.argv) == 3:
            atos(sys.argv[1], sys.argv[2])
        elif len(sys.argv) == 4:
            atos(sys.argv[1], sys.argv[2], arm_str=sys.argv[3])
    except Exception as e:
        print(e.args)


if __name__ == '__main__':
    # dsym_dir_path = sys.argv[1]  # .app.dSYM符号表的文件路径
    # crash_file_path = sys.argv[2]  # crash文件路径(可以是导出的 crash 文件路径,也可是待解析的原始堆栈)
    # arm_str = sys.argv[3]  # 架构名
    check_params()

git地址

https://github.com/shishanshanTest/AtosCrash.git

推荐阅读