[译]《iOS Crash Dump Analysis》- Apple Silicon

在本章中,我们着眼于 Apple Silicon Mac 上的崩溃,比如,因使用 Rosetta 翻译系统而引起的崩溃以及因在 macOS 上运行的未修改 iOS 应用程序而引起的崩溃。 此外,我们还将研究同时支持 ARM 和 Intel CPU的多体系结构代码可能导致的新型崩溃。

什么是 Apple Silicon Mac?

Apple Silicon表示该芯片的设计来自Apple,而不是第三方。 苹果公司的A系列芯片可以被认为是苹果芯片。 但是,本章重点是Apple Silicon Macs。 这些始于Apple M1芯片。 这些Mac之所以不被称为 基于ARM的Mac,可能是因为Apple在设计水平上做出了重大贡献,同时仍然符合ARM ABI。 当从基于 Intel 的 Mac 切换到 Apple Silicon Mac 时,这为客户带来了更优益的市场收益,例如更长的电池寿命和高性能。

什么是 Rosetta?

Rosetta 是 Apple Silicon Mac 上的指令翻译器。当应用程序将 Intel 指令作为二进制代码的一部分时,它可以将这些指令转换为 ARM 指令,然后运行它们。可以把它看作 AOT 编译器。这项技术的起源可以追溯到更早的时期,当时 mac 正在从 PowerPC 芯片过渡到 Intel 芯片。苹果在 Transitive Technologies Ltd. 的技术帮助下研发出了 Rosetta 的第一个版本。在 Rosetta 的第二个版本中,我们的系统允许在每个进程的基础上,将 Intel 指令预先翻译成 ARM 指令,然后以原生速度运行。

Rosetta 的二进制文件

在 Apple Silicon Mac 上,Rosetta 软件驻留在

/Library/Apple/usr/libexec/oah

在这个目录下有运行时引擎 runtime_t8027、翻译器 oahd-helper、命令行工具 translate_tool和其他工具。它的操作对终端用户来说基本是透明的,除了启动延迟较小或性能稍低。从崩溃分析的角度来看,我们可以从内存占用量,异常帮助程序和运行时帮助程序的角度看到它的存在。

Rosetta 的局限性

Rosetta 是一个功能强大的系统,但有一些局限性。这些主要涉及高性能多媒体应用程序和操作系统虚拟化解决方案。

Rosetta 并不包括以下功能:

  • 内核扩展
  • x86_64 虚拟化支持说明
  • 矢量指令,例如 AVX,AVX2 和 AVX512

有趣的是,Rosetta 支持即时编译应用程序。这些应用程序非常特殊,因为它们自己生成代码,然后执行代码。大多数应用程序都只有固定的只读代码(程序文本),然后执行这些代码,它们的数据只是可变的(但不是可执行的)。这大概是因为JIT是JavaScript运行时的常用技术。

Apple 建议在调用使用这种功能的代码之前先检查可选的硬件功能。 我们可以通过运行 sysctl hw | grep optional 来确定平台上存在哪些可选硬件支持。在代码中,我们可以调用sysctlbyname 方法来实现同样的功能。

强制执行 Rosetta

如果我们默认给自己的项目使用标准的构建选项,当在 Debug 时将Build Active Architecture Only 设置成为Yes,而对于Release构建则设置为No,然后再调试时,我们将只看到本机的二进制文件。 这是因为在 Debug 时,我们不想浪费时间来构建与我们正在测试的机器无关的体系结构。

如果我们进行 Archive 构建,Product > Archive,然后选择 Distribute App 我们最终获得了一个可供发布的版本。 在默认设置下,这将是 Fat Binary(我们将其称为胖二进制)文件,在多体系结构的二进制文件中提供 x86arm64

一旦我们有了一个 Fat Binary 文件,我们可以使用 Finder 应用程序,右键单击File info设置 Rosetta 来执行我们的二进制文件的翻译,这样在一个 Apple Silicon Mac 上,Intel 指令就会从 Fat Binary 中翻译出来。

