ios: Set EXC_SOFT_SIGNAL for signal exceptions.
Right now there's no clear way to differentiate between Signal and Mach
exceptions. Instead, set EXC_SOFT_SIGNAL as the top level exception for
signal exceptions, moving the signal number to ExceptionInfo() and
and the signal code plus the two previous values into Codes().
Fixed:crashpad:389
Change-Id: Ia57f402b98be2a648febb58b9dee0cb80d9e5954
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3388874
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Justin Cohen <justincohen@chromium.org>
diff --git a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc
index c4d99e7..a45d4cc 100644
--- a/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc
+++ b/snapshot/ios/exception_snapshot_ios_intermediate_dump.cc
@@ -131,10 +131,16 @@
#endif
}
- GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_);
- GetDataValueFromMap(exception_data, Key::kSignalCode, &exception_info_);
+ exception_ = EXC_SOFT_SIGNAL;
+ GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_info_);
GetDataValueFromMap(exception_data, Key::kSignalAddress, &exception_address_);
+ codes_.push_back(exception_);
+ codes_.push_back(exception_info_);
+ uint32_t code;
+ GetDataValueFromMap(exception_data, Key::kSignalCode, &code);
+ codes_.push_back(code);
+
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
diff --git a/test/ios/crash_type_xctest.mm b/test/ios/crash_type_xctest.mm
index 2dcfac7..3613e22 100644
--- a/test/ios/crash_type_xctest.mm
+++ b/test/ios/crash_type_xctest.mm
@@ -65,7 +65,7 @@
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
}
-- (void)verifyCrashReportException:(int)exception {
+- (void)verifyCrashReportException:(uint32_t)exception {
// Confirm the app is not running.
XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning);
@@ -75,7 +75,9 @@
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
rootObject_ = [EDOClientService rootObjectWithPort:12345];
XCTAssertEqual([rootObject_ pendingReportCount], 1);
- XCTAssertEqual([rootObject_ pendingReportException], exception);
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportException:&report_exception]);
+ XCTAssertEqual(report_exception.unsignedIntValue, exception);
}
- (void)testEDO {
@@ -85,44 +87,61 @@
- (void)testSegv {
[rootObject_ crashSegv];
-#if defined(NDEBUG) && TARGET_OS_SIMULATOR
- [self verifyCrashReportException:SIGINT];
+#if defined(NDEBUG)
+#if TARGET_OS_SIMULATOR
+ [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else
- [self verifyCrashReportException:SIGHUP];
+ [self verifyCrashReportException:EXC_BREAKPOINT];
+#endif
+#else
+ [self verifyCrashReportException:EXC_BAD_ACCESS];
#endif
}
- (void)testKillAbort {
[rootObject_ crashKillAbort];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
}
- (void)testTrap {
[rootObject_ crashTrap];
#if TARGET_OS_SIMULATOR
- [self verifyCrashReportException:SIGINT];
+ [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_BREAKPOINT];
#endif
}
- (void)testAbort {
[rootObject_ crashAbort];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
}
- (void)testBadAccess {
[rootObject_ crashBadAccess];
-#if defined(NDEBUG) && TARGET_OS_SIMULATOR
- [self verifyCrashReportException:SIGINT];
+#if defined(NDEBUG)
+#if TARGET_OS_SIMULATOR
+ [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else
- [self verifyCrashReportException:SIGHUP];
+ [self verifyCrashReportException:EXC_BREAKPOINT];
+#endif
+#else
+ [self verifyCrashReportException:EXC_BAD_ACCESS];
#endif
}
- (void)testException {
[rootObject_ crashException];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
}
- (void)testNSException {
@@ -183,7 +202,7 @@
- (void)testRecursion {
[rootObject_ crashRecursion];
- [self verifyCrashReportException:SIGHUP];
+ [self verifyCrashReportException:EXC_BAD_ACCESS];
}
- (void)testClientAnnotations {
@@ -192,7 +211,11 @@
// Set app launch args to trigger different client annotations.
NSArray<NSString*>* old_args = app_.launchArguments;
app_.launchArguments = @[ @"--alternate-client-annotations" ];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
+
app_.launchArguments = old_args;
// Confirm the initial crash took the standard annotations.
@@ -205,7 +228,10 @@
// Confirm passing alternate client annotation args works.
[rootObject_ clearPendingReports];
[rootObject_ crashKillAbort];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
+
dict = [rootObject_ getProcessAnnotations];
XCTAssertTrue([dict[@"crashpad"] isEqualToString:@"no"]);
XCTAssertTrue([dict[@"plat"] isEqualToString:@"macOS"]);
@@ -220,7 +246,7 @@
return;
}
[rootObject_ crashWithCrashInfoMessage];
- [self verifyCrashReportException:SIGHUP];
+ [self verifyCrashReportException:EXC_BAD_ACCESS];
NSDictionary* dict = [rootObject_ getAnnotations];
NSString* dyldMessage = dict[@"vector"][0];
XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]);
@@ -235,7 +261,7 @@
return;
}
[rootObject_ crashWithDyldErrorString];
- [self verifyCrashReportException:SIGINT];
+ [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
NSArray* vector = [rootObject_ getAnnotations][@"vector"];
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization().
@@ -246,7 +272,11 @@
- (void)testCrashWithAnnotations {
[rootObject_ crashWithAnnotations];
- [self verifyCrashReportException:SIGABRT];
+ [self verifyCrashReportException:EXC_SOFT_SIGNAL];
+ NSNumber* report_exception;
+ XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
+ XCTAssertEqual(report_exception.intValue, SIGABRT);
+
NSDictionary* dict = [rootObject_ getAnnotations];
NSDictionary* simpleMap = dict[@"simplemap"];
XCTAssertTrue([simpleMap[@"#TEST# empty_value"] isEqualToString:@""]);
diff --git a/test/ios/host/cptest_application_delegate.mm b/test/ios/host/cptest_application_delegate.mm
index 44a7d88..3bf39df 100644
--- a/test/ios/host/cptest_application_delegate.mm
+++ b/test/ios/host/cptest_application_delegate.mm
@@ -68,6 +68,24 @@
return database->GetPendingReports(pending_reports);
}
+std::unique_ptr<crashpad::ProcessSnapshotMinidump>
+GetProcessSnapshotMinidumpFromSinglePending() {
+ std::vector<Report> pending_reports;
+ OperationStatus status = GetPendingReports(&pending_reports);
+ if (status != crashpad::CrashReportDatabase::kNoError ||
+ pending_reports.size() != 1) {
+ return nullptr;
+ }
+
+ auto reader = std::make_unique<crashpad::FileReader>();
+ auto process_snapshot = std::make_unique<crashpad::ProcessSnapshotMinidump>();
+ if (!reader->Open(pending_reports[0].file_path) ||
+ !process_snapshot->Initialize(reader.get())) {
+ return nullptr;
+ }
+ return process_snapshot;
+}
+
[[clang::optnone]] void recurse(int counter) {
// Fill up the stack faster.
int arr[1024];
@@ -159,40 +177,36 @@
return pending_reports.size();
}
-- (int)pendingReportException {
- std::vector<Report> pending_reports;
- OperationStatus status = GetPendingReports(&pending_reports);
- if (status != crashpad::CrashReportDatabase::kNoError ||
- pending_reports.size() != 1) {
- return -1;
- }
+- (bool)pendingReportException:(NSNumber**)exception {
+ auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
+ if (!process_snapshot || !process_snapshot->Exception()->Exception())
+ return false;
+ *exception = [NSNumber
+ numberWithUnsignedInt:process_snapshot->Exception()->Exception()];
+ return true;
+}
- auto reader = std::make_unique<crashpad::FileReader>();
- reader->Open(pending_reports[0].file_path);
- crashpad::ProcessSnapshotMinidump process_snapshot;
- process_snapshot.Initialize(reader.get());
- return static_cast<int>(process_snapshot.Exception()->Exception());
+- (bool)pendingReportExceptionInfo:(NSNumber**)exception_info {
+ auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
+ if (!process_snapshot || !process_snapshot->Exception()->ExceptionInfo())
+ return false;
+
+ *exception_info = [NSNumber
+ numberWithUnsignedInt:process_snapshot->Exception()->ExceptionInfo()];
+ return true;
}
- (NSDictionary*)getAnnotations {
- std::vector<Report> pending_reports;
- OperationStatus status = GetPendingReports(&pending_reports);
- if (status != crashpad::CrashReportDatabase::kNoError ||
- pending_reports.size() != 1) {
+ auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
+ if (!process_snapshot)
return @{};
- }
-
- auto reader = std::make_unique<crashpad::FileReader>();
- reader->Open(pending_reports[0].file_path);
- crashpad::ProcessSnapshotMinidump process_snapshot;
- process_snapshot.Initialize(reader.get());
NSDictionary* dict = @{
@"simplemap" : [@{} mutableCopy],
@"vector" : [@[] mutableCopy],
@"objects" : [@[] mutableCopy]
};
- for (const auto* module : process_snapshot.Modules()) {
+ for (const auto* module : process_snapshot->Modules()) {
for (const auto& kv : module->AnnotationsSimpleMap()) {
[dict[@"simplemap"] setValue:@(kv.second.c_str())
forKey:@(kv.first.c_str())];
@@ -215,19 +229,12 @@
}
- (NSDictionary*)getProcessAnnotations {
- std::vector<Report> pending_reports;
- OperationStatus status = GetPendingReports(&pending_reports);
- if (status != crashpad::CrashReportDatabase::kNoError ||
- pending_reports.size() != 1) {
+ auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
+ if (!process_snapshot)
return @{};
- }
- auto reader = std::make_unique<crashpad::FileReader>();
- reader->Open(pending_reports[0].file_path);
- crashpad::ProcessSnapshotMinidump process_snapshot;
- process_snapshot.Initialize(reader.get());
NSDictionary* dict = [@{} mutableCopy];
- for (const auto& kv : process_snapshot.AnnotationsSimpleMap()) {
+ for (const auto& kv : process_snapshot->AnnotationsSimpleMap()) {
[dict setValue:@(kv.second.c_str()) forKey:@(kv.first.c_str())];
}
diff --git a/test/ios/host/cptest_shared_object.h b/test/ios/host/cptest_shared_object.h
index bcd7554..90e3de8 100644
--- a/test/ios/host/cptest_shared_object.h
+++ b/test/ios/host/cptest_shared_object.h
@@ -32,9 +32,15 @@
// report.
- (int)pendingReportCount;
-// Returns exception code when there's a single pending report, or -1 if there's
-// a different number of pending reports.
-- (int)pendingReportException;
+// Returns true if there's a single pending report and sets the exception code
+// in the out |exception| parameter. Returns false if there's a different number
+// of pending reports.
+- (bool)pendingReportException:(NSNumber**)exception;
+
+// Returns true if there's a single pending report and sets the second-level
+// exception code in the out |exception_info| parameter. Returns false if
+// there's a different number of pending reports.
+- (bool)pendingReportExceptionInfo:(NSNumber**)exception_info;
// Return an NSDictionary with a dictionary named "simplemap", an array named
// "vector" and an array named "objects", representing the combination of all