| Index: util/mach/exception_ports.cc
|
| diff --git a/util/mach/exception_ports.cc b/util/mach/exception_ports.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..b96517c64bdbc513777eb12ebdfc9e962bef4fa7
|
| --- /dev/null
|
| +++ b/util/mach/exception_ports.cc
|
| @@ -0,0 +1,131 @@
|
| +// Copyright 2014 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 "util/mach/exception_ports.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/mac/mach_logging.h"
|
| +
|
| +namespace crashpad {
|
| +
|
| +ExceptionPorts::ExceptionPorts(TargetType target_type, mach_port_t target_port)
|
| + : target_port_(target_port), dealloc_target_port_(false) {
|
| + switch (target_type) {
|
| + case kTargetTypeHost:
|
| + get_exception_ports_ = host_get_exception_ports;
|
| + set_exception_ports_ = host_set_exception_ports;
|
| + target_name_ = "host";
|
| + if (target_port_ == MACH_PORT_NULL) {
|
| + target_port_ = mach_host_self();
|
| + dealloc_target_port_ = true;
|
| + }
|
| + break;
|
| +
|
| + case kTargetTypeTask:
|
| + get_exception_ports_ = task_get_exception_ports;
|
| + set_exception_ports_ = task_set_exception_ports;
|
| + target_name_ = "task";
|
| + if (target_port_ == MACH_PORT_NULL) {
|
| + target_port_ = mach_task_self();
|
| + // Don’t deallocate mach_task_self().
|
| + }
|
| + break;
|
| +
|
| + case kTargetTypeThread:
|
| + get_exception_ports_ = thread_get_exception_ports;
|
| + set_exception_ports_ = thread_set_exception_ports;
|
| + target_name_ = "thread";
|
| + if (target_port_ == MACH_PORT_NULL) {
|
| + target_port_ = mach_thread_self();
|
| + dealloc_target_port_ = true;
|
| + }
|
| + break;
|
| +
|
| + default:
|
| + NOTREACHED();
|
| + get_exception_ports_ = NULL;
|
| + set_exception_ports_ = NULL;
|
| + target_name_ = NULL;
|
| + target_port_ = MACH_PORT_NULL;
|
| + break;
|
| + }
|
| +}
|
| +
|
| +ExceptionPorts::~ExceptionPorts() {
|
| + if (dealloc_target_port_) {
|
| + kern_return_t kr = mach_port_deallocate(mach_task_self(), target_port_);
|
| + MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
|
| + }
|
| +}
|
| +
|
| +bool ExceptionPorts::GetExceptionPorts(
|
| + exception_mask_t mask,
|
| + std::vector<ExceptionHandler>* handlers) const {
|
| + // <mach/mach_types.defs> says that these arrays have room for 32 elements,
|
| + // despite EXC_TYPES_COUNT only being as low as 11 (in the 10.6 SDK), and
|
| + // later operating system versions have defined more exception types. The
|
| + // generated task_get_exception_ports() in taskUser.c expects there to be room
|
| + // for 32.
|
| + const int kMaxPorts = 32;
|
| +
|
| + // task_get_exception_ports() doesn’t actually use the initial value of
|
| + // handler_count, but 10.9.4
|
| + // xnu-2422.110.17/osfmk/man/task_get_exception_ports.html says it does. Humor
|
| + // the documentation.
|
| + mach_msg_type_number_t handler_count = kMaxPorts;
|
| +
|
| + exception_mask_t masks[kMaxPorts];
|
| + exception_handler_t ports[kMaxPorts];
|
| + exception_behavior_t behaviors[kMaxPorts];
|
| + thread_state_flavor_t flavors[kMaxPorts];
|
| +
|
| + kern_return_t kr = get_exception_ports_(
|
| + target_port_, mask, masks, &handler_count, ports, behaviors, flavors);
|
| + if (kr != KERN_SUCCESS) {
|
| + MACH_LOG(ERROR, kr) << TargetTypeName() << "_get_exception_ports";
|
| + return false;
|
| + }
|
| +
|
| + handlers->clear();
|
| + for (mach_msg_type_number_t index = 0; index < handler_count; ++index) {
|
| + ExceptionHandler handler;
|
| + handler.mask = masks[index];
|
| + handler.port = ports[index];
|
| + handler.behavior = behaviors[index];
|
| + handler.flavor = flavors[index];
|
| + handlers->push_back(handler);
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool ExceptionPorts::SetExceptionPort(exception_mask_t mask,
|
| + exception_handler_t port,
|
| + exception_behavior_t behavior,
|
| + thread_state_flavor_t flavor) const {
|
| + kern_return_t kr =
|
| + set_exception_ports_(target_port_, mask, port, behavior, flavor);
|
| + if (kr != KERN_SUCCESS) {
|
| + MACH_LOG(ERROR, kr) << TargetTypeName() << "_set_exception_ports";
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +const char* ExceptionPorts::TargetTypeName() const {
|
| + return target_name_;
|
| +}
|
| +
|
| +} // namespace crashpad
|
|
|