univeral_application_icdab_rosetta_thread.png

翻译后的应用程序示例

本章的工作示例是icdab_thread程序。 可以在网上找到。@icdabgithub 该程序尝试调用 thread_set_state,然后在 60 秒后调用abort 主动崩溃。实际上它并没有办法达到这个效果,因为最近 macOS 的安全增强,以防止使用这样的API,它是恶意软件的攻击载体。尽管如此,这个程序还是很有趣的,因为在崩溃时,一个紧密相关的部分task_for_pid 被多次调用了 。

我们已经将命令行可执行程序 icdab_thread 修改为仅调用相同基础代码的应用程序。这个应用程序就是 icdab_rosetta_thread。这是因为 UNIX 命令行可执行文件不适合运行转换后的程序,而应用程序可以。

icdab_rosetta_thread Lipo 信息

以下命令显示我们的应用程序同时支持 ARM 和 Intel 指令。

# lipo -archs
 icdab_rosetta_thread.app/Contents/MacOS/icdab_rosetta_thread
x86_64 arm64

翻译后的程序崩溃

如果我们运行 icdab_rosetta_thread 应用程序,点击 Start Threads Test,在一分钟后,应用程序发生崩溃。比较原生案例与已翻译案例之间的崩溃分析,我们可以从崩溃报告中的找到差异。

代码类型

Code Type:             ARM-64 (Native)

当在本地运行时,变成了已翻译

Code Type:             X86-64 (Translated)

线程转储

崩溃的线程(和其他线程)看起来很相似,只是指针在翻译后的情况下基于更高的指针。
对于原生的崩溃,我们有:

Thread 1 Crashed:: Dispatch queue: com.apple.root.default-qos
0   libsystem_kernel.dylib              0x00000001de3015d8
 __pthread_kill + 8
1   libsystem_pthread.dylib             0x00000001de3accbc
 pthread_kill + 292
2   libsystem_c.dylib                   0x00000001de274904 abort
 + 104
3   perivalebluebell.com.icdab-rosetta-thread  
 0x00000001002cd478 start_threads + 244
4   perivalebluebell.com.icdab-rosetta-thread  
 0x00000001002cd858 thunk for @escaping @callee_guaranteed () ->
 () + 20
5   libdispatch.dylib                   0x00000001de139658
 _dispatch_call_block_and_release + 32
6   libdispatch.dylib                   0x00000001de13b150
 _dispatch_client_callout + 20
7   libdispatch.dylib                   0x00000001de13e090
 _dispatch_queue_override_invoke + 692
8   libdispatch.dylib                   0x00000001de14b774
 _dispatch_root_queue_drain + 356
9   libdispatch.dylib                   0x00000001de14bf6c
 _dispatch_worker_thread2 + 116
10  libsystem_pthread.dylib             0x00000001de3a9110
 _pthread_wqthread + 216
11  libsystem_pthread.dylib             0x00000001de3a7e80
 start_wqthread + 8

而对于翻译后的案例中崩溃,则有

Thread 1 Crashed:: Dispatch queue: com.apple.root.default-qos
0   ???                                 0x00007fff0144ff40 ???
1   libsystem_kernel.dylib              0x00007fff6bdc4812
 __pthread_kill + 10
2   libsystem_c.dylib                   0x00007fff6bd377f0 abort
 + 120
3   perivalebluebell.com.icdab-rosetta-thread  
 0x0000000100d1c5ab start_threads + 259
4   perivalebluebell.com.icdab-rosetta-thread  
 0x0000000100d1ca1e thunk for @escaping @callee_guaranteed () ->
 () + 14
5   libdispatch.dylib                   0x00007fff6bbf753d
 _dispatch_call_block_and_release + 12
6   libdispatch.dylib                   0x00007fff6bbf8727
 _dispatch_client_callout + 8
7   libdispatch.dylib                   0x00007fff6bbfad7c
 _dispatch_queue_override_invoke + 777
