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

在本章中,我們著眼于 Apple Silicon Mac 上的崩潰,比如,因使用 Rosetta 翻譯系統(tǒng)而引起的崩潰以及因在 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 時,這為客戶帶來了更優(yōu)益的市場收益,例如更長的電池壽命和高性能。

什么是 Rosetta?

Rosetta 是 Apple Silicon Mac 上的指令翻譯器。當應用程序?qū)?Intel 指令作為二進制代碼的一部分時,它可以將這些指令轉(zhuǎn)換為 ARM 指令,然后運行它們??梢园阉醋?AOT 編譯器。這項技術的起源可以追溯到更早的時期,當時 mac 正在從 PowerPC 芯片過渡到 Intel 芯片。蘋果在 Transitive Technologies Ltd. 的技術幫助下研發(fā)出了 Rosetta 的第一個版本。在 Rosetta 的第二個版本中,我們的系統(tǒng)允許在每個進程的基礎上,將 Intel 指令預先翻譯成 ARM 指令,然后以原生速度運行。

Rosetta 的二進制文件

在 Apple Silicon Mac 上,Rosetta 軟件駐留在

/Library/Apple/usr/libexec/oah

在這個目錄下有運行時引擎 runtime_t8027、翻譯器 oahd-helper、命令行工具 translate_tool和其他工具。它的操作對終端用戶來說基本是透明的,除了啟動延遲較小或性能稍低。從崩潰分析的角度來看,我們可以從內(nèi)存占用量,異常幫助程序和運行時幫助程序的角度看到它的存在。

Rosetta 的局限性

Rosetta 是一個功能強大的系統(tǒng),但有一些局限性。這些主要涉及高性能多媒體應用程序和操作系統(tǒng)虛擬化解決方案。

Rosetta 并不包括以下功能:

  • 內(nèi)核擴展
  • x86_64 虛擬化支持說明
  • 矢量指令,例如 AVX,AVX2 和 AVX512

有趣的是,Rosetta 支持即時編譯應用程序。這些應用程序非常特殊,因為它們自己生成代碼,然后執(zhí)行代碼。大多數(shù)應用程序都只有固定的只讀代碼(程序文本),然后執(zhí)行這些代碼,它們的數(shù)據(jù)只是可變的(但不是可執(zhí)行的)。這大概是因為JIT是JavaScript運行時的常用技術。

Apple 建議在調(diào)用使用這種功能的代碼之前先檢查可選的硬件功能。 我們可以通過運行 sysctl hw | grep optional 來確定平臺上存在哪些可選硬件支持。在代碼中,我們可以調(diào)用sysctlbyname 方法來實現(xiàn)同樣的功能。

強制執(zhí)行 Rosetta

如果我們默認給自己的項目使用標準的構建選項,當在 Debug 時將Build Active Architecture Only 設置成為Yes,而對于Release構建則設置為No,然后再調(diào)試時,我們將只看到本機的二進制文件。 這是因為在 Debug 時,我們不想浪費時間來構建與我們正在測試的機器無關的體系結構。

如果我們進行 Archive 構建,Product > Archive,然后選擇 Distribute App 我們最終獲得了一個可供發(fā)布的版本。 在默認設置下,這將是 Fat Binary(我們將其稱為胖二進制)文件,在多體系結構的二進制文件中提供 x86arm64

一旦我們有了一個 Fat Binary 文件,我們可以使用 Finder 應用程序,右鍵單擊File info設置 Rosetta 來執(zhí)行我們的二進制文件的翻譯,這樣在一個 Apple Silicon Mac 上,Intel 指令就會從 Fat Binary 中翻譯出來。

univeral_application_icdab_rosetta_thread.png

翻譯后的應用程序示例

本章的工作示例是icdab_thread程序。 可以在網(wǎng)上找到。@icdabgithub 該程序嘗試調(diào)用 thread_set_state,然后在 60 秒后調(diào)用abort 主動崩潰。實際上它并沒有辦法達到這個效果,因為最近 macOS 的安全增強,以防止使用這樣的API,它是惡意軟件的攻擊載體。盡管如此,這個程序還是很有趣的,因為在崩潰時,一個緊密相關的部分task_for_pid 被多次調(diào)用了 。

我們已經(jīng)將命令行可執(zhí)行程序 icdab_thread 修改為僅調(diào)用相同基礎代碼的應用程序。這個應用程序就是 icdab_rosetta_thread。這是因為 UNIX 命令行可執(zhí)行文件不適合運行轉(zhuǎn)換后的程序,而應用程序可以。

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,在一分鐘后,應用程序發(fā)生崩潰。比較原生案例與已翻譯案例之間的崩潰分析,我們可以從崩潰報告中的找到差異。

代碼類型

