2023-01-28 04:54:20 +00:00
|
|
|
|
// Copyright 2014 The Crashpad Authors
|
2022-04-02 01:21:55 +00:00
|
|
|
|
//
|
|
|
|
|
// 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"
|
|
|
|
|
#include "base/notreached.h"
|
|
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
|
|
|
|
|
|
ExceptionPorts::ExceptionHandlerVector::ExceptionHandlerVector()
|
|
|
|
|
: vector_() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ExceptionPorts::ExceptionHandlerVector::~ExceptionHandlerVector() {
|
|
|
|
|
Deallocate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExceptionPorts::ExceptionHandlerVector::clear() {
|
|
|
|
|
Deallocate();
|
|
|
|
|
vector_.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExceptionPorts::ExceptionHandlerVector::Deallocate() {
|
|
|
|
|
for (ExceptionHandler& exception_handler : vector_) {
|
|
|
|
|
if (exception_handler.port != MACH_PORT_NULL) {
|
|
|
|
|
kern_return_t kr =
|
|
|
|
|
mach_port_deallocate(mach_task_self(), exception_handler.port);
|
|
|
|
|
MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
swap_exception_ports_ = host_swap_exception_ports;
|
|
|
|
|
target_name_ = "host";
|
|
|
|
|
if (target_port_ == HOST_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;
|
|
|
|
|
swap_exception_ports_ = task_swap_exception_ports;
|
|
|
|
|
target_name_ = "task";
|
|
|
|
|
if (target_port_ == TASK_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;
|
|
|
|
|
swap_exception_ports_ = thread_swap_exception_ports;
|
|
|
|
|
target_name_ = "thread";
|
|
|
|
|
if (target_port_ == THREAD_NULL) {
|
|
|
|
|
target_port_ = mach_thread_self();
|
|
|
|
|
dealloc_target_port_ = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
NOTREACHED();
|
|
|
|
|
get_exception_ports_ = nullptr;
|
|
|
|
|
set_exception_ports_ = nullptr;
|
|
|
|
|
target_name_ = nullptr;
|
|
|
|
|
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,
|
|
|
|
|
ExceptionHandlerVector* 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.
|
|
|
|
|
constexpr 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) {
|
|
|
|
|
if (ports[index] != MACH_PORT_NULL) {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExceptionPorts::SwapExceptionPorts(
|
|
|
|
|
exception_mask_t mask,
|
|
|
|
|
exception_handler_t new_port,
|
|
|
|
|
exception_behavior_t new_behavior,
|
|
|
|
|
thread_state_flavor_t new_flavor,
|
|
|
|
|
ExceptionHandlerVector* old_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_swap_exception_ports() in taskUser.c expects there to be
|
|
|
|
|
// room for 32.
|
|
|
|
|
constexpr int kMaxPorts = 32;
|
|
|
|
|
|
|
|
|
|
// task_swap_exception_ports() doesn’t actually use the initial value of
|
|
|
|
|
// handler_count, but 10.15.1
|
|
|
|
|
// xnu-6153.41.3/osfmk/man/task_get_exception_ports.html says it does. Humor
|
|
|
|
|
// the documentation.
|
|
|
|
|
mach_msg_type_number_t old_handler_count = kMaxPorts;
|
|
|
|
|
|
|
|
|
|
exception_mask_t old_masks[kMaxPorts];
|
|
|
|
|
exception_handler_t old_ports[kMaxPorts];
|
|
|
|
|
exception_behavior_t old_behaviors[kMaxPorts];
|
|
|
|
|
thread_state_flavor_t old_flavors[kMaxPorts];
|
|
|
|
|
|
|
|
|
|
kern_return_t kr = swap_exception_ports_(target_port_,
|
|
|
|
|
mask,
|
|
|
|
|
new_port,
|
|
|
|
|
new_behavior,
|
|
|
|
|
new_flavor,
|
|
|
|
|
old_masks,
|
|
|
|
|
&old_handler_count,
|
|
|
|
|
old_ports,
|
|
|
|
|
old_behaviors,
|
|
|
|
|
old_flavors);
|
|
|
|
|
if (kr != KERN_SUCCESS) {
|
|
|
|
|
MACH_LOG(ERROR, kr) << TargetTypeName() << "_swap_exception_ports";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
old_handlers->clear();
|
|
|
|
|
for (mach_msg_type_number_t index = 0; index < old_handler_count; ++index) {
|
|
|
|
|
if (old_ports[index] != MACH_PORT_NULL) {
|
|
|
|
|
ExceptionHandler old_handler;
|
|
|
|
|
old_handler.mask = old_masks[index];
|
|
|
|
|
old_handler.port = old_ports[index];
|
|
|
|
|
old_handler.behavior = old_behaviors[index];
|
|
|
|
|
old_handler.flavor = old_flavors[index];
|
|
|
|
|
old_handlers->push_back(old_handler);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* ExceptionPorts::TargetTypeName() const {
|
|
|
|
|
return target_name_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace crashpad
|