8   libdispatch.dylib                   0x00007fff6bc077a5
 _dispatch_root_queue_drain + 326
9   libdispatch.dylib                   0x00007fff6bc07f06
 _dispatch_worker_thread2 + 92
10  libsystem_pthread.dylib             0x00007fff6be8c4ac
 _pthread_wqthread + 244
11  libsystem_pthread.dylib             0x00007fff6be8b4c3
 start_wqthread + 15

注意,在翻译后的案例中,线程堆栈 0 中的实际代码行是 ???。 大概这是 Rosetta 合成的实际翻译代码。

此外,在翻译后的案例中,我们还有另外两个线程,异常服务器和运行时环境:

Thread 3:: com.apple.rosetta.exceptionserver
0   runtime_t8027                       0x00007ffdfff76af8
 0x7ffdfff74000 + 11000
1   runtime_t8027                       0x00007ffdfff803cc
 0x7ffdfff74000 + 50124
2   runtime_t8027                       0x00007ffdfff82738
 0x7ffdfff74000 + 59192

Thread 4:
0   runtime_t8027                       0x00007ffdfffce8ac
 0x7ffdfff74000 + 370860

崩溃的线程状态寄存器

在原生的例子中,我们得到了线程状态寄存器:

Thread 1 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000000   x2:
 0x0000000000000000   x3: 0x0000000000000000
    x4: 0x000000000000003c   x5: 0x0000000000000000   x6:
 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x00000000000005b9   x9: 0xb91ed5337c66d7ee  x10:
 0x0000000000003ffe  x11: 0x0000000206c1fa22
   x12: 0x0000000206c1fa22  x13: 0x000000000000001e  x14:
 0x0000000000000881  x15: 0x000000008000001f
   x16: 0x0000000000000148  x17: 0x0000000200e28528  x18:
 0x0000000000000000  x19: 0x0000000000000006
   x20: 0x000000016fbbb000  x21: 0x0000000000001707  x22:
 0x000000016fbbb0e0  x23: 0x0000000000000114
   x24: 0x000000016fbbb0e0  x25: 0x000000020252d184  x26:
 0x00000000000005ff  x27: 0x000000020252d6c0
   x28: 0x0000000002ffffff   fp: 0x000000016fbbab70   lr:
 0x00000001de3accbc
    sp: 0x000000016fbbab50   pc: 0x00000001de3015d8 cpsr:
 0x40000000
   far: 0x0000000100ff8000  esr: 0x56000080

在翻译后的案例中,同样也有线程状态寄存器:

Thread 1 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x000000030600b000  rcx:
 0x0000000000000000  rdx: 0x0000000000000000
  rdi: 0x0000000000000000  rsi: 0x0000000000000003  rbp:
 0x0000000000000000  rsp: 0x000000000000003c
   r8: 0x000000030600ad40   r9: 0x0000000000000000  r10:
 0x000000030600b000  r11: 0x00007fff6bd37778
  r12: 0x0000000000003d03  r13: 0x0000000000000000  r14:
 0x0000000000000006  r15: 0x0000000000000016
  rip:   rfl: 0x0000000000000287

翻译的代码信息

在翻译后的案例中,我们会获得更多信息,这可能对那些从事调试 Rosetta 的工程师有用:

Translated Code Information:
  tmp0: 0xffffffffffffffff tmp1: 0x00007fff0144ff14 tmp2:
 0x00007fff6bdc4808

外部修改摘要

在原生的例子中,我们看到:

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 914636
    thread_create: 0
    thread_set_state: 804

我们的代码曾尝试调用 thread_set_state,但未能(由于 macOS 限制,在任何平台配置下都不行)。

然后我们看一下翻译后的示例:

External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 1
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 915091
    thread_create: 0
    thread_set_state: 804

我们看到几乎相同的统计信息,但是有趣的是,我们将task_for_pid 设置为 1。因此,翻译环境仅对翻译过程进行了最小的观察/修改。

