mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
mac: Add CrashpadClient::UseSystemDefaultHandler()
Chrome’s relauncher process needs a way to sever ties with the crashpad_handler instance running from the disk image in order to cause that instance to exit so that the disk image may be unmounted. This new function is otherwise not thought to be interesting, and its use is not recommended. This comes with a small refactoring to create a SystemCrashReporterHandler() function, and a fix for a minor port leak in CrashReportExceptionHandler::CatchMachException(). BUG=chromium:538373 R=rsesek@chromium.org Review URL: https://codereview.chromium.org/1375573005 .
This commit is contained in:
parent
ccd5ec6404
commit
cd85c9f700
@ -122,6 +122,30 @@ class CrashpadClient {
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
bool UseHandler();
|
||||
|
||||
#if defined(OS_MACOSX) || DOXYGEN
|
||||
//! \brief Configures the process to direct its crashes to the default handler
|
||||
//! for the operating system.
|
||||
//!
|
||||
//! On OS X, this sets the task’s exception port as in UseHandler(), but the
|
||||
//! exception handler used is obtained from SystemCrashReporterHandler(). If
|
||||
//! the system’s crash reporter handler cannot be determined, the task’s
|
||||
//! exception ports for crash-type exceptions are cleared.
|
||||
//!
|
||||
//! Use of this function is strongly discouraged.
|
||||
//!
|
||||
//! \warning After a successful call to this function, Crashpad will no longer
|
||||
//! monitor the process for crashes until a subsequent call to
|
||||
//! UseHandler().
|
||||
//!
|
||||
//! \note This is provided as a static function to allow it to be used in
|
||||
//! situations where a CrashpadClient object is not otherwise available.
|
||||
//! This may be useful when a child process inherits its parent’s Crashpad
|
||||
//! handler, but wants to sever this tie.
|
||||
//!
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
static bool UseSystemDefaultHandler();
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined(OS_MACOSX)
|
||||
base::mac::ScopedMachSendRight exception_port_;
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/posix/close_multiple.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string FormatArgumentString(const std::string& name,
|
||||
@ -37,9 +39,45 @@ std::string FormatArgumentInt(const std::string& name, int value) {
|
||||
return base::StringPrintf("--%s=%d", name.c_str(), value);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Set the exception handler for EXC_CRASH, EXC_RESOURCE, and EXC_GUARD.
|
||||
//
|
||||
// EXC_CRASH is how most crashes are received. Most other exception types such
|
||||
// as EXC_BAD_ACCESS are delivered to a host-level exception handler in the
|
||||
// kernel where they are converted to POSIX signals. See 10.9.5
|
||||
// xnu-2422.115.4/bsd/uxkern/ux_exception.c catch_mach_exception_raise(). If a
|
||||
// core-generating signal (triggered through this hardware mechanism or a
|
||||
// software mechanism such as abort() sending SIGABRT) is unhandled and the
|
||||
// process exits, or if the process is killed with SIGKILL for code-signing
|
||||
// reasons, an EXC_CRASH exception will be sent. See 10.9.5
|
||||
// xnu-2422.115.4/bsd/kern/kern_exit.c proc_prepareexit().
|
||||
//
|
||||
// EXC_RESOURCE and EXC_GUARD do not become signals or EXC_CRASH exceptions. The
|
||||
// host-level exception handler in the kernel does not receive these exception
|
||||
// types, and even if it did, it would not map them to signals. Instead, the
|
||||
// first Mach service loaded by the root (process ID 1) launchd with a boolean
|
||||
// “ExceptionServer” property in its job dictionary (regardless of its value) or
|
||||
// with any subdictionary property will become the host-level exception handler
|
||||
// for EXC_CRASH, EXC_RESOURCE, and EXC_GUARD. See 10.9.5
|
||||
// launchd-842.92.1/src/core.c job_setup_exception_port(). Normally, this job is
|
||||
// com.apple.ReportCrash.Root, the systemwide Apple Crash Reporter. Since it is
|
||||
// impossible to receive EXC_RESOURCE and EXC_GUARD exceptions through the
|
||||
// EXC_CRASH mechanism, an exception handler must be registered for them by name
|
||||
// if it is to receive these exception types. The default task-level handler for
|
||||
// these exception types is set by launchd in a similar manner.
|
||||
//
|
||||
// EXC_MASK_RESOURCE and EXC_MASK_GUARD are not available on all systems, and
|
||||
// the kernel will reject attempts to use them if it does not understand them,
|
||||
// so AND them with ExcMaskValid(). EXC_MASK_CRASH is always supported.
|
||||
bool SetCrashExceptionPorts(exception_handler_t exception_handler) {
|
||||
ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL);
|
||||
return exception_ports.SetExceptionPort(
|
||||
(EXC_MASK_CRASH | EXC_MASK_RESOURCE | EXC_MASK_GUARD) & ExcMaskValid(),
|
||||
exception_handler,
|
||||
EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
|
||||
MACHINE_THREAD_STATE);
|
||||
}
|
||||
|
||||
namespace crashpad {
|
||||
} // namespace
|
||||
|
||||
CrashpadClient::CrashpadClient()
|
||||
: exception_port_() {
|
||||
@ -179,46 +217,17 @@ bool CrashpadClient::StartHandler(
|
||||
bool CrashpadClient::UseHandler() {
|
||||
DCHECK_NE(exception_port_, kMachPortNull);
|
||||
|
||||
// Set the exception handler for EXC_CRASH, EXC_RESOURCE, and EXC_GUARD.
|
||||
//
|
||||
// EXC_CRASH is how most crashes are received. Most other exception types such
|
||||
// as EXC_BAD_ACCESS are delivered to a host-level exception handler in the
|
||||
// kernel where they are converted to POSIX signals. See 10.9.5
|
||||
// xnu-2422.115.4/bsd/uxkern/ux_exception.c catch_mach_exception_raise(). If a
|
||||
// core-generating signal (triggered through this hardware mechanism or a
|
||||
// software mechanism such as abort() sending SIGABRT) is unhandled and the
|
||||
// process exits, or if the process is killed with SIGKILL for code-signing
|
||||
// reasons, an EXC_CRASH exception will be sent. See 10.9.5
|
||||
// xnu-2422.115.4/bsd/kern/kern_exit.c proc_prepareexit().
|
||||
//
|
||||
// EXC_RESOURCE and EXC_GUARD do not become signals or EXC_CRASH exceptions.
|
||||
// The host-level exception handler in the kernel does not receive these
|
||||
// exception types, and even if it did, it would not map them to signals.
|
||||
// Instead, the first Mach service loaded by the root (process ID 1) launchd
|
||||
// with a boolean “ExceptionServer” property in its job dictionary (regardless
|
||||
// of its value) or with any subdictionary property will become the host-level
|
||||
// exception handler for EXC_CRASH, EXC_RESOURCE, and EXC_GUARD. See 10.9.5
|
||||
// launchd-842.92.1/src/core.c job_setup_exception_port(). Normally, this job
|
||||
// is com.apple.ReportCrash.Root, the systemwide Apple Crash Reporter. Since
|
||||
// it is impossible to receive EXC_RESOURCE and EXC_GUARD exceptions through
|
||||
// the EXC_CRASH mechanism, an exception handler must be registered for them
|
||||
// by name if it is to receive these exception types. The default task-level
|
||||
// handler for these exception types is set by launchd in a similar manner.
|
||||
//
|
||||
// EXC_MASK_RESOURCE and EXC_MASK_GUARD are not available on all systems, and
|
||||
// the kernel will reject attempts to use them if it does not understand them,
|
||||
// so AND them with ExcMaskValid(). EXC_MASK_CRASH is always supported.
|
||||
ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL);
|
||||
if (!exception_ports.SetExceptionPort(
|
||||
(EXC_MASK_CRASH | EXC_MASK_RESOURCE | EXC_MASK_GUARD) &
|
||||
ExcMaskValid(),
|
||||
exception_port_,
|
||||
EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
|
||||
MACHINE_THREAD_STATE)) {
|
||||
return false;
|
||||
}
|
||||
return SetCrashExceptionPorts(exception_port_);
|
||||
}
|
||||
|
||||
return true;
|
||||
// static
|
||||
bool CrashpadClient::UseSystemDefaultHandler() {
|
||||
base::mac::ScopedMachSendRight
|
||||
system_crash_reporter_handler(SystemCrashReporterHandler());
|
||||
|
||||
// Proceed even if SystemCrashReporterHandler() failed, setting MACH_PORT_NULL
|
||||
// to clear the current exception ports.
|
||||
return SetCrashExceptionPorts(system_crash_reporter_handler);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -14,12 +14,11 @@
|
||||
|
||||
#include "handler/mac/crash_report_exception_handler.h"
|
||||
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/mac/mach_logging.h"
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "client/settings.h"
|
||||
#include "minidump/minidump_file_writer.h"
|
||||
@ -202,15 +201,9 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
|
||||
// Note that normally, EXC_RESOURCE and EXC_GUARD exceptions are sent to the
|
||||
// system-level com.apple.ReportCrash.Root job, and not to the user-level
|
||||
// job that they are forwarded to here.
|
||||
mach_port_t system_crash_reporter_port;
|
||||
const char kSystemCrashReporterServiceName[] = "com.apple.ReportCrash";
|
||||
kern_return_t kr = bootstrap_look_up(bootstrap_port,
|
||||
kSystemCrashReporterServiceName,
|
||||
&system_crash_reporter_port);
|
||||
if (kr != BOOTSTRAP_SUCCESS) {
|
||||
BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up "
|
||||
<< kSystemCrashReporterServiceName;
|
||||
} else {
|
||||
base::mac::ScopedMachSendRight
|
||||
system_crash_reporter_handler(SystemCrashReporterHandler());
|
||||
if (system_crash_reporter_handler) {
|
||||
// Make copies of mutable out parameters so that the system crash reporter
|
||||
// can’t influence the state returned by this method.
|
||||
thread_state_flavor_t flavor_forward = *flavor;
|
||||
@ -227,9 +220,9 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
|
||||
// problems may arise if the state wasn’t available and the system crash
|
||||
// reporter changes in the future to use it. However, normally, the state
|
||||
// will be available.
|
||||
kr = UniversalExceptionRaise(
|
||||
kern_return_t kr = UniversalExceptionRaise(
|
||||
EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
|
||||
system_crash_reporter_port,
|
||||
system_crash_reporter_handler,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
@ -240,8 +233,7 @@ kern_return_t CrashReportExceptionHandler::CatchMachException(
|
||||
old_state_count,
|
||||
new_state_forward_count ? &new_state_forward[0] : nullptr,
|
||||
&new_state_forward_count);
|
||||
MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr)
|
||||
<< "UniversalExceptionRaise " << kSystemCrashReporterServiceName;
|
||||
MACH_LOG_IF(WARNING, kr != KERN_SUCCESS, kr) << "UniversalExceptionRaise";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <pthread.h>
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
#include "base/mac/mach_logging.h"
|
||||
#include "util/mac/mac_util.h"
|
||||
@ -96,4 +97,19 @@ exception_mask_t ExcMaskValid() {
|
||||
return kExcMaskValid_10_11;
|
||||
}
|
||||
|
||||
base::mac::ScopedMachSendRight SystemCrashReporterHandler() {
|
||||
const char kSystemCrashReporterServiceName[] = "com.apple.ReportCrash";
|
||||
exception_handler_t system_crash_reporter_handler;
|
||||
kern_return_t kr = bootstrap_look_up(bootstrap_port,
|
||||
kSystemCrashReporterServiceName,
|
||||
&system_crash_reporter_handler);
|
||||
if (kr != BOOTSTRAP_SUCCESS) {
|
||||
BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up "
|
||||
<< kSystemCrashReporterServiceName;
|
||||
system_crash_reporter_handler = MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
return base::mac::ScopedMachSendRight(system_crash_reporter_handler);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief `MACH_PORT_NULL` with the correct type for a Mach port,
|
||||
@ -115,6 +117,20 @@ exception_mask_t ExcMaskAll();
|
||||
//! support is present.
|
||||
exception_mask_t ExcMaskValid();
|
||||
|
||||
//! \brief Obtains the system’s default Mach exception handler for crash-type
|
||||
//! exceptions.
|
||||
//!
|
||||
//! This is obtained by looking up `"com.apple.ReportCrash"` with the bootstrap
|
||||
//! server. The service name comes from the first launch agent loaded by
|
||||
//! `launchd` with a `MachServices` entry having `ExceptionServer` set. This
|
||||
//! launch agent is normally loaded from
|
||||
//! `/System/Library/LaunchAgents/com.apple.ReportCrash.plist`.
|
||||
//!
|
||||
//! \return On success, a send right to an `exception_handler_t` corresponding
|
||||
//! to the system’s default crash reporter. On failure, `MACH_PORT_NULL`,
|
||||
//! with a message logged.
|
||||
base::mac::ScopedMachSendRight SystemCrashReporterHandler();
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MACH_MACH_EXTENSIONS_H_
|
||||
|
@ -131,6 +131,12 @@ TEST(MachExtensions, ExcMaskValid) {
|
||||
EXPECT_TRUE(ExcMaskValid() & ~ExcMaskAll());
|
||||
}
|
||||
|
||||
TEST(MachExtensions, SystemCrashReporterHandler) {
|
||||
base::mac::ScopedMachSendRight
|
||||
system_crash_reporter_handler(SystemCrashReporterHandler());
|
||||
EXPECT_TRUE(system_crash_reporter_handler);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
Loading…
x
Reference in New Issue
Block a user