在本章中,我們著眼于 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(我們將其稱為胖二進制)文件,在多體系結構的二進制文件中提供 x86 和 arm64。
一旦我們有了一個 Fat Binary 文件,我們可以使用 Finder 應用程序,右鍵單擊File info設置 Rosetta 來執(zhí)行我們的二進制文件的翻譯,這樣在一個 Apple Silicon Mac 上,Intel 指令就會從 Fat Binary 中翻譯出來。

翻譯后的應用程序示例
本章的工作示例是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 應用程序的最佳實踐指南。你可以進行如下操作:
- 如果確定自己的 iOS 應用程序不適合 macOS。在 App Store Connect 中可以取消配置。
- 允許在 iOS 上安裝的應用程序安裝在 macOS 上,但是添加檢查可用的可選硬件功能。
- 增強該應用程序,使 Mac 用戶更易于使用替代功能。 例如,添加iOS鍵盤支持。
- 添加代碼以檢測 iOS-on-Mac 的場景。
- 通過 Mac Catalyst 技術連接到Mac。這意味著首先得擁有一個出色的iPadOS應用。
- 編寫純原生 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()
.
.