虚拟内存区域

该程序的翻译版本在 RAM 使用率上比原生版本高。

在原生的案例中,我们可以看到:

                                VIRTUAL   REGION
REGION TYPE                        SIZE    COUNT (non-coalesced)
===========                     =======  =======
TOTAL                              1.7G     2053
TOTAL, minus reserved VM space     1.3G     2053

而翻译后的情况则是:

REGION TYPE                        SIZE    COUNT (non-coalesced)
===========                     =======  =======
TOTAL                              5.4G     1512
TOTAL, minus reserved VM space     5.1G     1512

请注意,在翻译后的情况下,我们为 Rosetta 提供了其他虚拟内存区域:

Rosetta Arena                     2048K        1
Rosetta Generic                    864K       19
Rosetta IndirectBranch             512K        1
Rosetta JIT                      128.0M        1
Rosetta Return Stack               192K       12
Rosetta Thread Context             192K       12

Rosetta 崩溃

Rosetta 是功能强大的翻译系统。 但是它不能翻译所有 X86-64指令。 例如,矢量指令无法翻译,遇到时会发生崩溃。

在诊断特定问题之前,有必要先熟悉一下 Apple 的 Porting Guide,因为这可以帮助我们针对程序可能崩溃的原因提出合理的假设。

icdab_avx 矢量指令崩溃

当在使用翻译运行应用程序的 Apple Silicon Mac 上遇到英特尔 AVX 矢量指令\index{Vector instruction!AVX} 时,我们就会崩溃。我们用一个示例应用程序 icdab_avx来演示了这一点。

崩溃代码类型将为:

Code Type:             X86-64 (Translated)

崩溃类型将为EXC_BAD_INSTRUCTION,如下所示:\index{signal!SIGILL}

Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes:       0x0000000000000001, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Illegal instruction: 4
Termination Reason:    Namespace SIGNAL, Code 0x4
Terminating Process:   exc handler [26823]

在我们的情况下,崩溃时的线程状态为:

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000001  rbx: 0x0000600001fcf5c0  rcx:
 0x00007f87d143f8c0  rdx: 0x00007f87d143f8c0
  rdi: 0x00000001047d6fa0  rsi: 0x00000001047d770a  rbp:
 0x000000030d132ab0  rsp: 0x000000030d132ab0
   r8: 0x0000000000000003   r9: 0x0000000104b0e000  r10:
 0x00000001047dc702  r11: 0x00000001047d57d0
  r12: 0x00006000012d5100  r13: 0x00007fff6a9d4000  r14:
 0x00007f87d143f8c0  r15: 0x00000001047d770a
  rip: 0x00000001047d56cb  rfl: 0x0000000000000206

应用程序二进制文件(程序文本)按如下方式加载:

