// 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 #include #include "base/basictypes.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 system’s 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()` doesn’t return the privileged //! `host_priv` port to non-root users, and this is the target port //! that’s 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 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. The caller must take //! ownership of the \a port members of the returned ExceptionHandler //! objects. 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, std::vector* 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 Returns a string identifying the target type. //! //! \return `"host"`, `"task"`, or `"thread"`, as appropriate. const char* TargetTypeName() const; private: typedef kern_return_t (*GetExceptionPortsType)(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); typedef kern_return_t (*SetExceptionPortsType)(mach_port_t, exception_mask_t, exception_handler_t, exception_behavior_t, thread_state_flavor_t); GetExceptionPortsType get_exception_ports_; SetExceptionPortsType set_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_