网络知识 娱乐 还原iOS的Crash日志中的符号表

还原iOS的Crash日志中的符号表

获取crash日志一般有两种:

  1. iphone 手机自动收集的.crash 会存储在手机上,通过Xcode 可以导出来。

  2. Mac控制台等其他工具抓取到的 crash日志。

1. 在iphone 手机自动收集的crash,可以通过Xcode 上的工具导出xxx.crash文件

使用xcode 自带的symbolicatecrash命令就可以复原

操作如下:
将“.dSYM”和 “.crash”文件放到同一个目录下,终端设置如下环境:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

然后

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash appName.crash > appName.log

就好了

2. 其他形式的控制台的crash堆栈日志如下

在这里插入图片描述

这个时候,我们就需要手动来还原这个符号表了。

mac 自带了atos 命令可以还原符号地址,这个命令的使用参数:

atos -arch  -o /Contents/Resources/DWARF/ -l  
  • Binary Architecture: arm64、armv6、armv7 armv7s 根据自己的情况来写。

  • Path to dSYM file: dSYM文件的路径。

  • binary image name: 你工程的名字。

  • load address: 是运行时起始地址(基地址),如果我们的崩溃日志中没有这个信息(比如上面的Crash信息中就没有包含),就需要我们手动去计算这个load * address:laod address = address to symbolicate - offset,比如:0x0000000102838119转化为十进制为4337139993,再减去偏移量265,为4337139728,在转化为十六进制0x0000000102838010

  • address to symbolicate:运行时堆栈地址,当前方法的内存地址。

实际crash日志中除了项目的工程调用堆栈还有系统库的调用堆栈,为了方便快速解析,我们使用python脚本来批量解析地址,例如这是我自己调试我们项目写的脚本

# coding=utf-8
import re
import os

def findLibSystemSyboPath(libName):
    systemLibRootPath = "/Users/xxx/Library/Developer/Xcode/iOS DeviceSupport/13.6 (17G68)"
    cmd = "find "" + systemLibRootPath + "" -name " + libName
    p = os.popen(cmd)
    s = p.read().strip()
    return s


def decodeIosCrashLog():

    UAGameSyboFile = "/Users/xxx/Downloads/xxxxx.dSYM/Contents/Resources/DWARF/Game"
    logFile = "/Users/xxx/Downloads/game_06121026.log"
    newlogFile = "/Users/xxx/Downloads/game_06121026_decode.log"
    with open(logFile, "r", encoding="utf-8") as f:
        lines = f.readlines()
        content = ""
        reg = re.compile(".++ d+$")
        for line in lines:
            if len(line.strip()) > 0 and reg.match(line):
                arr = re.split("s+", line)
                if len(arr) == 7:
                    print(arr[1], arr[2], arr[3])
                    if arr[1] == "Game":
                        symboFile = UAGameSyboFile
                    else:
                        symboFile = findLibSystemSyboPath(arr[1])
                    cmd = "atos -o "" + symboFile + "" -arch arm64 -l " + arr[3] + " " + arr[2]
                    print(cmd)
                    try:
                        p = os.popen(cmd)
                        s = p.read()
                        print(s)
                        content += "t".join(arr[:2]) + "t" + s + "rn"
                        continue
                    except:
                        print("find symbo error")
            content += line

    with open(newlogFile, "w", encoding="utf-8") as f:
        f.write(content)
        f.close()

if __name__=="__main__":
    decodeIosCrashLog()

大家按照自己项目的改下路径啥的,也就能直接用了,方便快捷。