Binary Images:
       0x1047d4000 -        0x1047d7fff
 +perivalebluebell.com.icdab-avx (1.0 - 1)
 <3D9E0DED-2C66-30EE-AC6C-7C426246332E>
 /Users/USER/Desktop/*/icdab_avx.app/Contents/MacOS/icdab_avx

如果我们发现Apple Silicon Mac 以这种方式使我们的应用程序崩溃,如果我们有这样的怀疑,我们可以迅速搜索任何矢量指令 \index{Vector instruction!AVX}。

# objdump -d icdab_avx.app/Contents/MacOS/icdab_avx | grep vmov |
 head
100004527: c5 fa 10 84 24 a4 00 00 00      vmovss    164(%rsp),
 %xmm0
100004530: c5 fa 10 8c 24 a0 00 00 00      vmovss    160(%rsp),
 %xmm1
10000453f: c5 fa 10 8c 24 a8 00 00 00      vmovss    168(%rsp),
 %xmm1
10000454e: c5 fa 10 8c 24 ac 00 00 00      vmovss    172(%rsp),
 %xmm1
10000455d: c5 fa 10 8c 24 b4 00 00 00      vmovss    180(%rsp),
 %xmm1
100004566: c5 fa 10 94 24 b0 00 00 00      vmovss    176(%rsp),
 %xmm2
100004575: c5 fa 10 94 24 b8 00 00 00      vmovss    184(%rsp),
 %xmm2
100004584: c5 fa 10 94 24 bc 00 00 00      vmovss    188(%rsp),
 %xmm2
100004593: c5 f8 29 8c 24 90 00 00 00      vmovaps    %xmm1,
 144(%rsp)
10000459c: c5 f8 29 84 24 80 00 00 00      vmovaps    %xmm0,
 128(%rsp)

但是,更确切地说,我们可以在崩溃时使用指令指针。
我们从崩溃的线程状态中看到,我们有:

  rip: 0x00000001047d56cb  rfl: 0x0000000000000206

我们从Binary Images中看到,该程序已加载到地址0x1047d4000

使用我们在 Symbolification 章节中探讨的技术,我们可以在 Hopper 中加载 icdab_avx 二进制文件,将二进制文件的基址更改为0x1047d4000,然后转到指令指针 rip和地址 0x00000001047d56cb

然后,我们看到程序集转储:

_compute_delta:
push       rbp          ; CODE
 XREF=_$s9icdab_avx14ViewControllerC31runVectorOperationsButtonAc
tionyySo12NSButtonCellCF+32
mov        rbp, rsp
and        rsp, 0xffffffffffffffe0
sub        rsp, 0x160
mov        dword [rsp+0x160+var_A4], 0x40000000
mov        dword [rsp+0x160+var_A8], 0x40800000
mov        dword [rsp+0x160+var_AC], 0x40c00000
mov        dword [rsp+0x160+var_B0], 0x41000000
mov        dword [rsp+0x160+var_B4], 0x41200000
mov        dword [rsp+0x160+var_B8], 0x41400000
mov        dword [rsp+0x160+var_BC], 0x41600000
mov        dword [rsp+0x160+var_C0], 0x41800000
vmovss     xmm0, dword [rsp+0x160+var_BC]
vmovss     xmm1, dword [rsp+0x160+var_C0]

因此,虽然我们没有找到失败的确切指令,但是找到了出现错误的函数 compute_delta,它位于runVectorOperationsButtonAction方法中,它看起来已经被内联到这个版本二进制文件中。尽管如此,我们已经获得了足够的帮助,能够在相关区域中探索二进制文件并确定确认进行了向量操作vmovss。 Rosetta不支持此功能。

导致该问题的原始代码为:

void
compute_delta() {
    /* Initialize the two argument vectors */
    __m256 evens = _mm256_set_ps(2.0, 4.0, 6.0, 8.0, 10.0, 12.0,
 14.0, 16.0);
    __m256 odds = _mm256_set_ps(1.0, 3.0, 5.0, 7.0, 9.0, 11.0,
 13.0, 15.0);
    
    /* Compute the difference between the two vectors */
    __m256 result = _mm256_sub_ps(evens, odds);
    
    /* Display the elements of the result vector */
    float* f = (float*)&result;
    printf("%f %f %f %f %f %f %f %f\n",
           f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]);
    
    return;
}

为了避免此问题,我们应该使用一个有用的方法来检测当前环境是否支持 AVX\index{Vector instruction!AVX},如下所示:

bool
avx_v1_supported() {
    int ret = 0;
    size_t size = sizeof(ret);
    if (sysctlbyname("hw.optional.avx1_0", &ret, &size, NULL, 0)
 == -1)
    {
       if (errno == ENOENT)
          return false;
       return false;
    }
    bool supported = (ret != 0);
    return supported;
}

如果支持 AVX 版本1(并且在检索信息时没有错误),此函数返回 true

在 Mac 上运行 iOS

由于 Apple Silicon Mac 和 iOS 设备共享相同的 ARM CPU 体系结构,因此Apple提供了附加功能。 未经修改的 iOS 应用程序可能会在基于 ARM 的 macOS 上运行。 为此,基于 ARM 的 macOS 拥有了一些特殊的 iOS 支持库。

