| // 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 "base/stl_util.h" |
| #include "util/mac/mac_util.h" |
| #include "util/mach/composite_mach_message_server.h" |
| #include "util/mach/exc.h" |
| #include "util/mach/excServer.h" |
| #include "util/mach/exception_behaviors.h" |
| #include "util/mach/mach_exc.h" |
| #include "util/mach/mach_excServer.h" |
| #include "util/mach/mach_message.h" |
| |
| 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 { |
| constexpr mach_msg_id_t request_ids[] = { |
| Traits::kMachMessageIDExceptionRaise, |
| Traits::kMachMessageIDExceptionRaiseState, |
| Traits::kMachMessageIDExceptionRaiseStateIdentity, |
| }; |
| return std::set<mach_msg_id_t>(&request_ids[0], |
| &request_ids[base::size(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 = base::size(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 = base::size(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 |