| Index: third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
|
| diff --git a/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..c5a74a3b16bdaf9d33852935be10303a23b94125
|
| --- /dev/null
|
| +++ b/third_party/crashpad/crashpad/util/mach/exc_server_variants.cc
|
| @@ -0,0 +1,801 @@
|
| +// 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/exc_server_variants.h"
|
| +
|
| +#include <AvailabilityMacros.h>
|
| +#include <string.h>
|
| +
|
| +#include <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "base/logging.h"
|
| +#include "util/mac/mac_util.h"
|
| +#include "util/mach/composite_mach_message_server.h"
|
| +#include "util/mach/exc.h"
|
| +#include "util/mach/exception_behaviors.h"
|
| +#include "util/mach/excServer.h"
|
| +#include "util/mach/mach_exc.h"
|
| +#include "util/mach/mach_excServer.h"
|
| +#include "util/mach/mach_message.h"
|
| +
|
| +extern "C" {
|
| +
|
| +// These six functions are not used, and are in fact obsoleted by the other
|
| +// functionality implemented in this file. The standard MIG-generated exc_server
|
| +// (in excServer.c) and mach_exc_server (in mach_excServer.c) server dispatch
|
| +// routines usable with the standard mach_msg_server() function call out to
|
| +// these functions. exc_server() and mach_exc_server() are unused and are
|
| +// replaced by the more flexible ExcServer and MachExcServer, but the linker
|
| +// still needs to see these six function definitions.
|
| +
|
| +kern_return_t catch_exception_raise(exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + exception_data_t code,
|
| + mach_msg_type_number_t code_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +kern_return_t catch_exception_raise_state(
|
| + exception_handler_t exception_port,
|
| + exception_type_t exception,
|
| + exception_data_t code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + thread_state_t old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +kern_return_t catch_exception_raise_state_identity(
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + exception_data_t code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + thread_state_t old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +kern_return_t catch_mach_exception_raise(exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + mach_exception_data_t code,
|
| + mach_msg_type_number_t code_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +kern_return_t catch_mach_exception_raise_state(
|
| + exception_handler_t exception_port,
|
| + exception_type_t exception,
|
| + mach_exception_data_t code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + thread_state_t old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +kern_return_t catch_mach_exception_raise_state_identity(
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + mach_exception_data_t code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + thread_state_t old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count) {
|
| + NOTREACHED();
|
| + return KERN_FAILURE;
|
| +}
|
| +
|
| +} // extern "C"
|
| +
|
| +namespace crashpad {
|
| +
|
| +namespace {
|
| +
|
| +// Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
|
| +// the exc subsystem.
|
| +struct ExcTraits {
|
| + using ExceptionCode = exception_data_type_t;
|
| +
|
| + using RequestUnion = __RequestUnion__exc_subsystem;
|
| + using ReplyUnion = __ReplyUnion__exc_subsystem;
|
| +
|
| + using ExceptionRaiseRequest = __Request__exception_raise_t;
|
| + using ExceptionRaiseStateRequest = __Request__exception_raise_state_t;
|
| + using ExceptionRaiseStateIdentityRequest =
|
| + __Request__exception_raise_state_identity_t;
|
| +
|
| + using ExceptionRaiseReply = __Reply__exception_raise_t;
|
| + using ExceptionRaiseStateReply = __Reply__exception_raise_state_t;
|
| + using ExceptionRaiseStateIdentityReply =
|
| + __Reply__exception_raise_state_identity_t;
|
| +
|
| + // The MIG-generated __MIG_check__Request__*() functions are not declared as
|
| + // accepting const data, but they could have been because they in fact do not
|
| + // modify the data.
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaise(
|
| + const ExceptionRaiseRequest* in_request) {
|
| + return __MIG_check__Request__exception_raise_t(
|
| + const_cast<ExceptionRaiseRequest*>(in_request));
|
| + }
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaiseState(
|
| + const ExceptionRaiseStateRequest* in_request,
|
| + const ExceptionRaiseStateRequest** in_request_1) {
|
| + return __MIG_check__Request__exception_raise_state_t(
|
| + const_cast<ExceptionRaiseStateRequest*>(in_request),
|
| + const_cast<ExceptionRaiseStateRequest**>(in_request_1));
|
| + }
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
|
| + const ExceptionRaiseStateIdentityRequest* in_request,
|
| + const ExceptionRaiseStateIdentityRequest** in_request_1) {
|
| + return __MIG_check__Request__exception_raise_state_identity_t(
|
| + const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
|
| + const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
|
| + }
|
| +
|
| + // There are no predefined constants for these.
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaise = 2401;
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2402;
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2403;
|
| +
|
| + static const exception_behavior_t kExceptionBehavior = 0;
|
| +};
|
| +
|
| +// Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
|
| +// the mach_exc subsystem.
|
| +struct MachExcTraits {
|
| + using ExceptionCode = mach_exception_data_type_t;
|
| +
|
| + using RequestUnion = __RequestUnion__mach_exc_subsystem;
|
| + using ReplyUnion = __ReplyUnion__mach_exc_subsystem;
|
| +
|
| + using ExceptionRaiseRequest = __Request__mach_exception_raise_t;
|
| + using ExceptionRaiseStateRequest = __Request__mach_exception_raise_state_t;
|
| + using ExceptionRaiseStateIdentityRequest =
|
| + __Request__mach_exception_raise_state_identity_t;
|
| +
|
| + using ExceptionRaiseReply = __Reply__mach_exception_raise_t;
|
| + using ExceptionRaiseStateReply = __Reply__mach_exception_raise_state_t;
|
| + using ExceptionRaiseStateIdentityReply =
|
| + __Reply__mach_exception_raise_state_identity_t;
|
| +
|
| + // The MIG-generated __MIG_check__Request__*() functions are not declared as
|
| + // accepting const data, but they could have been because they in fact do not
|
| + // modify the data.
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaise(
|
| + const ExceptionRaiseRequest* in_request) {
|
| + return __MIG_check__Request__mach_exception_raise_t(
|
| + const_cast<ExceptionRaiseRequest*>(in_request));
|
| + }
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaiseState(
|
| + const ExceptionRaiseStateRequest* in_request,
|
| + const ExceptionRaiseStateRequest** in_request_1) {
|
| + return __MIG_check__Request__mach_exception_raise_state_t(
|
| + const_cast<ExceptionRaiseStateRequest*>(in_request),
|
| + const_cast<ExceptionRaiseStateRequest**>(in_request_1));
|
| + }
|
| +
|
| + static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
|
| + const ExceptionRaiseStateIdentityRequest* in_request,
|
| + const ExceptionRaiseStateIdentityRequest** in_request_1) {
|
| + return __MIG_check__Request__mach_exception_raise_state_identity_t(
|
| + const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
|
| + const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
|
| + }
|
| +
|
| + // There are no predefined constants for these.
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaise = 2405;
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2406;
|
| + static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2407;
|
| +
|
| + static const exception_behavior_t kExceptionBehavior = MACH_EXCEPTION_CODES;
|
| +};
|
| +
|
| +//! \brief A server interface for the `exc` or `mach_exc` Mach subsystems.
|
| +template <typename Traits>
|
| +class ExcServer : public MachMessageServer::Interface {
|
| + public:
|
| + //! \brief An interface that the different request messages that are a part of
|
| + //! the `exc` or `mach_exc` Mach subsystems can be dispatched to.
|
| + class Interface {
|
| + public:
|
| + //! \brief Handles exceptions raised by `exception_raise()` or
|
| + //! `mach_exception_raise()`.
|
| + //!
|
| + //! This behaves equivalently to a `catch_exception_raise()` function used
|
| + //! with `exc_server()`, or a `catch_mach_exception_raise()` function used
|
| + //! with `mach_exc_server()`.
|
| + //!
|
| + //! \param[in] trailer The trailer received with the request message.
|
| + //! \param[out] destroy_request `true` if the request message is to be
|
| + //! destroyed even when this method returns success. See
|
| + //! MachMessageServer::Interface.
|
| + virtual kern_return_t CatchExceptionRaise(
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_request) = 0;
|
| +
|
| + //! \brief Handles exceptions raised by `exception_raise_state()` or
|
| + //! `mach_exception_raise_state()`.
|
| + //!
|
| + //! This behaves equivalently to a `catch_exception_raise_state()` function
|
| + //! used with `exc_server()`, or a `catch_mach_exception_raise_state()`
|
| + //! function used with `mach_exc_server()`.
|
| + //!
|
| + //! There is no \a destroy_request parameter because, unlike
|
| + //! CatchExceptionRaise() and CatchExceptionRaiseStateIdentity(), the
|
| + //! request message is not complex (it does not carry the \a thread or \a
|
| + //! task port rights) and thus there is nothing to destroy.
|
| + //!
|
| + //! \param[in] trailer The trailer received with the request message.
|
| + virtual kern_return_t CatchExceptionRaiseState(
|
| + exception_handler_t exception_port,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer) = 0;
|
| +
|
| + //! \brief Handles exceptions raised by `exception_raise_state_identity()`
|
| + //! or `mach_exception_raise_state_identity()`.
|
| + //!
|
| + //! This behaves equivalently to a `catch_exception_raise_state_identity()`
|
| + //! function used with `exc_server()`, or a
|
| + //! `catch_mach_exception_raise_state_identity()` function used with
|
| + //! `mach_exc_server()`.
|
| + //!
|
| + //! \param[in] trailer The trailer received with the request message.
|
| + //! \param[out] destroy_request `true` if the request message is to be
|
| + //! destroyed even when this method returns success. See
|
| + //! MachMessageServer::Interface.
|
| + virtual kern_return_t CatchExceptionRaiseStateIdentity(
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_request) = 0;
|
| +
|
| + protected:
|
| + ~Interface() {}
|
| + };
|
| +
|
| + //! \brief Constructs an object of this class.
|
| + //!
|
| + //! \param[in] interface The interface to dispatch requests to. Weak.
|
| + explicit ExcServer(Interface* interface)
|
| + : MachMessageServer::Interface(), interface_(interface) {}
|
| +
|
| + // MachMessageServer::Interface:
|
| +
|
| + bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
| + mach_msg_header_t* out_header,
|
| + bool* destroy_complex_request) override;
|
| +
|
| + std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
|
| + const mach_msg_id_t request_ids[] = {
|
| + Traits::kMachMessageIDExceptionRaise,
|
| + Traits::kMachMessageIDExceptionRaiseState,
|
| + Traits::kMachMessageIDExceptionRaiseStateIdentity,
|
| + };
|
| + return std::set<mach_msg_id_t>(&request_ids[0],
|
| + &request_ids[arraysize(request_ids)]);
|
| + }
|
| +
|
| + mach_msg_size_t MachMessageServerRequestSize() override {
|
| + return sizeof(typename Traits::RequestUnion);
|
| + }
|
| +
|
| + mach_msg_size_t MachMessageServerReplySize() override {
|
| + return sizeof(typename Traits::ReplyUnion);
|
| + }
|
| +
|
| + private:
|
| + Interface* interface_; // weak
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ExcServer);
|
| +};
|
| +
|
| +template <typename Traits>
|
| +bool ExcServer<Traits>::MachMessageServerFunction(
|
| + const mach_msg_header_t* in_header,
|
| + mach_msg_header_t* out_header,
|
| + bool* destroy_complex_request) {
|
| + PrepareMIGReplyFromRequest(in_header, out_header);
|
| +
|
| + const mach_msg_trailer_t* in_trailer =
|
| + MachMessageTrailerFromHeader(in_header);
|
| +
|
| + switch (in_header->msgh_id) {
|
| + case Traits::kMachMessageIDExceptionRaise: {
|
| + // exception_raise(), catch_exception_raise(), mach_exception_raise(),
|
| + // catch_mach_exception_raise().
|
| + using Request = typename Traits::ExceptionRaiseRequest;
|
| + const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
| + kern_return_t kr = Traits::MIGCheckRequestExceptionRaise(in_request);
|
| + if (kr != MACH_MSG_SUCCESS) {
|
| + SetMIGReplyError(out_header, kr);
|
| + return true;
|
| + }
|
| +
|
| + using Reply = typename Traits::ExceptionRaiseReply;
|
| + Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
| + out_reply->RetCode =
|
| + interface_->CatchExceptionRaise(in_header->msgh_local_port,
|
| + in_request->thread.name,
|
| + in_request->task.name,
|
| + in_request->exception,
|
| + in_request->code,
|
| + in_request->codeCnt,
|
| + in_trailer,
|
| + destroy_complex_request);
|
| + if (out_reply->RetCode != KERN_SUCCESS) {
|
| + return true;
|
| + }
|
| +
|
| + out_header->msgh_size = sizeof(*out_reply);
|
| + return true;
|
| + }
|
| +
|
| + case Traits::kMachMessageIDExceptionRaiseState: {
|
| + // exception_raise_state(), catch_exception_raise_state(),
|
| + // mach_exception_raise_state(), catch_mach_exception_raise_state().
|
| + using Request = typename Traits::ExceptionRaiseStateRequest;
|
| + const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
| +
|
| + // in_request_1 is used for the portion of the request after the codes,
|
| + // which in theory can be variable-length. The check function will set it.
|
| + const Request* in_request_1;
|
| + kern_return_t kr =
|
| + Traits::MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
|
| + if (kr != MACH_MSG_SUCCESS) {
|
| + SetMIGReplyError(out_header, kr);
|
| + return true;
|
| + }
|
| +
|
| + using Reply = typename Traits::ExceptionRaiseStateReply;
|
| + Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
| + out_reply->flavor = in_request_1->flavor;
|
| + out_reply->new_stateCnt = arraysize(out_reply->new_state);
|
| + out_reply->RetCode =
|
| + interface_->CatchExceptionRaiseState(in_header->msgh_local_port,
|
| + in_request->exception,
|
| + in_request->code,
|
| + in_request->codeCnt,
|
| + &out_reply->flavor,
|
| + in_request_1->old_state,
|
| + in_request_1->old_stateCnt,
|
| + out_reply->new_state,
|
| + &out_reply->new_stateCnt,
|
| + in_trailer);
|
| + if (out_reply->RetCode != KERN_SUCCESS) {
|
| + return true;
|
| + }
|
| +
|
| + out_header->msgh_size =
|
| + sizeof(*out_reply) - sizeof(out_reply->new_state) +
|
| + sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
|
| + return true;
|
| + }
|
| +
|
| + case Traits::kMachMessageIDExceptionRaiseStateIdentity: {
|
| + // exception_raise_state_identity(),
|
| + // catch_exception_raise_state_identity(),
|
| + // mach_exception_raise_state_identity(),
|
| + // catch_mach_exception_raise_state_identity().
|
| + using Request = typename Traits::ExceptionRaiseStateIdentityRequest;
|
| + const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
| +
|
| + // in_request_1 is used for the portion of the request after the codes,
|
| + // which in theory can be variable-length. The check function will set it.
|
| + const Request* in_request_1;
|
| + kern_return_t kr = Traits::MIGCheckRequestExceptionRaiseStateIdentity(
|
| + in_request, &in_request_1);
|
| + if (kr != MACH_MSG_SUCCESS) {
|
| + SetMIGReplyError(out_header, kr);
|
| + return true;
|
| + }
|
| +
|
| + using Reply = typename Traits::ExceptionRaiseStateIdentityReply;
|
| + Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
| + out_reply->flavor = in_request_1->flavor;
|
| + out_reply->new_stateCnt = arraysize(out_reply->new_state);
|
| + out_reply->RetCode = interface_->CatchExceptionRaiseStateIdentity(
|
| + in_header->msgh_local_port,
|
| + in_request->thread.name,
|
| + in_request->task.name,
|
| + in_request->exception,
|
| + in_request->code,
|
| + in_request->codeCnt,
|
| + &out_reply->flavor,
|
| + in_request_1->old_state,
|
| + in_request_1->old_stateCnt,
|
| + out_reply->new_state,
|
| + &out_reply->new_stateCnt,
|
| + in_trailer,
|
| + destroy_complex_request);
|
| + if (out_reply->RetCode != KERN_SUCCESS) {
|
| + return true;
|
| + }
|
| +
|
| + out_header->msgh_size =
|
| + sizeof(*out_reply) - sizeof(out_reply->new_state) +
|
| + sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
|
| + return true;
|
| + }
|
| +
|
| + default: {
|
| + SetMIGReplyError(out_header, MIG_BAD_ID);
|
| + return false;
|
| + }
|
| + }
|
| +}
|
| +
|
| +//! \brief A server interface for the `exc` or `mach_exc` Mach subsystems,
|
| +//! simplified to have only a single interface method needing
|
| +//! implementation.
|
| +template <typename Traits>
|
| +class SimplifiedExcServer final : public ExcServer<Traits>,
|
| + public ExcServer<Traits>::Interface {
|
| + public:
|
| + //! \brief An interface that the different request messages that are a part of
|
| + //! the `exc` or `mach_exc` Mach subsystems can be dispatched to.
|
| + class Interface {
|
| + public:
|
| + //! \brief Handles exceptions raised by `exception_raise()`,
|
| + //! `exception_raise_state()`, and `exception_raise_state_identity()`;
|
| + //! or `mach_exception_raise()`, `mach_exception_raise_state()`, and
|
| + //! `mach_exception_raise_state_identity()`.
|
| + //!
|
| + //! For convenience in implementation, these different “behaviors” of
|
| + //! exception messages are all mapped to a single interface method. The
|
| + //! exception’s original “behavior” is specified in the \a behavior
|
| + //! parameter. Only parameters that were supplied in the request message
|
| + //! are populated, other parameters are set to reasonable default values.
|
| + //!
|
| + //! The meanings of most parameters are identical to that of
|
| + //! ExcServer<>::Interface::CatchExceptionRaiseStateIdentity().
|
| + //!
|
| + //! \param[in] behavior `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
|
| + //! `EXCEPTION_STATE_IDENTITY`, identifying which exception request
|
| + //! message was processed and thus which other parameters are valid.
|
| + //! When used with the `mach_exc` subsystem, `MACH_EXCEPTION_CODES` will
|
| + //! be ORed in to this parameter.
|
| + virtual kern_return_t CatchException(
|
| + exception_behavior_t behavior,
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_complex_request) = 0;
|
| +
|
| + protected:
|
| + ~Interface() {}
|
| + };
|
| +
|
| + //! \brief Constructs an object of this class.
|
| + //!
|
| + //! \param[in] interface The interface to dispatch requests to. Weak.
|
| + explicit SimplifiedExcServer(Interface* interface)
|
| + : ExcServer<Traits>(this),
|
| + ExcServer<Traits>::Interface(),
|
| + interface_(interface) {}
|
| +
|
| + // ExcServer::Interface:
|
| +
|
| + kern_return_t CatchExceptionRaise(exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_request) override {
|
| + thread_state_flavor_t flavor = THREAD_STATE_NONE;
|
| + mach_msg_type_number_t new_state_count = 0;
|
| + return interface_->CatchException(
|
| + Traits::kExceptionBehavior | EXCEPTION_DEFAULT,
|
| + exception_port,
|
| + thread,
|
| + task,
|
| + exception,
|
| + code_count ? code : nullptr,
|
| + code_count,
|
| + &flavor,
|
| + nullptr,
|
| + 0,
|
| + nullptr,
|
| + &new_state_count,
|
| + trailer,
|
| + destroy_request);
|
| + }
|
| +
|
| + kern_return_t CatchExceptionRaiseState(
|
| + exception_handler_t exception_port,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer) override {
|
| + bool destroy_complex_request = false;
|
| + return interface_->CatchException(
|
| + Traits::kExceptionBehavior | EXCEPTION_STATE,
|
| + exception_port,
|
| + THREAD_NULL,
|
| + TASK_NULL,
|
| + exception,
|
| + code_count ? code : nullptr,
|
| + code_count,
|
| + flavor,
|
| + old_state_count ? old_state : nullptr,
|
| + old_state_count,
|
| + new_state_count ? new_state : nullptr,
|
| + new_state_count,
|
| + trailer,
|
| + &destroy_complex_request);
|
| + }
|
| +
|
| + kern_return_t CatchExceptionRaiseStateIdentity(
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const typename Traits::ExceptionCode* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_request) override {
|
| + return interface_->CatchException(
|
| + Traits::kExceptionBehavior | EXCEPTION_STATE_IDENTITY,
|
| + exception_port,
|
| + thread,
|
| + task,
|
| + exception,
|
| + code_count ? code : nullptr,
|
| + code_count,
|
| + flavor,
|
| + old_state_count ? old_state : nullptr,
|
| + old_state_count,
|
| + new_state_count ? new_state : nullptr,
|
| + new_state_count,
|
| + trailer,
|
| + destroy_request);
|
| + }
|
| +
|
| + private:
|
| + Interface* interface_; // weak
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SimplifiedExcServer);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +namespace internal {
|
| +
|
| +class UniversalMachExcServerImpl final
|
| + : public CompositeMachMessageServer,
|
| + public SimplifiedExcServer<ExcTraits>::Interface,
|
| + public SimplifiedExcServer<MachExcTraits>::Interface {
|
| + public:
|
| + explicit UniversalMachExcServerImpl(
|
| + UniversalMachExcServer::Interface* interface)
|
| + : CompositeMachMessageServer(),
|
| + SimplifiedExcServer<ExcTraits>::Interface(),
|
| + SimplifiedExcServer<MachExcTraits>::Interface(),
|
| + exc_server_(this),
|
| + mach_exc_server_(this),
|
| + interface_(interface) {
|
| + AddHandler(&exc_server_);
|
| + AddHandler(&mach_exc_server_);
|
| + }
|
| +
|
| + ~UniversalMachExcServerImpl() {}
|
| +
|
| + // SimplifiedExcServer<ExcTraits>::Interface:
|
| + kern_return_t CatchException(exception_behavior_t behavior,
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const exception_data_type_t* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_complex_request) {
|
| + std::vector<mach_exception_data_type_t> mach_codes;
|
| + mach_codes.reserve(code_count);
|
| + for (size_t index = 0; index < code_count; ++index) {
|
| + mach_codes.push_back(code[index]);
|
| + }
|
| +
|
| + return interface_->CatchMachException(behavior,
|
| + exception_port,
|
| + thread,
|
| + task,
|
| + exception,
|
| + code_count ? &mach_codes[0] : nullptr,
|
| + code_count,
|
| + flavor,
|
| + old_state_count ? old_state : nullptr,
|
| + old_state_count,
|
| + new_state_count ? new_state : nullptr,
|
| + new_state_count,
|
| + trailer,
|
| + destroy_complex_request);
|
| + }
|
| +
|
| + // SimplifiedExcServer<MachExcTraits>::Interface:
|
| + kern_return_t CatchException(exception_behavior_t behavior,
|
| + exception_handler_t exception_port,
|
| + thread_t thread,
|
| + task_t task,
|
| + exception_type_t exception,
|
| + const mach_exception_data_type_t* code,
|
| + mach_msg_type_number_t code_count,
|
| + thread_state_flavor_t* flavor,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count,
|
| + const mach_msg_trailer_t* trailer,
|
| + bool* destroy_complex_request) {
|
| + return interface_->CatchMachException(behavior,
|
| + exception_port,
|
| + thread,
|
| + task,
|
| + exception,
|
| + code_count ? code : nullptr,
|
| + code_count,
|
| + flavor,
|
| + old_state_count ? old_state : nullptr,
|
| + old_state_count,
|
| + new_state_count ? new_state : nullptr,
|
| + new_state_count,
|
| + trailer,
|
| + destroy_complex_request);
|
| + }
|
| +
|
| + private:
|
| + SimplifiedExcServer<ExcTraits> exc_server_;
|
| + SimplifiedExcServer<MachExcTraits> mach_exc_server_;
|
| + UniversalMachExcServer::Interface* interface_; // weak
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(UniversalMachExcServerImpl);
|
| +};
|
| +
|
| +} // namespace internal
|
| +
|
| +UniversalMachExcServer::UniversalMachExcServer(
|
| + UniversalMachExcServer::Interface* interface)
|
| + : MachMessageServer::Interface(),
|
| + impl_(new internal::UniversalMachExcServerImpl(interface)) {
|
| +}
|
| +
|
| +UniversalMachExcServer::~UniversalMachExcServer() {
|
| +}
|
| +
|
| +bool UniversalMachExcServer::MachMessageServerFunction(
|
| + const mach_msg_header_t* in_header,
|
| + mach_msg_header_t* out_header,
|
| + bool* destroy_complex_request) {
|
| + return impl_->MachMessageServerFunction(
|
| + in_header, out_header, destroy_complex_request);
|
| +}
|
| +
|
| +std::set<mach_msg_id_t> UniversalMachExcServer::MachMessageServerRequestIDs() {
|
| + return impl_->MachMessageServerRequestIDs();
|
| +}
|
| +
|
| +mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
|
| + return impl_->MachMessageServerRequestSize();
|
| +}
|
| +
|
| +mach_msg_size_t UniversalMachExcServer::MachMessageServerReplySize() {
|
| + return impl_->MachMessageServerReplySize();
|
| +}
|
| +
|
| +kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception,
|
| + exception_behavior_t behavior,
|
| + bool set_thread_state) {
|
| + if (exception == EXC_CRASH
|
| +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
|
| + && MacOSXMinorVersion() >= 11
|
| +#endif
|
| + ) {
|
| + return KERN_SUCCESS;
|
| + }
|
| +
|
| + if (!set_thread_state && ExceptionBehaviorHasState(behavior)) {
|
| + return MACH_RCV_PORT_DIED;
|
| + }
|
| +
|
| + return KERN_SUCCESS;
|
| +}
|
| +
|
| +void ExcServerCopyState(exception_behavior_t behavior,
|
| + ConstThreadState old_state,
|
| + mach_msg_type_number_t old_state_count,
|
| + thread_state_t new_state,
|
| + mach_msg_type_number_t* new_state_count) {
|
| + if (ExceptionBehaviorHasState(behavior)) {
|
| + *new_state_count = std::min(old_state_count, *new_state_count);
|
| + memcpy(new_state, old_state, *new_state_count * sizeof(old_state[0]));
|
| + }
|
| +}
|
| +
|
| +} // namespace crashpad
|
|
|