我们可以这样想,macOS (主语)是提供支持库和框架的 ,提供 iOS( 宾语 )应用程序期望的 UIKit。

当此类应用程序崩溃时,我们会获得崩溃报告,该报告是 macOS 崩溃报告,但大多数细节都涉及 iOS 库。

icdab_wrap iOS 应用程序在 macOS 上崩溃

如果我们在 Apple Silicon Mac 上运行 iOS 应用 icdab_wrap ,它可以正常加载,是因为 macOS 提供了 UIKit 框架,而 icdab_wrap 也假定该框架已存在。该应用程序是为了来演示一个问题,解包 Nil 可选项。

崩溃时,我们可以看到:

Code Type:             ARM-64 (Native)
Parent Process:        ??? [1]
Responsible:           icdab_wrap [2802]
User ID:               501

这表明应用程序正在运行原生代码,而不是翻译过的代码。

Date/Time:             2020-11-14 11:58:17.668 +0000
OS Version:            Mac OS X 10.16 (20A5343i)
Report Version:        12
Anonymous UUID:        0118DF8D-2876-0263-8668-41B1482DDC38

这表明我们很明显的是在 Mac 上运行。

System Integrity Protection: enabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BREAKPOINT (SIGTRAP)
Exception Codes:       EXC_ARM_BREAKPOINT at 0x00000001c6c8f1f0
 (brk 1)
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Trace/BPT trap: 5
Termination Reason:    Namespace SIGNAL, Code 0x5
Terminating Process:   exc handler [2802]

Application Specific Information:
dyld3 mode
Fatal error: Unexpectedly found nil while implicitly unwrapping
 an Optional value: file icdab_wrap/PlanetViewController.swift,
 line 45

这说明程序崩溃时正在解包 Nil 可选项。

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libswiftCore.dylib                  0x00000001c6c8f1f0
 closure #1 in closure #1 in closure #1 in
 _assertionFailure(_:_:file:line:flags:) + 404
1   libswiftCore.dylib                  0x00000001c6c8f1f0
 closure #1 in closure #1 in closure #1 in
 _assertionFailure(_:_:file:line:flags:) + 404
2   libswiftCore.dylib                  0x00000001c6c8e660
 _assertionFailure(_:_:file:line:flags:) + 488
3   www.perivalebluebell.icdab-wrap     0x0000000104937da4
 PlanetViewController.imageDownloaded(_:) + 196
 (PlanetViewController.swift:45)
.
.
.

16  com.apple.AppKit                    0x0000000189740824
 _DPSNextEvent + 880
