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>
This commit is contained in:
Justin Cohen 2022-01-14 22:25:59 -05:00 committed by Crashpad LUCI CQ
parent 824ddb2de1
commit 243e1fd8e2
4 changed files with 106 additions and 57 deletions

View File

@ -131,10 +131,16 @@ bool ExceptionSnapshotIOSIntermediateDump::InitializeFromSignal(
#endif #endif
} }
GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_); exception_ = EXC_SOFT_SIGNAL;
GetDataValueFromMap(exception_data, Key::kSignalCode, &exception_info_); GetDataValueFromMap(exception_data, Key::kSignalNumber, &exception_info_);
GetDataValueFromMap(exception_data, Key::kSignalAddress, &exception_address_); 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_); INITIALIZATION_STATE_SET_VALID(initialized_);
return true; return true;
} }

View File

@ -65,7 +65,7 @@
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
} }
- (void)verifyCrashReportException:(int)exception { - (void)verifyCrashReportException:(uint32_t)exception {
// Confirm the app is not running. // Confirm the app is not running.
XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]); XCTAssertTrue([app_ waitForState:XCUIApplicationStateNotRunning timeout:15]);
XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning); XCTAssertTrue(app_.state == XCUIApplicationStateNotRunning);
@ -75,7 +75,9 @@
XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground); XCTAssertTrue(app_.state == XCUIApplicationStateRunningForeground);
rootObject_ = [EDOClientService rootObjectWithPort:12345]; rootObject_ = [EDOClientService rootObjectWithPort:12345];
XCTAssertEqual([rootObject_ pendingReportCount], 1); XCTAssertEqual([rootObject_ pendingReportCount], 1);
XCTAssertEqual([rootObject_ pendingReportException], exception); NSNumber* report_exception;
XCTAssertTrue([rootObject_ pendingReportException:&report_exception]);
XCTAssertEqual(report_exception.unsignedIntValue, exception);
} }
- (void)testEDO { - (void)testEDO {
@ -85,44 +87,61 @@
- (void)testSegv { - (void)testSegv {
[rootObject_ crashSegv]; [rootObject_ crashSegv];
#if defined(NDEBUG) && TARGET_OS_SIMULATOR #if defined(NDEBUG)
[self verifyCrashReportException:SIGINT]; #if TARGET_OS_SIMULATOR
[self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else #else
[self verifyCrashReportException:SIGHUP]; [self verifyCrashReportException:EXC_BREAKPOINT];
#endif
#else
[self verifyCrashReportException:EXC_BAD_ACCESS];
#endif #endif
} }
- (void)testKillAbort { - (void)testKillAbort {
[rootObject_ crashKillAbort]; [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 { - (void)testTrap {
[rootObject_ crashTrap]; [rootObject_ crashTrap];
#if TARGET_OS_SIMULATOR #if TARGET_OS_SIMULATOR
[self verifyCrashReportException:SIGINT]; [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else #else
[self verifyCrashReportException:SIGABRT]; [self verifyCrashReportException:EXC_BREAKPOINT];
#endif #endif
} }
- (void)testAbort { - (void)testAbort {
[rootObject_ crashAbort]; [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 { - (void)testBadAccess {
[rootObject_ crashBadAccess]; [rootObject_ crashBadAccess];
#if defined(NDEBUG) && TARGET_OS_SIMULATOR #if defined(NDEBUG)
[self verifyCrashReportException:SIGINT]; #if TARGET_OS_SIMULATOR
[self verifyCrashReportException:EXC_BAD_INSTRUCTION];
#else #else
[self verifyCrashReportException:SIGHUP]; [self verifyCrashReportException:EXC_BREAKPOINT];
#endif
#else
[self verifyCrashReportException:EXC_BAD_ACCESS];
#endif #endif
} }
- (void)testException { - (void)testException {
[rootObject_ crashException]; [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 { - (void)testNSException {
@ -183,7 +202,7 @@
- (void)testRecursion { - (void)testRecursion {
[rootObject_ crashRecursion]; [rootObject_ crashRecursion];
[self verifyCrashReportException:SIGHUP]; [self verifyCrashReportException:EXC_BAD_ACCESS];
} }
- (void)testClientAnnotations { - (void)testClientAnnotations {
@ -192,7 +211,11 @@
// Set app launch args to trigger different client annotations. // Set app launch args to trigger different client annotations.
NSArray<NSString*>* old_args = app_.launchArguments; NSArray<NSString*>* old_args = app_.launchArguments;
app_.launchArguments = @[ @"--alternate-client-annotations" ]; 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; app_.launchArguments = old_args;
// Confirm the initial crash took the standard annotations. // Confirm the initial crash took the standard annotations.
@ -205,7 +228,10 @@
// Confirm passing alternate client annotation args works. // Confirm passing alternate client annotation args works.
[rootObject_ clearPendingReports]; [rootObject_ clearPendingReports];
[rootObject_ crashKillAbort]; [rootObject_ crashKillAbort];
[self verifyCrashReportException:SIGABRT]; [self verifyCrashReportException:EXC_SOFT_SIGNAL];
XCTAssertTrue([rootObject_ pendingReportExceptionInfo:&report_exception]);
XCTAssertEqual(report_exception.intValue, SIGABRT);
dict = [rootObject_ getProcessAnnotations]; dict = [rootObject_ getProcessAnnotations];
XCTAssertTrue([dict[@"crashpad"] isEqualToString:@"no"]); XCTAssertTrue([dict[@"crashpad"] isEqualToString:@"no"]);
XCTAssertTrue([dict[@"plat"] isEqualToString:@"macOS"]); XCTAssertTrue([dict[@"plat"] isEqualToString:@"macOS"]);
@ -220,7 +246,7 @@
return; return;
} }
[rootObject_ crashWithCrashInfoMessage]; [rootObject_ crashWithCrashInfoMessage];
[self verifyCrashReportException:SIGHUP]; [self verifyCrashReportException:EXC_BAD_ACCESS];
NSDictionary* dict = [rootObject_ getAnnotations]; NSDictionary* dict = [rootObject_ getAnnotations];
NSString* dyldMessage = dict[@"vector"][0]; NSString* dyldMessage = dict[@"vector"][0];
XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]); XCTAssertTrue([dyldMessage isEqualToString:@"dyld: in dlsym()"]);
@ -235,7 +261,7 @@
return; return;
} }
[rootObject_ crashWithDyldErrorString]; [rootObject_ crashWithDyldErrorString];
[self verifyCrashReportException:SIGINT]; [self verifyCrashReportException:EXC_BAD_INSTRUCTION];
NSArray* vector = [rootObject_ getAnnotations][@"vector"]; NSArray* vector = [rootObject_ getAnnotations][@"vector"];
// This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp
// ImageLoaderMachO::doInitialization(). // ImageLoaderMachO::doInitialization().
@ -246,7 +272,11 @@
- (void)testCrashWithAnnotations { - (void)testCrashWithAnnotations {
[rootObject_ crashWithAnnotations]; [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* dict = [rootObject_ getAnnotations];
NSDictionary* simpleMap = dict[@"simplemap"]; NSDictionary* simpleMap = dict[@"simplemap"];
XCTAssertTrue([simpleMap[@"#TEST# empty_value"] isEqualToString:@""]); XCTAssertTrue([simpleMap[@"#TEST# empty_value"] isEqualToString:@""]);

View File

@ -68,6 +68,24 @@ OperationStatus GetPendingReports(std::vector<Report>* pending_reports) {
return database->GetPendingReports(pending_reports); 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) { [[clang::optnone]] void recurse(int counter) {
// Fill up the stack faster. // Fill up the stack faster.
int arr[1024]; int arr[1024];
@ -159,40 +177,36 @@ OperationStatus GetPendingReports(std::vector<Report>* pending_reports) {
return pending_reports.size(); return pending_reports.size();
} }
- (int)pendingReportException { - (bool)pendingReportException:(NSNumber**)exception {
std::vector<Report> pending_reports; auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
OperationStatus status = GetPendingReports(&pending_reports); if (!process_snapshot || !process_snapshot->Exception()->Exception())
if (status != crashpad::CrashReportDatabase::kNoError || return false;
pending_reports.size() != 1) { *exception = [NSNumber
return -1; numberWithUnsignedInt:process_snapshot->Exception()->Exception()];
} return true;
}
auto reader = std::make_unique<crashpad::FileReader>(); - (bool)pendingReportExceptionInfo:(NSNumber**)exception_info {
reader->Open(pending_reports[0].file_path); auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
crashpad::ProcessSnapshotMinidump process_snapshot; if (!process_snapshot || !process_snapshot->Exception()->ExceptionInfo())
process_snapshot.Initialize(reader.get()); return false;
return static_cast<int>(process_snapshot.Exception()->Exception());
*exception_info = [NSNumber
numberWithUnsignedInt:process_snapshot->Exception()->ExceptionInfo()];
return true;
} }
- (NSDictionary*)getAnnotations { - (NSDictionary*)getAnnotations {
std::vector<Report> pending_reports; auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
OperationStatus status = GetPendingReports(&pending_reports); if (!process_snapshot)
if (status != crashpad::CrashReportDatabase::kNoError ||
pending_reports.size() != 1) {
return @{}; 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 = @{ NSDictionary* dict = @{
@"simplemap" : [@{} mutableCopy], @"simplemap" : [@{} mutableCopy],
@"vector" : [@[] mutableCopy], @"vector" : [@[] mutableCopy],
@"objects" : [@[] mutableCopy] @"objects" : [@[] mutableCopy]
}; };
for (const auto* module : process_snapshot.Modules()) { for (const auto* module : process_snapshot->Modules()) {
for (const auto& kv : module->AnnotationsSimpleMap()) { for (const auto& kv : module->AnnotationsSimpleMap()) {
[dict[@"simplemap"] setValue:@(kv.second.c_str()) [dict[@"simplemap"] setValue:@(kv.second.c_str())
forKey:@(kv.first.c_str())]; forKey:@(kv.first.c_str())];
@ -215,19 +229,12 @@ OperationStatus GetPendingReports(std::vector<Report>* pending_reports) {
} }
- (NSDictionary*)getProcessAnnotations { - (NSDictionary*)getProcessAnnotations {
std::vector<Report> pending_reports; auto process_snapshot = GetProcessSnapshotMinidumpFromSinglePending();
OperationStatus status = GetPendingReports(&pending_reports); if (!process_snapshot)
if (status != crashpad::CrashReportDatabase::kNoError ||
pending_reports.size() != 1) {
return @{}; 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]; 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())]; [dict setValue:@(kv.second.c_str()) forKey:@(kv.first.c_str())];
} }

View File

@ -32,9 +32,15 @@
// report. // report.
- (int)pendingReportCount; - (int)pendingReportCount;
// Returns exception code when there's a single pending report, or -1 if there's // Returns true if there's a single pending report and sets the exception code
// a different number of pending reports. // in the out |exception| parameter. Returns false if there's a different number
- (int)pendingReportException; // 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 // Return an NSDictionary with a dictionary named "simplemap", an array named
// "vector" and an array named "objects", representing the combination of all // "vector" and an array named "objects", representing the combination of all