/iOS-DeviceSupport

Symbols folders in ~/Library/Developer/Xcode/iOS DeviceSupport

Primary LanguageC

iOS-DeviceSupport

[TOC]

1、Symbols

Symbols folders in ~/Library/Developer/Xcode/iOS DeviceSupport

name
9.2.1 (13D15)
9.3.5 (13G36)
10.3.2 (14F89)
10.3.3 (14G60)
11.0 (15A372)
11.0.1 (15A402)
11.0.1 (15A403)
11.4 (15F79)
12.1.4 (16D57)
12.4.1 (16G102) arm64e
12.4.1 (16G102)
12.4.8 (16G201)
12.5.1 (16H22)
13.1 (17A5821e)
13.1.2 (17A861)
13.3 (17C54)
13.4.1 (17E262)
13.5.1 (17F80)
13.6 (17G68) arm64e
13.6.1 (17G80)
13.7 (17H35) arm64e
14.0 (18A373) arm64e
14.0.1 (18A393) arm64e
14.2.1 (18B121) arm64e
14.3 (18C66)
14.4 (18D52) arm64e
14.4.1 (18D61)
14.4.1 (18D61) arm64e
14.4.2 (18D70) arm64e
14.5 (18E199) arm64e
14.5.1 (18E212) arm64e
14.6 (18F72) arm64e
14.7.1 (18G82)
14.7.1 (18G82) arm64e
14.8 (18H17) arm64e
15.0 (19A5340a)
15.0 (19A344) arm64e
15.0.2 (19A404) arm64e
15.1 (19B74) arm64e
15.1.1 (19B81) arm64e
15.2 (19C56) arm64e
15.2 (19C57) arm64e
15.2.1 (19C63) arm64e
15.3 (19D50) arm64e
15.3.1 (19D52) arm64e
15.4 (19E241) arm64e
15.4.1 (19E258) arm64e
15.5 (19F77) arm64
15.5 (19F77) arm64e
15.6 (19G71) arm64e
15.6.1 (19G82) arm64e
15.7 (19H12) arm64e
16.0 (20A5339d) arm64e
16.0.2 (20A380) arm64e
16.0.3 (20A392) arm64e
16.1 (20B82) arm64e
16.1.1 (20B101) arm64e
16.1.2 (20B110) arm64e
16.2 (20C65) arm64e
16.3 (20D47) arm64e
16.3.1 (20D67) arm64e
16.4 (20E247) arm64e
16.4.1 (20E252) arm64e
16.5 (20F66) arm64e
16.5.1 (20F75) arm64e
16.6 (20G75) arm64e
16.6.1 (20G81) arm64e
iPhone13,2 16.6.1 (20G81)
16.7 (20H19) arm64e
16.7.1 (20H30) arm64
16.7.2 (20H115) arm64e
iPhone12,1 17.0 (21A329)
iPhone12,1 17.0.1 (21A340)
iPhone12,1 17.0.2 (21A351)
iPhone12,1 17.0.3 (21A360)
iPhone12,1 17.1.1 (21B91)
iPhone12,1 17.1.2 (21B101)
iPhone12,1 17.2 (21C62)
iPhone12,1 17.2.1 (21C66)
iPhone12,1 17.3 (21D50)
iPhone12,1 17.3.1 (21D61)
iPhone12,1 17.4 (21E219)
iPhone12,1 17.4.1 (21E236)
iPhone12,1 17.5 (21F79)
iPhone12,1 17.5.1 (21F90)
iPhone12,1 17.6 (21G80)
iPhone12,1 17.6.1 (21G93)
iPhone12,1 17.7 (21H16)
iPhone12,1 17.7.1 (21H216)
iPhone12,1 17.7.2 (21H221)
iPhone12,1 18.0 (22A3354)
iPhone12,1 18.0.1 (22A3370)
iPhone12,1 18.1 (22B83)
iPhone12,1 18.1.1 (22B91)

Google Drive: https://drive.google.com/drive/folders/1pkdZpu0bME4wXFd1CQhuIhjUkWVKNDkO

2、从固件中获取符号文件

iOS固件会有系统符号文件,通过一些工具,可以从固件中提取出符号文件,

