crashpad/util/mach/exception_ports.h
Mark Mentovai 174a92d296 mac, ios: Add ExceptionPorts::SwapExceptionPorts
Change-Id: Ia4044c82440af1d05c24ee502d51eef5185cbeec
Test: crashpad_util_test ExceptionPorts.*_Swap*
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2170546
Reviewed-by: Justin Cohen <justincohen@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
2020-04-28 16:43:41 +00:00

263 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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.
#ifndef CRASHPAD_UTIL_MACH_EXCEPTION_PORTS_H_
#define CRASHPAD_UTIL_MACH_EXCEPTION_PORTS_H_
#include <mach/mach.h>
#include <vector>
#include "base/macros.h"
namespace crashpad {
//! \brief A better interface to `*_get_exception_ports()` and
//! `*_set_exception_ports()`.
//!
//! The same generic interface can be used to operate on host, task, and thread
//! exception ports. The “get” interface is superior to the systems native
//! interface because it keeps related data about a single exception handler
//! together in one struct, rather than separating it into four parallel arrays.
class ExceptionPorts {
public:
//! \brief Various entities which can have their own exception ports set.
enum TargetType {
//! \brief The host exception target.
//!
//! `host_get_exception_ports()` and `host_set_exception_ports()` will be
//! used. If no target port is explicitly provided, `mach_host_self()` will
//! be used as the target port. `mach_host_self()` is the only target port
//! for this type that is expected to function properly.
//!
//! \note Operations on this target type are not expected to succeed as
//! non-root, because `mach_host_self()` doesnt return the privileged
//! `host_priv` port to non-root users, and this is the target port
//! thats required for `host_get_exception_ports()` and
//! `host_set_exception_ports()`.
kTargetTypeHost = 0,
//! \brief A task exception target.
//!
//! `task_get_exception_ports()` and `task_set_exception_ports()` will be
//! used. If no target port is explicitly provided, `mach_task_self()` will
//! be used as the target port.
kTargetTypeTask,
//! \brief A thread exception target.
//!
//! `thread_get_exception_ports()` and `thread_set_exception_ports()` will
//! be used. If no target port is explicitly provided, `mach_thread_self()`
//! will be used as the target port.
kTargetTypeThread,
};
//! \brief Information about a registered exception handler.
struct ExceptionHandler {
//! \brief A mask specifying the exception types to direct to \a port,
//! containing `EXC_MASK_*` values.
exception_mask_t mask;
//! \brief A send right to a Mach port that will handle exceptions of the
//! types indicated in \a mask.
exception_handler_t port;
//! \brief The “behavior” that the exception handler at \a port implements:
//! `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
//! `EXCEPTION_STATE_IDENTITY`, possibly combined with
//! `MACH_EXCEPTION_CODES`.
exception_behavior_t behavior;
//! \brief The thread state flavor that the exception handler at \a port
//! will receive and possibly modify. This member has no effect for \a
//! \a behavior values that indicate a “default” behavior.
thread_state_flavor_t flavor;
};
//! \brief Wraps `std::vector<ExceptionHandler>`, providing proper cleanup of
//! the send rights contained in each elements ExceptionHandler::port.
//!
//! Upon destruction or clear(), an object of this class will deallocate all
//! send rights it contains. Otherwise, it is an interface-compatible drop-in
//! replacement for `std::vector<ExceptionHandler>`. Note that non-`const`
//! mutators are not provided to avoid accidental Mach right leaks.
class ExceptionHandlerVector {
public:
using VectorType = std::vector<ExceptionHandler>;
ExceptionHandlerVector();
~ExceptionHandlerVector();
VectorType::const_iterator begin() const { return vector_.begin(); }
VectorType::const_iterator end() const { return vector_.end(); }
VectorType::size_type size() const { return vector_.size(); }
bool empty() const { return vector_.empty(); }
VectorType::const_reference operator[](VectorType::size_type index) const {
return vector_[index];
}
void push_back(VectorType::value_type& value) { vector_.push_back(value); }
void clear();
private:
void Deallocate();
VectorType vector_;
DISALLOW_COPY_AND_ASSIGN(ExceptionHandlerVector);
};
//! \brief Constructs an interface object to get or set exception ports on a
//! host, task, or thread port.
//!
//! \param[in] target_type The type of target on which the exception ports are
//! to be get or set: #kTargetTypeHost, #kTargetTypeTask, or or
//! #kTargetTypeThread. The correct functions for
//! `*_get_exception_ports()` and `*_set_exception_ports()` will be used.
//! \param[in] target_port The target on which to call
//! `*_get_exception_ports()` or `*_set_exception_ports()`. The target
//! port must be a send right to a port of the type specified in \a
//! target_type. In this case, ownership of \a target_port is not given to
//! the new ExceptionPorts object. \a target_port may also be
//! `HOST_NULL`, `TASK_NULL`, or `THREAD_NULL`, in which case
//! `mach_host_self()`, `mach_task_self()`, or `mach_thread_self()` will
//! be used as the target port depending on the value of \a target_type.
//! In this case, ownership of the target port will be managed
//! appropriately for \a target_type.
ExceptionPorts(TargetType target_type, mach_port_t target_port);
~ExceptionPorts();
//! \brief Calls `*_get_exception_ports()` on the target.
//!
//! \param[in] mask The exception mask, containing the `EXC_MASK_*` values to
//! be looked up and returned in \a handlers.
//! \param[out] handlers The exception handlers registered for \a target_port
//! to handle exceptions indicated in \a mask. If no execption port is
//! registered for a bit in \a mask, \a handlers will not contain an entry
//! corresponding to that bit. This is a departure from the
//! `*_get_exception_ports()` functions, which may return a handler whose
//! port is set to `EXCEPTION_PORT_NULL` in this case. On failure, this
//! argument is untouched.
//!
//! \return `true` if `*_get_exception_ports()` returned `KERN_SUCCESS`, with
//! \a handlers set appropriately. `false` otherwise, with an appropriate
//! message logged.
bool GetExceptionPorts(exception_mask_t mask,
ExceptionHandlerVector* handlers) const;
//! \brief Calls `*_set_exception_ports()` on the target.
//!
//! \param[in] mask A mask specifying the exception types to direct to \a
//! port, containing `EXC_MASK_*` values.
//! \param[in] port A send right to a Mach port that will handle exceptions
//! sustained by \a target_port of the types indicated in \a mask. The
//! send right is copied, not consumed, by this call.
//! \param[in] behavior The “behavior” that the exception handler at \a port
//! implements: `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
//! `EXCEPTION_STATE_IDENTITY`, possibly combined with
//! `MACH_EXCEPTION_CODES`.
//! \param[in] flavor The thread state flavor that the exception handler at \a
//! port expects to receive and possibly modify. This argument has no
//! effect for \a behavior values that indicate a “default” behavior.
//!
//! \return `true` if `*_set_exception_ports()` returned `KERN_SUCCESS`.
//! `false` otherwise, with an appropriate message logged.
bool SetExceptionPort(exception_mask_t mask,
exception_handler_t port,
exception_behavior_t behavior,
thread_state_flavor_t flavor) const;
//! \brief Calls `*_swap_exception_ports()` on the target.
//!
//! \param[in] mask A mask specifying the exception types to direct to \a
//! port, containing `EXC_MASK_*` values.
//! \param[in] new_port A send right to a Mach port that will handle
//! exceptions sustained by \a target_port of the types indicated in \a
//! mask. The send right is copied, not consumed, by this call.
//! \param[in] new_behavior The “behavior” that the exception handler at \a
//! port implements: `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
//! `EXCEPTION_STATE_IDENTITY`, possibly combined with
//! `MACH_EXCEPTION_CODES`.
//! \param[in] new_flavor The thread state flavor that the exception handler
//! at \a port expects to receive and possibly modify. This argument has
//! no effect for \a new_behavior values that indicate a “default”
//! behavior.
//! \param[out] old_handlers The exception handlers registered for \a
//! target_port to handle exceptions indicated in \a mask. If no execption
//! port is registered for a bit in \a mask, \a old_handlers will not
//! contain an entry corresponding to that bit. This is a departure from
//! the `*_get_exception_ports()` functions, which may return a handler
//! whose port is set to `EXCEPTION_PORT_NULL` in this case. On failure,
//! this argument is untouched.
//!
//! \return `true` if `*_swap_exception_ports()` returned `KERN_SUCCESS`, with
//! \a old_handlers set appropriately. . `false` otherwise, with an
//! appropriate message logged.
bool 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;
//! \brief Returns a string identifying the target type.
//!
//! \return `"host"`, `"task"`, or `"thread"`, as appropriate.
const char* TargetTypeName() const;
private:
using GetExceptionPortsType = kern_return_t(*)(mach_port_t,
exception_mask_t,
exception_mask_array_t,
mach_msg_type_number_t*,
exception_handler_array_t,
exception_behavior_array_t,
exception_flavor_array_t);
using SetExceptionPortsType = kern_return_t(*)(mach_port_t,
exception_mask_t,
exception_handler_t,
exception_behavior_t,
thread_state_flavor_t);
using SwapExceptionPortsType = kern_return_t(*)(mach_port_t,
exception_mask_t,
exception_handler_t,
exception_behavior_t,
thread_state_flavor_t,
exception_mask_array_t,
mach_msg_type_number_t*,
exception_handler_array_t,
exception_behavior_array_t,
exception_flavor_array_t);
GetExceptionPortsType get_exception_ports_;
SetExceptionPortsType set_exception_ports_;
SwapExceptionPortsType swap_exception_ports_;
const char* target_name_;
mach_port_t target_port_;
// If true, target_port_ will be deallocated in the destructor. This will
// always be false when the user provides a non-null target_port to the
// constructor. It will also be false when target_type is kTargetTypeTask,
// even with a TASK_NULL target_port, because it is incorrect to deallocate
// the result of mach_task_self().
bool dealloc_target_port_;
DISALLOW_COPY_AND_ASSIGN(ExceptionPorts);
};
} // namespace crashpad
#endif // CRASHPAD_UTIL_MACH_EXCEPTION_PORTS_H_