17  com.apple.AppKit                    0x000000018973f1fc
 -[NSApplication(NSEvent)
 _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1300
18  com.apple.AppKit                    0x00000001897313c4
 -[NSApplication run] + 600
19  com.apple.AppKit                    0x0000000189703550
 NSApplicationMain + 1064
20  com.apple.AppKit                    0x00000001899e92f8
 _NSApplicationMainWithInfoDictionary + 24
21  com.apple.UIKitMacHelper            0x00000001bd9a6038
 UINSApplicationMain + 476
22  com.apple.UIKitCore                 0x00000001d333d1b0
 UIApplicationMain + 2108
23  www.perivalebluebell.icdab-wrap     0x0000000104933a38 main +
 88 (AppDelegate.swift:12)
24  libdyld.dylib                       0x00000001c758ca50 start
 + 4

这表明当程序被加载时 libdyld.dylib,它所期望的 UIKit UIKitCore 是通过 UIKitMacHelper 支持层实现的。

Binary Images:
       0x10492c000 -        0x10493bfff
 +www.perivalebluebell.icdab-wrap (1.0 - 1)
 
 /Users/USER/Library/Developer/Xcode/DerivedData/icdab-gbtgrhpqeh
gqogaglrpuvzajteku/Build/Products/Debug-iphoneos/icdab_wrap.app/i
cdab_wrap
       0x104a1c000 -        0x104a27fff 
 libobjc-trampolines.dylib (817)
 <4A2C66DE-9358-3AE9-A69F-36687DB19CE3>
 /usr/lib/libobjc-trampolines.dylib
       0x104b34000 -        0x104baffff  dyld (828)
 <7A9F335B-50E3-3018-A9CC-26E57B61D907> /usr/lib/dyld
.
.

       0x189700000 -        0x18a400fff  com.apple.AppKit (6.9 -
 2004.102) <96941AAC-01D7-36E7-9253-2C1187864719>
 /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
.
.

       0x1bd77f000 -        0x1bd9a1fff  com.apple.UIFoundation
 (1.0 - 714) 
 /System/Library/PrivateFrameworks/UIFoundation.framework/Version
s/A/UIFoundation
       0x1bd9a2000 -        0x1bda37fff  com.apple.UIKitMacHelper
 (1.0 - 3979.1.400) 
 /System/Library/PrivateFrameworks/UIKitMacHelper.framework/Versi
ons/A/UIKitMacHelper
       0x1bda38000 -        0x1bda4bfff  com.apple.UIKitServices
 (1.0 - 1) 
 /System/Library/PrivateFrameworks/UIKitServices.framework/Versio
ns/A/UIKitServices
.
.

       0x1c9b1b000 -        0x1c9b1bfff 
 com.apple.MobileCoreServices (1112.0.10 - 1112.0.10)
 <992DAEC7-6964-3686-A910-4365B353D925>
 /System/iOSSupport/System/Library/Frameworks/MobileCoreServices.
framework/Versions/A/MobileCoreServices
.
.

       0x1d333a000 -        0x1d462ffff  com.apple.UIKitCore (1.0
 - 3979.1.400) <023078DD-44DA-3A11-82CA-12F8412661A2>
 /System/iOSSupport/System/Library/PrivateFrameworks/UIKitCore.fr
amework/Versions/A/UIKitCore
.
.

       0x1d72fa000 -        0x1d7337fff  libswiftUIKit.dylib (15)
 <68377BCA-6493-3E34-920E-0765BD07F2A7>
 /System/iOSSupport/usr/lib/swift/libswiftUIKit.dylib

在大多数情况下,这些崩溃可以像在 iOS 上崩溃一样直接进行分析。问题很有可能是由于不同的物理环境导致的。例如,iOS 设备具有陀螺仪,而 macOS 设备则没有。

在 Mac 上支持 iOS 应用程序

Apple 提供了在 Mac 上部署 iOS 应用程序的最佳实践指南。你可以进行如下操作:

  1. 如果确定自己的 iOS 应用程序不适合 macOS。在 App Store Connect 中可以取消配置。
  2. 允许在 iOS 上安装的应用程序安装在 macOS 上,但是添加检查可用的可选硬件功能。
  3. 增强该应用程序,使 Mac 用户更易于使用替代功能。 例如,添加iOS键盘支持。
  4. 添加代码以检测 iOS-on-Mac 的场景。
  5. 通过 Mac Catalyst 技术连接到Mac。这意味着首先得拥有一个出色的iPadOS应用。
  6. 编写纯原生 macOS 应用程序。

例如,在应用程序 icdab_gyro 我们将展示如何检测 iOS-on-Mac 的场景:

        let info = ProcessInfo()
        if #available(iOS 14.0, *) {
            if info.isiOSAppOnMac {
                print("We are an iOS app running on a Mac")
            }
        }

此外,当使用陀螺仪时

var motion = CMMotionManager()

并仅在可用时使用陀螺仪:

if motion.isGyroAvailable {
          self.motion.gyroUpdateInterval = 1.0 / 60.0
          self.motion.startGyroUpdates()
.
.

你可能感兴趣的:([译]《iOS Crash Dump Analysis》- Apple Silicon)