(1) 下载对应版本的固件

国内有几个网址,可以提供固件下载

以iPhone14,5_15.0.1_19A348_Restore.ipsw为例,下载地址是这里

ipsw文件一般都比较大,选择网络好和空闲的时间来下载。

(2) 确定符号文件的位置

将ipsw文件解压,它实际是个zip文件,因此换下后缀名可以解压出来,得到下面的一些文件和文件夹

$ iPhone14,5_15.0.1_19A348_Restore.ipsw ls -l
total 12722096
-rw-r--r--@  1 wesley_chen  staff  6251791817 Jan  9  2007 018-79898-003.dmg
-rw-r--r--@  1 wesley_chen  staff   121403931 Jan  9  2007 038-42528-641.dmg
-rw-r--r--@  1 wesley_chen  staff   123465243 Jan  9  2007 038-42637-643.dmg
-r--r--r--@  1 wesley_chen  staff      314550 Jan  9  2007 BuildManifest.plist
drwxr-xr-x@ 33 wesley_chen  staff        1056 Jan  9  2007 Firmware
-r--r--r--@  1 wesley_chen  staff        1030 Jan  9  2007 Restore.plist
-rw-r--r--@  1 wesley_chen  staff    16727656 Jan  9  2007 kernelcache.release.iphone14

按照文件排序,找到最大的那个dmg文件,这里是018-79898-003.dmg,将它打开。

根据下面的路径,找到dyld_shared_cache_arm64e文件

/System/Library/Caches/com.apple.dyld

还有其他两个文件

  • /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.1
  • /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64e.symbols

(3) 获取dsc_extractor工具

有很多工具可以从dyld_shared_cache_arm64e文件提取符号文件,但是dsc_extractor提取的产物,是和Xcode连接真机提取的产物是一样的。

这篇文章的描述1,如下

dsc_extractor (source code). More info here. It produces the best results among all tools, but without branch islands workaround. Do note this is the exact same output provided by XCode automatically.

所以使用dsc_extractor工具,是最佳选择。但是dsc_extractor工具不是现成的,需要自己编译出来。

有两个文章23介绍如何编译这个工具,按照它们的步骤一步步来

a. 下载dyld文件

Apple的opensource网站提供下载dyld文件,地址是:https://opensource.apple.com/tarballs/dyld/

找到最新的dyld文件的下载地址。

执行下面几个命令

$ wget https://opensource.apple.com/tarballs/dyld/dyld-852.2.tar.gz
$ tar -xvzf dyld-852.2.tar.gz

dyld文件,由于更新了很多版本,因此解压后的文件结构可能会不一样。

b. 从dsc_extractor.cpp获取extract代码

找到需要的dsc_extractor.cpp,位置如下

dyld-852.2/dyld3/shared-cache/dsc_extractor.cpp

说明

如果有dyld.xcodeproj,可以打开搜一下dsc_extractor.cpp

在dsc_extractor.cpp的代码中,找到下面一段被if条件编译注释掉的代码,如下

#if 0
// test program
#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>


typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
                              void (^progress)(unsigned current, unsigned total));

int main(int argc, const char* argv[])
{
    if ( argc != 3 ) {
        fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
        return 1;
    }

    //void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
    void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
    if ( handle == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
        return 1;
    }

    extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
    if ( proc == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
        return 1;
    }

    int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
    fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
    return 0;
}


#endif

上面代码的大致逻辑是:在本地的Xcode.app中找到dsc_extractor.bundle这个动态库,加载到内存,然后通过dlsym拿到dyld_shared_cache_extract_dylibs_progress函数,然后用这个函数对dyld_shared_cache_arm64e文件进行提取。

另外,代码中清楚说明了,如何使用这个命令行工具

usage: dsc_extractor

c. 准备extract代码

有了上面现成的代码,那么copy&paste一下,变成自己的dsc_extractor.cpp文件,如下

#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>


typedef int (*extractor_proc)(const char* shared_cache_file_path, const char* extraction_root_path,
                              void (^progress)(unsigned current, unsigned total));

