Skip to content

Commit 739d21a

Browse files
authored
Crashlytics add support for x86 apps running on Rosetta 2 (#6890)
1 parent 5d793ae commit 739d21a

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

Crashlytics/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Unreleased
2+
- [added] Added Crashlytics support for x86 apps running on Apple Silicon via Rosetta 2
3+
- [changed] Decreased Crashlytics CocoaPods minimum deployment target from iOS 10 to iOS 9
24
- [changed] Removed obsolete API calls from upload-symbols
35
- [changed] Removed obsolete onboarding calls from the SDK.
4-
- [changed] Decreased Crashlytics CocoaPods minimum deployment target from iOS 10 to iOS 9
56

67
# v7.1.0
78
- [fixed] Fixed an issue where symbol uploads would fail when there are spaces in the project path, particularly in Unity builds (#6789).

Crashlytics/Crashlytics/Components/FIRCLSHost.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,6 @@ bool FIRCLSHostRecord(FIRCLSFile* file);
3434

3535
void FIRCLSHostWriteDiskUsage(FIRCLSFile* file);
3636

37+
bool FIRCLSHostIsRosettaTranslated(void);
38+
3739
__END_DECLS

Crashlytics/Crashlytics/Components/FIRCLSHost.m

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
#endif
3333

3434
#define CLS_HOST_SYSCTL_BUFFER_SIZE (128)
35+
#define CLS_MAX_ARM64_NATIVE_PAGE_SIZE (1024 * 16)
3536

3637
#if CLS_CPU_ARM64
37-
#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 16)
38+
#define CLS_MAX_NATIVE_PAGE_SIZE CLS_MAX_ARM64_NATIVE_PAGE_SIZE
3839
#else
3940
// return 4K, which is correct for all platforms except arm64, currently
4041
#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 4)
@@ -68,22 +69,32 @@ vm_size_t FIRCLSHostGetPageSize(void) {
6869
// these types. Turns out that sysctl will not init the data to zero, but it appears
6970
// that sysctlbyname does. This API is nicer, but that's important to keep in mind.
7071

72+
int maxNativePageSize = CLS_MAX_NATIVE_PAGE_SIZE;
73+
74+
// On Apple Silicon, we need to use the arm64 page size
75+
// even if we're in x86 land.
76+
if (FIRCLSHostIsRosettaTranslated()) {
77+
FIRCLSSDKLog("Running under Rosetta 2 emulation. Using the arm64 page size.\n");
78+
79+
maxNativePageSize = CLS_MAX_ARM64_NATIVE_PAGE_SIZE;
80+
}
81+
7182
pageSize = 0;
7283
size = sizeof(pageSize);
7384
if (sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0) != 0) {
7485
FIRCLSSDKLog("sysctlbyname failed while trying to get hw.pagesize\n");
7586

76-
return CLS_MAX_NATIVE_PAGE_SIZE;
87+
return maxNativePageSize;
7788
}
7889

7990
// if the returned size is not the expected value, abort
8091
if (size != sizeof(pageSize)) {
81-
return CLS_MAX_NATIVE_PAGE_SIZE;
92+
return maxNativePageSize;
8293
}
8394

8495
// put in some guards to make sure our size is reasonable
85-
if (pageSize > CLS_MAX_NATIVE_PAGE_SIZE) {
86-
return CLS_MAX_NATIVE_PAGE_SIZE;
96+
if (pageSize > maxNativePageSize) {
97+
return maxNativePageSize;
8798
}
8899

89100
if (pageSize < CLS_MIN_NATIVE_PAGE_SIZE) {
@@ -93,6 +104,29 @@ vm_size_t FIRCLSHostGetPageSize(void) {
93104
return pageSize;
94105
}
95106

107+
// This comes from the Apple documentation here:
108+
// https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment
109+
bool FIRCLSHostIsRosettaTranslated() {
110+
#if TARGET_OS_MAC
111+
int result = 0;
112+
size_t size = sizeof(result);
113+
if (sysctlbyname("sysctl.proc_translated", &result, &size, NULL, 0) == -1) {
114+
// If we get an error, or 0, we're going to treat this as x86_64 macOS native
115+
if (errno == ENOENT) {
116+
return false;
117+
}
118+
// This is the error case
119+
FIRCLSSDKLog("sysctlbyname failed while trying to get sysctl.proc_translated for Rosetta 2 "
120+
"translation\n");
121+
return false;
122+
}
123+
return result == 1;
124+
125+
#else
126+
return false;
127+
#endif
128+
}
129+
96130
static void FIRCLSHostWriteSysctlEntry(
97131
FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize) {
98132
if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) {

Crashlytics/Crashlytics/Components/FIRCLSProcess.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,14 @@ static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process,
216216
#if !TARGET_OS_WATCH
217217
// try to get the value by querying the thread state
218218
mach_msg_type_number_t stateCount = FIRCLSThreadStateCount;
219-
if (thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)),
220-
&stateCount) != KERN_SUCCESS) {
221-
FIRCLSSDKLogError("failed to get thread state\n");
219+
220+
// For unknown reasons, thread_get_state returns this value on Rosetta,
221+
// but still succeeds.
222+
const int ROSETTA_SUCCESS = 268435459;
223+
kern_return_t status = thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)),
224+
&stateCount);
225+
if (status != KERN_SUCCESS && status != ROSETTA_SUCCESS) {
226+
FIRCLSSDKLogError("Failed to get thread state via thread_get_state for thread: %i\n", thread);
222227
return false;
223228
}
224229

@@ -546,6 +551,11 @@ void FIRCLSProcessRecordDispatchQueueNames(FIRCLSProcess *process, FIRCLSFile *f
546551

547552
name = FIRCLSProcessGetThreadDispatchQueueName(process, thread);
548553

554+
// Apple Report Converter will fail to parse this when "name" is null,
555+
// so we will use an empty string instead.
556+
if (name == NULL) {
557+
name = "";
558+
}
549559
FIRCLSFileWriteArrayEntryString(file, name);
550560
}
551561

0 commit comments

Comments
 (0)