2014-09-10 17:29:07 -04:00
|
|
|
|
// 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"
|
|
|
|
|
|
2015-09-04 14:29:12 -04:00
|
|
|
|
#include <AvailabilityMacros.h>
|
2015-04-01 12:16:22 -04:00
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2014-09-10 17:29:07 -04:00
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "base/logging.h"
|
2019-01-04 16:57:57 -05:00
|
|
|
|
#include "base/stl_util.h"
|
2015-09-04 14:29:12 -04:00
|
|
|
|
#include "util/mac/mac_util.h"
|
2014-12-11 14:29:42 -05:00
|
|
|
|
#include "util/mach/composite_mach_message_server.h"
|
2014-09-10 17:29:07 -04:00
|
|
|
|
#include "util/mach/exc.h"
|
|
|
|
|
#include "util/mach/excServer.h"
|
2016-01-06 12:22:50 -05:00
|
|
|
|
#include "util/mach/exception_behaviors.h"
|
2014-09-10 17:29:07 -04:00
|
|
|
|
#include "util/mach/mach_exc.h"
|
|
|
|
|
#include "util/mach/mach_excServer.h"
|
2014-12-02 17:02:32 -05:00
|
|
|
|
#include "util/mach/mach_message.h"
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
namespace crashpad {
|
|
|
|
|
|
2014-09-10 17:29:07 -04:00
|
|
|
|
namespace {
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// 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;
|
2014-09-10 17:29:07 -04:00
|
|
|
|
};
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
|
|
|
|
|
// the mach_exc subsystem.
|
|
|
|
|
struct MachExcTraits {
|
|
|
|
|
using ExceptionCode = mach_exception_data_type_t;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using RequestUnion = __RequestUnion__mach_exc_subsystem;
|
|
|
|
|
using ReplyUnion = __ReplyUnion__mach_exc_subsystem;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using ExceptionRaiseRequest = __Request__mach_exception_raise_t;
|
|
|
|
|
using ExceptionRaiseStateRequest = __Request__mach_exception_raise_state_t;
|
|
|
|
|
using ExceptionRaiseStateIdentityRequest =
|
|
|
|
|
__Request__mach_exception_raise_state_identity_t;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using ExceptionRaiseReply = __Reply__mach_exception_raise_t;
|
|
|
|
|
using ExceptionRaiseStateReply = __Reply__mach_exception_raise_state_t;
|
|
|
|
|
using ExceptionRaiseStateIdentityReply =
|
|
|
|
|
__Reply__mach_exception_raise_state_identity_t;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// 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.
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
static kern_return_t MIGCheckRequestExceptionRaise(
|
|
|
|
|
const ExceptionRaiseRequest* in_request) {
|
|
|
|
|
return __MIG_check__Request__mach_exception_raise_t(
|
|
|
|
|
const_cast<ExceptionRaiseRequest*>(in_request));
|
|
|
|
|
}
|
2014-09-10 18:57:14 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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));
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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));
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// 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;
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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 {
|
2017-07-25 19:15:48 -04:00
|
|
|
|
constexpr mach_msg_id_t request_ids[] = {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
Traits::kMachMessageIDExceptionRaise,
|
|
|
|
|
Traits::kMachMessageIDExceptionRaiseState,
|
|
|
|
|
Traits::kMachMessageIDExceptionRaiseStateIdentity,
|
|
|
|
|
};
|
|
|
|
|
return std::set<mach_msg_id_t>(&request_ids[0],
|
2019-01-04 16:57:57 -05:00
|
|
|
|
&request_ids[base::size(request_ids)]);
|
2014-12-11 14:29:42 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
2014-11-25 14:29:46 -05:00
|
|
|
|
PrepareMIGReplyFromRequest(in_header, out_header);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-01 16:06:56 -05:00
|
|
|
|
const mach_msg_trailer_t* in_trailer =
|
|
|
|
|
MachMessageTrailerFromHeader(in_header);
|
|
|
|
|
|
2014-09-10 17:29:07 -04:00
|
|
|
|
switch (in_header->msgh_id) {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
case Traits::kMachMessageIDExceptionRaise: {
|
|
|
|
|
// exception_raise(), catch_exception_raise(), mach_exception_raise(),
|
|
|
|
|
// catch_mach_exception_raise().
|
|
|
|
|
using Request = typename Traits::ExceptionRaiseRequest;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
2014-12-11 14:29:42 -05:00
|
|
|
|
kern_return_t kr = Traits::MIGCheckRequestExceptionRaise(in_request);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
if (kr != MACH_MSG_SUCCESS) {
|
2014-11-25 14:29:46 -05:00
|
|
|
|
SetMIGReplyError(out_header, kr);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using Reply = typename Traits::ExceptionRaiseReply;
|
2014-09-10 17:29:07 -04:00
|
|
|
|
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,
|
2014-12-01 16:06:56 -05:00
|
|
|
|
in_trailer,
|
2014-09-10 17:29:07 -04:00
|
|
|
|
destroy_complex_request);
|
|
|
|
|
if (out_reply->RetCode != KERN_SUCCESS) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out_header->msgh_size = sizeof(*out_reply);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
case Traits::kMachMessageIDExceptionRaiseState: {
|
|
|
|
|
// exception_raise_state(), catch_exception_raise_state(),
|
|
|
|
|
// mach_exception_raise_state(), catch_mach_exception_raise_state().
|
|
|
|
|
using Request = typename Traits::ExceptionRaiseStateRequest;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
|
|
|
|
// 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.
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const Request* in_request_1;
|
2014-09-17 12:08:18 -04:00
|
|
|
|
kern_return_t kr =
|
2014-12-11 14:29:42 -05:00
|
|
|
|
Traits::MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
if (kr != MACH_MSG_SUCCESS) {
|
2014-11-25 14:29:46 -05:00
|
|
|
|
SetMIGReplyError(out_header, kr);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using Reply = typename Traits::ExceptionRaiseStateReply;
|
2014-09-10 17:29:07 -04:00
|
|
|
|
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
2014-09-10 18:57:14 -04:00
|
|
|
|
out_reply->flavor = in_request_1->flavor;
|
2019-01-04 16:57:57 -05:00
|
|
|
|
out_reply->new_stateCnt = base::size(out_reply->new_state);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
out_reply->RetCode =
|
|
|
|
|
interface_->CatchExceptionRaiseState(in_header->msgh_local_port,
|
|
|
|
|
in_request->exception,
|
|
|
|
|
in_request->code,
|
|
|
|
|
in_request->codeCnt,
|
2014-09-10 18:57:14 -04:00
|
|
|
|
&out_reply->flavor,
|
2014-09-10 17:29:07 -04:00
|
|
|
|
in_request_1->old_state,
|
|
|
|
|
in_request_1->old_stateCnt,
|
|
|
|
|
out_reply->new_state,
|
2014-12-01 16:06:56 -05:00
|
|
|
|
&out_reply->new_stateCnt,
|
|
|
|
|
in_trailer);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
case Traits::kMachMessageIDExceptionRaiseStateIdentity: {
|
2014-09-10 17:29:07 -04:00
|
|
|
|
// exception_raise_state_identity(),
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// catch_exception_raise_state_identity(),
|
|
|
|
|
// mach_exception_raise_state_identity(),
|
|
|
|
|
// catch_mach_exception_raise_state_identity().
|
|
|
|
|
using Request = typename Traits::ExceptionRaiseStateIdentityRequest;
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
|
|
|
|
// 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.
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const Request* in_request_1;
|
2014-12-11 14:29:42 -05:00
|
|
|
|
kern_return_t kr = Traits::MIGCheckRequestExceptionRaiseStateIdentity(
|
|
|
|
|
in_request, &in_request_1);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
if (kr != MACH_MSG_SUCCESS) {
|
2014-11-25 14:29:46 -05:00
|
|
|
|
SetMIGReplyError(out_header, kr);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
using Reply = typename Traits::ExceptionRaiseStateIdentityReply;
|
2014-09-10 17:29:07 -04:00
|
|
|
|
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
2014-09-10 18:57:14 -04:00
|
|
|
|
out_reply->flavor = in_request_1->flavor;
|
2019-01-04 16:57:57 -05:00
|
|
|
|
out_reply->new_stateCnt = base::size(out_reply->new_state);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
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,
|
2014-09-10 18:57:14 -04:00
|
|
|
|
&out_reply->flavor,
|
2014-09-10 17:29:07 -04:00
|
|
|
|
in_request_1->old_state,
|
|
|
|
|
in_request_1->old_stateCnt,
|
|
|
|
|
out_reply->new_state,
|
|
|
|
|
&out_reply->new_stateCnt,
|
2014-12-01 16:06:56 -05:00
|
|
|
|
in_trailer,
|
2014-09-10 17:29:07 -04:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-15 14:47:47 -05:00
|
|
|
|
default: {
|
|
|
|
|
SetMIGReplyError(out_header, MIG_BAD_ID);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
//! \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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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() {}
|
2014-12-04 16:45:02 -05:00
|
|
|
|
};
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
//! \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) {}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// ExcServer::Interface:
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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);
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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);
|
|
|
|
|
}
|
2014-12-01 16:06:56 -05:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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);
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
private:
|
|
|
|
|
Interface* interface_; // weak
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(SimplifiedExcServer);
|
|
|
|
|
};
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
} // namespace
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
namespace internal {
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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_);
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
~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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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]);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
// 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,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2014-12-11 14:29:42 -05:00
|
|
|
|
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);
|
|
|
|
|
}
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
private:
|
|
|
|
|
SimplifiedExcServer<ExcTraits> exc_server_;
|
|
|
|
|
SimplifiedExcServer<MachExcTraits> mach_exc_server_;
|
|
|
|
|
UniversalMachExcServer::Interface* interface_; // weak
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
2014-12-11 14:29:42 -05:00
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(UniversalMachExcServerImpl);
|
|
|
|
|
};
|
2014-09-10 17:29:07 -04:00
|
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
2014-12-04 10:18:24 -05:00
|
|
|
|
UniversalMachExcServer::UniversalMachExcServer(
|
|
|
|
|
UniversalMachExcServer::Interface* interface)
|
2014-09-10 17:29:07 -04:00
|
|
|
|
: MachMessageServer::Interface(),
|
2014-12-11 14:29:42 -05:00
|
|
|
|
impl_(new internal::UniversalMachExcServerImpl(interface)) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UniversalMachExcServer::~UniversalMachExcServer() {
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool UniversalMachExcServer::MachMessageServerFunction(
|
2014-09-10 18:57:14 -04:00
|
|
|
|
const mach_msg_header_t* in_header,
|
2014-09-10 17:29:07 -04:00
|
|
|
|
mach_msg_header_t* out_header,
|
|
|
|
|
bool* destroy_complex_request) {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
return impl_->MachMessageServerFunction(
|
|
|
|
|
in_header, out_header, destroy_complex_request);
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 16:45:02 -05:00
|
|
|
|
std::set<mach_msg_id_t> UniversalMachExcServer::MachMessageServerRequestIDs() {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
return impl_->MachMessageServerRequestIDs();
|
2014-12-04 16:45:02 -05:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-10 17:29:07 -04:00
|
|
|
|
mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
return impl_->MachMessageServerRequestSize();
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mach_msg_size_t UniversalMachExcServer::MachMessageServerReplySize() {
|
2014-12-11 14:29:42 -05:00
|
|
|
|
return impl_->MachMessageServerReplySize();
|
2014-09-10 17:29:07 -04:00
|
|
|
|
}
|
|
|
|
|
|
2015-09-04 14:29:12 -04:00
|
|
|
|
kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception,
|
|
|
|
|
exception_behavior_t behavior,
|
2014-09-17 12:08:18 -04:00
|
|
|
|
bool set_thread_state) {
|
2015-09-04 14:29:12 -04:00
|
|
|
|
if (exception == EXC_CRASH
|
|
|
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
|
|
|
|
|
&& MacOSXMinorVersion() >= 11
|
|
|
|
|
#endif
|
|
|
|
|
) {
|
|
|
|
|
return KERN_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-17 12:08:18 -04:00
|
|
|
|
if (!set_thread_state && ExceptionBehaviorHasState(behavior)) {
|
|
|
|
|
return MACH_RCV_PORT_DIED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return KERN_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-01 12:16:22 -04:00
|
|
|
|
void ExcServerCopyState(exception_behavior_t behavior,
|
2015-04-02 15:28:28 -04:00
|
|
|
|
ConstThreadState old_state,
|
2015-04-01 12:16:22 -04:00
|
|
|
|
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]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-10 17:29:07 -04:00
|
|
|
|
} // namespace crashpad
|