int main(int argc, const char* argv[])
{
    if ( argc != 3 ) {
        fprintf(stderr, "usage: dsc_extractor <path-to-cache-file> <path-to-device-dir>\n");
        return 1;
    }

    //void* handle = dlopen("/Volumes/my/src/dyld/build/Debug/dsc_extractor.bundle", RTLD_LAZY);
    void* handle = dlopen("/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle", RTLD_LAZY);
    if ( handle == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle could not be loaded\n");
        return 1;
    }

    extractor_proc proc = (extractor_proc)dlsym(handle, "dyld_shared_cache_extract_dylibs_progress");
    if ( proc == NULL ) {
        fprintf(stderr, "dsc_extractor.bundle did not have dyld_shared_cache_extract_dylibs_progress symbol\n");
        return 1;
    }

    int result = (*proc)(argv[1], argv[2], ^(unsigned c, unsigned total) { printf("%d/%d\n", c, total); } );
    fprintf(stderr, "dyld_shared_cache_extract_dylibs_progress() => %d\n", result);
    return 0;
}

编译之前,检查下这个路径是否有dsc_extractor.bundle文件

$ ls -l /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle
-rwxrwxr-x  1 wesley_chen  staff  567024 Apr 10  2021 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/usr/lib/dsc_extractor.bundle

d. 生成dsc_extractor命令行工具

执行下面的命令

$ clang++ -o dsc_extractor dsc_extractor.cpp

如果顺利的话,会得到名为dsc_extractor的可执行文件。

(4) 提取dyld_shared_cache_arm64e文件

执行下面命令

$ ./dsc_extractor dyld_shared_cache_arm64e arm64e/
0/2369
1/2369
2/2369
3/2369
4/2369
5/2369
...
dyld_shared_cache_extract_dylibs_progress() => 0

如果顺利的话,会输出进度,并打印“dyld_shared_cache_extract_dylibs_progress() => 0”。

注意

如果没有进度,仅打印“dyld_shared_cache_extract_dylibs_progress() => 0”,说明存在问题。

很可能提取的dyld_shared_cache_arm64e文件的版本,要高于Xcode的版本。比如说上面固件是15.0.1,但是Xcode版本还是12.5,不是Xcode 13.1。尽可能使用最新版本的Xcode,然后执行dsc_extractor工具

(5) 放置Symbol文件

按照iOS DeviceSupport规范,添加2个文件

  • .finalized。这个文件copy下已有的,就可以了
  • Info.plist。这个文件自己修改下,如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>DSC Extractor Version</key>
	<string>dyld-852.2</string>
	<key>DateCollected</key>
	<date>2021-11-04T16:25:01Z</date>
	<key>Version</key>
	<string>15.0.1 (19A348)</string>
</dict>
</plist>

将文件夹重命名为15.0.1 (19A348) arm64e,放置到~/Library/Developer/Xcode/iOS DeviceSupport。

3、MacOS系统的Symbol符号

在Apple M1芯片推出后,MacOS系统支持arm64结构,某些iOS app可以运行在MacOS上。这些app使用的系统库是MacOS上的系统库,而不是iOS系统上的系统库。如果要符号化这些app出现的crash日志,则需要找到MacOS上的系统库。

参考官方论坛的这个帖子,从Big Sur(MacOS 11)开始,引入dyld shared cache机制,所有系统库framework集成到一个单独二进制文件中,对应的描述,如下

Big Sur introduces a dyld shared cache, where all of the system frameworks are built into a single optimized binary. The individual framework binaries are no longer present in the OS.

参考这个SO,dyld shared cache文件,名为dyld_shared_cache_arm64e,它位于下面文件夹

/System/Library/dyld

说明

参考这个SO,MacOS 11后,位置可能存在变化。

由于SIP保护,默认是在该目录找不到dyld_shared_cache_arm64e文件。

在恢复模式下面,可以查看dyld_shared_cache_arm64e文件。

References

Footnotes

  1. https://iphonedev.wiki/index.php/Dyld_shared_cache

  2. http://crash.163.com/#news/!newsId=31

  3. https://gist.github.com/NSExceptional/85527151eeec4b0640187a0a165da1cd