Code Type:             ARM-64 (Native)

當在本地運行時,變成了已翻譯

Code Type:             X86-64 (Translated)

線程轉(zhuǎn)儲

崩潰的線程(和其他線程)看起來很相似,只是指針在翻譯后的情況下基于更高的指針。
對于原生的崩潰,我們有:

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 合成的實際翻譯代碼。

此外,在翻譯后的案例中,我們還有另外兩個線程,異常服務器和運行時環(huán)境:

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

崩潰的線程狀態(tài)寄存器

在原生的例子中,我們得到了線程狀態(tài)寄存器:

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

在翻譯后的案例中,同樣也有線程狀態(tài)寄存器:

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: <unavailable>  rfl: 0x0000000000000287

翻譯的代碼信息

在翻譯后的案例中,我們會獲得更多信息,這可能對那些從事調(diào)試 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

我們的代碼曾嘗試調(diào)用 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

我們看到幾乎相同的統(tǒng)計信息,但是有趣的是,我們將task_for_pid 設置為 1。因此,翻譯環(huán)境僅對翻譯過程進行了最小的觀察/修改。

虛擬內(nèi)存區(qū)域

該程序的翻譯版本在 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

請注意,在翻譯后的情況下,我們?yōu)?Rosetta 提供了其他虛擬內(nèi)存區(qū)域:

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 是功能強大的翻譯系統(tǒng)。 但是它不能翻譯所有 X86-64指令。 例如,矢量指令無法翻譯,遇到時會發(fā)生崩潰。

在診斷特定問題之前,有必要先熟悉一下 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]

在我們的情況下,崩潰時的線程狀態(tài)為:

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

如果我們發(fā)現(xiàn)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)

但是,更確切地說,我們可以在崩潰時使用指令指針。
我們從崩潰的線程狀態(tài)中看到,我們有:

  rip: 0x00000001047d56cb  rfl: 0x0000000000000206

我們從Binary Images中看到,該程序已加載到地址0x1047d4000

使用我們在 Symbolification 章節(jié)中探討的技術,我們可以在 Hopper 中加載 icdab_avx 二進制文件,將二進制文件的基址更改為0x1047d4000,然后轉(zhuǎn)到指令指針 rip和地址 0x00000001047d56cb

然后,我們看到程序集轉(zhuǎn)儲:

_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]

因此,雖然我們沒有找到失敗的確切指令,但是找到了出現(xiàn)錯誤的函數(shù) compute_delta,它位于runVectorOperationsButtonAction方法中,它看起來已經(jīng)被內(nèi)聯(lián)到這個版本二進制文件中。盡管如此,我們已經(jīng)獲得了足夠的幫助,能夠在相關區(qū)域中探索二進制文件并確定確認進行了向量操作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;
}

為了避免此問題,我們應該使用一個有用的方法來檢測當前環(huán)境是否支持 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(并且在檢索信息時沒有錯誤),此函數(shù)返回 true

在 Mac 上運行 iOS

由于 Apple Silicon Mac 和 iOS 設備共享相同的 ARM CPU 體系結構,因此Apple提供了附加功能。 未經(jīng)修改的 iOS 應用程序可能會在基于 ARM 的 macOS 上運行。 為此,基于 ARM 的 macOS 擁有了一些特殊的 iOS 支持庫。

我們可以這樣想,macOS (主語)是提供支持庫和框架的 ,提供 iOS( 賓語 )應用程序期望的 UIKit。

當此類應用程序崩潰時,我們會獲得崩潰報告,該報告是 macOS 崩潰報告,但大多數(shù)細節(jié)都涉及 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 支持層實現(xiàn)的。

Binary Images:
       0x10492c000 -        0x10493bfff
 +www.perivalebluebell.icdab-wrap (1.0 - 1)
 <E9A2E2CC-E879-37B0-820C-F336DF2AACDA>
 /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) <D3335C2E-2366-30AD-A5F3-6058164D69EE>
 /System/Library/PrivateFrameworks/UIFoundation.framework/Version
s/A/UIFoundation
       0x1bd9a2000 -        0x1bda37fff  com.apple.UIKitMacHelper
 (1.0 - 3979.1.400) <F2F6D8F7-8178-3113-856E-F99614A4F13E>
 /System/Library/PrivateFrameworks/UIKitMacHelper.framework/Versi
ons/A/UIKitMacHelper
       0x1bda38000 -        0x1bda4bfff  com.apple.UIKitServices
 (1.0 - 1) <D8C4D101-A04C-37E6-87A3-6AD9ADFEC787>
 /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

在大多數(shù)情況下,這些崩潰可以像在 iOS 上崩潰一樣直接進行分析。問題很有可能是由于不同的物理環(huán)境導致的。例如,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()
.
.
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容