crashpad/client/crashpad_client_ios.cc
Justin Cohen b2fd7d5307 [ios] Bring up first half of UncaughtExceptionHandler.
When code raises an Objective-C exception, unwind the stack looking for
any exception handlers. If an exception handler is encountered, test to
see if it is a function known to be a catch-and-rethrow 'sinkhole'
exception handler. Various routines in UIKit and elsewhere do this, and
they obscure the exception stack, since the original throw location is
no longer present on the stack (just the re-throw) when Crashpad
captures the crash report. In the case of sinkholes, trigger an
immediate exception to capture the original stack.

The is an improvement over the alternative,
NSSetUncaughtExceptionHandler, which passes along the stack frames, but
not the stack memory contents and full exception context itself.

The details of what happens after a fatal exception is triggered are
unresolved in this CL.  For now, simply call std::terminate.

This code was inspired by chromium/src/chrome/browser/mac/
exception_processor.mm.

Bug: crashpad:31
Change-Id: Ieebc6476a0507c466c8219c10f790ec0a624e58c
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2125254
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
2020-04-08 20:57:21 +00:00

99 lines
3.0 KiB
C++

// Copyright 2020 The Crashpad Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "client/crashpad_client.h"
#include <unistd.h>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "client/client_argv_handling.h"
#include "snapshot/ios/process_snapshot_ios.h"
#include "util/ios/exception_processor.h"
#include "util/ios/ios_system_data_collector.h"
#include "util/posix/signals.h"
namespace crashpad {
namespace {
// A base class for Crashpad signal handler implementations.
class SignalHandler {
public:
// Returns the currently installed signal hander.
static SignalHandler* Get() {
static SignalHandler* instance = new SignalHandler();
return instance;
}
bool Install(const std::set<int>* unhandled_signals) {
return Signals::InstallCrashHandlers(
HandleSignal, 0, &old_actions_, unhandled_signals);
}
void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
// TODO(justincohen): This is incomplete.
ProcessSnapshotIOS process_snapshot;
process_snapshot.Initialize(system_data);
process_snapshot.SetException(siginfo,
reinterpret_cast<ucontext_t*>(context));
}
private:
SignalHandler() = default;
// The base implementation for all signal handlers, suitable for calling
// directly to simulate signal delivery.
void HandleCrashAndReraiseSignal(int signo,
siginfo_t* siginfo,
void* context) {
HandleCrash(signo, siginfo, context);
// Always call system handler.
Signals::RestoreHandlerAndReraiseSignalOnReturn(
siginfo, old_actions_.ActionForSignal(signo));
}
// The signal handler installed at OS-level.
static void HandleSignal(int signo, siginfo_t* siginfo, void* context) {
Get()->HandleCrashAndReraiseSignal(signo, siginfo, context);
}
Signals::OldActions old_actions_ = {};
// Collect some system data before the signal handler is triggered.
IOSSystemDataCollector system_data;
DISALLOW_COPY_AND_ASSIGN(SignalHandler);
};
} // namespace
CrashpadClient::CrashpadClient() {}
CrashpadClient::~CrashpadClient() {}
bool CrashpadClient::StartCrashpadInProcessHandler() {
InstallObjcExceptionPreprocessor();
return SignalHandler::Get()->Install(nullptr);
}
// static
void CrashpadClient::DumpWithoutCrash() {
DCHECK(SignalHandler::Get());
siginfo_t siginfo = {};
SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr);
}
} // namespace crashpad