mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add exc_server_variants including UniversalMachExcServer and its test.
TEST=util_test ExcServerVariants.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/545053003
This commit is contained in:
parent
10d1b76b90
commit
177f5dcddc
@ -25,6 +25,7 @@
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
|
||||
namespace {
|
||||
@ -51,21 +52,21 @@ TEST(Bootstrap, BootstrapCheckIn) {
|
||||
kr = BootstrapCheckIn(bootstrap_port, service_name.c_str(), &server_port);
|
||||
ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
|
||||
<< BootstrapErrorMessage(kr, "bootstrap_check_in");
|
||||
ASSERT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), server_port);
|
||||
ASSERT_NE(kMachPortNull, server_port);
|
||||
base::mac::ScopedMachReceiveRight server_port_owner(server_port);
|
||||
|
||||
// A subsequent checkin attempt should fail.
|
||||
mach_port_t fail_port = MACH_PORT_NULL;
|
||||
kr = BootstrapCheckIn(bootstrap_port, service_name.c_str(), &fail_port);
|
||||
EXPECT_EQ(BOOTSTRAP_SERVICE_ACTIVE, kr);
|
||||
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), fail_port);
|
||||
EXPECT_EQ(kMachPortNull, fail_port);
|
||||
|
||||
// Look up the service, getting a send right.
|
||||
kr = bootstrap_look_up(bootstrap_port, service_name.c_str(), &client_port);
|
||||
ASSERT_EQ(BOOTSTRAP_SUCCESS, kr)
|
||||
<< BootstrapErrorMessage(kr, "bootstrap_look_up");
|
||||
base::mac::ScopedMachSendRight client_port_owner(client_port);
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), client_port);
|
||||
EXPECT_NE(kMachPortNull, client_port);
|
||||
|
||||
// Have the “client” send a message to the “server”.
|
||||
struct SendMessage {
|
||||
|
674
util/mach/exc_server_variants.cc
Normal file
674
util/mach/exc_server_variants.cc
Normal file
@ -0,0 +1,674 @@
|
||||
// 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 <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "util/mach/exc.h"
|
||||
#include "util/mach/excServer.h"
|
||||
#include "util/mach/mach_exc.h"
|
||||
#include "util/mach/mach_excServer.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 {
|
||||
|
||||
void PrepareReplyFromRequest(const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header) {
|
||||
out_header->msgh_bits =
|
||||
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(in_header->msgh_bits), 0);
|
||||
out_header->msgh_remote_port = in_header->msgh_remote_port;
|
||||
out_header->msgh_size = sizeof(mig_reply_error_t);
|
||||
out_header->msgh_local_port = MACH_PORT_NULL;
|
||||
out_header->msgh_id = in_header->msgh_id + 100;
|
||||
reinterpret_cast<mig_reply_error_t*>(out_header)->NDR = NDR_record;
|
||||
}
|
||||
|
||||
void SetReplyError(mach_msg_header_t* out_header, kern_return_t error) {
|
||||
reinterpret_cast<mig_reply_error_t*>(out_header)->RetCode = error;
|
||||
}
|
||||
|
||||
// There are no predefined constants for these.
|
||||
enum MachMessageID : mach_msg_id_t {
|
||||
kMachMessageIDExceptionRaise = 2401,
|
||||
kMachMessageIDExceptionRaiseState = 2402,
|
||||
kMachMessageIDExceptionRaiseStateIdentity = 2403,
|
||||
kMachMessageIDMachExceptionRaise = 2405,
|
||||
kMachMessageIDMachExceptionRaiseState = 2406,
|
||||
kMachMessageIDMachExceptionRaiseStateIdentity = 2407,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
ExcServer::ExcServer(ExcServer::Interface* interface)
|
||||
: MachMessageServer::Interface(),
|
||||
interface_(interface) {
|
||||
}
|
||||
|
||||
bool ExcServer::MachMessageServerFunction(mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
PrepareReplyFromRequest(in_header, out_header);
|
||||
|
||||
switch (in_header->msgh_id) {
|
||||
case kMachMessageIDExceptionRaise: {
|
||||
// exception_raise(), catch_exception_raise().
|
||||
typedef __Request__exception_raise_t Request;
|
||||
Request* in_request = reinterpret_cast<Request*>(in_header);
|
||||
kern_return_t kr = __MIG_check__Request__exception_raise_t(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__exception_raise_t Reply;
|
||||
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,
|
||||
destroy_complex_request);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_header->msgh_size = sizeof(*out_reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
case kMachMessageIDExceptionRaiseState: {
|
||||
// exception_raise_state(), catch_exception_raise_state().
|
||||
typedef __Request__exception_raise_state_t Request;
|
||||
Request* in_request = reinterpret_cast<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.
|
||||
Request* in_request_1;
|
||||
kern_return_t kr = __MIG_check__Request__exception_raise_state_t(
|
||||
in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__exception_raise_state_t Reply;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
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,
|
||||
&in_request_1->flavor,
|
||||
in_request_1->old_state,
|
||||
in_request_1->old_stateCnt,
|
||||
out_reply->new_state,
|
||||
&out_reply->new_stateCnt);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_reply->flavor = in_request_1->flavor;
|
||||
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 kMachMessageIDExceptionRaiseStateIdentity: {
|
||||
// exception_raise_state_identity(),
|
||||
// catch_exception_raise_state_identity().
|
||||
typedef __Request__exception_raise_state_identity_t Request;
|
||||
Request* in_request = reinterpret_cast<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.
|
||||
Request* in_request_1;
|
||||
kern_return_t kr = __MIG_check__Request__exception_raise_state_identity_t(
|
||||
in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__exception_raise_state_identity_t Reply;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
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,
|
||||
&in_request_1->flavor,
|
||||
in_request_1->old_state,
|
||||
in_request_1->old_stateCnt,
|
||||
out_reply->new_state,
|
||||
&out_reply->new_stateCnt,
|
||||
destroy_complex_request);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_reply->flavor = in_request_1->flavor;
|
||||
out_header->msgh_size =
|
||||
sizeof(*out_reply) - sizeof(out_reply->new_state) +
|
||||
sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
SetReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_msg_size_t ExcServer::MachMessageServerRequestSize() {
|
||||
return sizeof(__RequestUnion__exc_subsystem);
|
||||
}
|
||||
|
||||
mach_msg_size_t ExcServer::MachMessageServerReplySize() {
|
||||
return sizeof(__ReplyUnion__exc_subsystem);
|
||||
}
|
||||
|
||||
MachExcServer::MachExcServer(MachExcServer::Interface* interface)
|
||||
: MachMessageServer::Interface(),
|
||||
interface_(interface) {
|
||||
}
|
||||
|
||||
bool MachExcServer::MachMessageServerFunction(mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
PrepareReplyFromRequest(in_header, out_header);
|
||||
|
||||
switch (in_header->msgh_id) {
|
||||
case kMachMessageIDMachExceptionRaise: {
|
||||
// mach_exception_raise(), catch_mach_exception_raise().
|
||||
typedef __Request__mach_exception_raise_t Request;
|
||||
Request* in_request = reinterpret_cast<Request*>(in_header);
|
||||
kern_return_t kr =
|
||||
__MIG_check__Request__mach_exception_raise_t(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__mach_exception_raise_t Reply;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->RetCode =
|
||||
interface_->CatchMachExceptionRaise(in_header->msgh_local_port,
|
||||
in_request->thread.name,
|
||||
in_request->task.name,
|
||||
in_request->exception,
|
||||
in_request->code,
|
||||
in_request->codeCnt,
|
||||
destroy_complex_request);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_header->msgh_size = sizeof(*out_reply);
|
||||
return true;
|
||||
}
|
||||
|
||||
case kMachMessageIDMachExceptionRaiseState: {
|
||||
// mach_exception_raise_state(), catch_mach_exception_raise_state().
|
||||
typedef __Request__mach_exception_raise_state_t Request;
|
||||
Request* in_request = reinterpret_cast<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.
|
||||
Request* in_request_1;
|
||||
kern_return_t kr = __MIG_check__Request__mach_exception_raise_state_t(
|
||||
in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__mach_exception_raise_state_t Reply;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->new_stateCnt = arraysize(out_reply->new_state);
|
||||
out_reply->RetCode =
|
||||
interface_->CatchMachExceptionRaiseState(in_header->msgh_local_port,
|
||||
in_request->exception,
|
||||
in_request->code,
|
||||
in_request->codeCnt,
|
||||
&in_request_1->flavor,
|
||||
in_request_1->old_state,
|
||||
in_request_1->old_stateCnt,
|
||||
out_reply->new_state,
|
||||
&out_reply->new_stateCnt);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_reply->flavor = in_request_1->flavor;
|
||||
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 kMachMessageIDMachExceptionRaiseStateIdentity: {
|
||||
// mach_exception_raise_state_identity(),
|
||||
// catch_mach_exception_raise_state_identity().
|
||||
typedef __Request__mach_exception_raise_state_identity_t Request;
|
||||
Request* in_request = reinterpret_cast<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.
|
||||
Request* in_request_1;
|
||||
kern_return_t kr =
|
||||
__MIG_check__Request__mach_exception_raise_state_identity_t(
|
||||
in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef __Reply__mach_exception_raise_state_identity_t Reply;
|
||||
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||
out_reply->new_stateCnt = arraysize(out_reply->new_state);
|
||||
out_reply->RetCode = interface_->CatchMachExceptionRaiseStateIdentity(
|
||||
in_header->msgh_local_port,
|
||||
in_request->thread.name,
|
||||
in_request->task.name,
|
||||
in_request->exception,
|
||||
in_request->code,
|
||||
in_request->codeCnt,
|
||||
&in_request_1->flavor,
|
||||
in_request_1->old_state,
|
||||
in_request_1->old_stateCnt,
|
||||
out_reply->new_state,
|
||||
&out_reply->new_stateCnt,
|
||||
destroy_complex_request);
|
||||
if (out_reply->RetCode != KERN_SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
out_reply->flavor = in_request_1->flavor;
|
||||
out_header->msgh_size =
|
||||
sizeof(*out_reply) - sizeof(out_reply->new_state) +
|
||||
sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
SetReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_msg_size_t MachExcServer::MachMessageServerRequestSize() {
|
||||
return sizeof(__RequestUnion__mach_exc_subsystem);
|
||||
}
|
||||
|
||||
mach_msg_size_t MachExcServer::MachMessageServerReplySize() {
|
||||
return sizeof(__ReplyUnion__mach_exc_subsystem);
|
||||
}
|
||||
|
||||
SimplifiedExcServer::SimplifiedExcServer(
|
||||
SimplifiedExcServer::Interface* interface)
|
||||
: ExcServer(this),
|
||||
ExcServer::Interface(),
|
||||
interface_(interface) {
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedExcServer::CatchExceptionRaise(
|
||||
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,
|
||||
bool* destroy_request) {
|
||||
thread_state_flavor_t flavor = THREAD_STATE_NONE;
|
||||
mach_msg_type_number_t new_state_count = 0;
|
||||
return interface_->CatchException(EXCEPTION_DEFAULT,
|
||||
exception_port,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
&flavor,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&new_state_count,
|
||||
destroy_request);
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedExcServer::CatchExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) {
|
||||
bool destroy_complex_request = false;
|
||||
return interface_->CatchException(EXCEPTION_STATE,
|
||||
exception_port,
|
||||
MACH_PORT_NULL,
|
||||
MACH_PORT_NULL,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
flavor,
|
||||
old_state,
|
||||
old_state_count,
|
||||
new_state,
|
||||
new_state_count,
|
||||
&destroy_complex_request);
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedExcServer::CatchExceptionRaiseStateIdentity(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) {
|
||||
return interface_->CatchException(EXCEPTION_STATE_IDENTITY,
|
||||
exception_port,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
flavor,
|
||||
old_state,
|
||||
old_state_count,
|
||||
new_state,
|
||||
new_state_count,
|
||||
destroy_request);
|
||||
}
|
||||
|
||||
SimplifiedMachExcServer::SimplifiedMachExcServer(
|
||||
SimplifiedMachExcServer::Interface* interface)
|
||||
: MachExcServer(this),
|
||||
MachExcServer::Interface(),
|
||||
interface_(interface) {
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaise(
|
||||
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,
|
||||
bool* destroy_request) {
|
||||
thread_state_flavor_t flavor = THREAD_STATE_NONE;
|
||||
mach_msg_type_number_t new_state_count = 0;
|
||||
return interface_->CatchMachException(
|
||||
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
|
||||
exception_port,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
&flavor,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
&new_state_count,
|
||||
destroy_request);
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const mach_exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) {
|
||||
bool destroy_complex_request = false;
|
||||
return interface_->CatchMachException(EXCEPTION_STATE | MACH_EXCEPTION_CODES,
|
||||
exception_port,
|
||||
MACH_PORT_NULL,
|
||||
MACH_PORT_NULL,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
flavor,
|
||||
old_state,
|
||||
old_state_count,
|
||||
new_state,
|
||||
new_state_count,
|
||||
&destroy_complex_request);
|
||||
}
|
||||
|
||||
kern_return_t SimplifiedMachExcServer::CatchMachExceptionRaiseStateIdentity(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) {
|
||||
return interface_->CatchMachException(
|
||||
EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES,
|
||||
exception_port,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
code,
|
||||
code_count,
|
||||
flavor,
|
||||
old_state,
|
||||
old_state_count,
|
||||
new_state,
|
||||
new_state_count,
|
||||
destroy_request);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
UniversalMachExcServer::UniversalMachExcServer()
|
||||
: MachMessageServer::Interface(),
|
||||
internal::SimplifiedExcServer::Interface(),
|
||||
internal::SimplifiedMachExcServer::Interface(),
|
||||
exc_server_(this),
|
||||
mach_exc_server_(this) {
|
||||
}
|
||||
|
||||
bool UniversalMachExcServer::MachMessageServerFunction(
|
||||
mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
switch (in_header->msgh_id) {
|
||||
case kMachMessageIDMachExceptionRaise:
|
||||
case kMachMessageIDMachExceptionRaiseState:
|
||||
case kMachMessageIDMachExceptionRaiseStateIdentity:
|
||||
return mach_exc_server_.MachMessageServerFunction(
|
||||
in_header, out_header, destroy_complex_request);
|
||||
case kMachMessageIDExceptionRaise:
|
||||
case kMachMessageIDExceptionRaiseState:
|
||||
case kMachMessageIDExceptionRaiseStateIdentity:
|
||||
return exc_server_.MachMessageServerFunction(
|
||||
in_header, out_header, destroy_complex_request);
|
||||
}
|
||||
|
||||
// Do what the MIG-generated server routines do when they can’t dispatch a
|
||||
// message.
|
||||
PrepareReplyFromRequest(in_header, out_header);
|
||||
SetReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
|
||||
return std::max(mach_exc_server_.MachMessageServerRequestSize(),
|
||||
exc_server_.MachMessageServerRequestSize());
|
||||
}
|
||||
|
||||
mach_msg_size_t UniversalMachExcServer::MachMessageServerReplySize() {
|
||||
return std::max(mach_exc_server_.MachMessageServerReplySize(),
|
||||
exc_server_.MachMessageServerReplySize());
|
||||
}
|
||||
|
||||
kern_return_t UniversalMachExcServer::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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
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 CatchMachException(behavior,
|
||||
exception_port,
|
||||
thread,
|
||||
task,
|
||||
exception,
|
||||
code_count ? &mach_codes[0] : NULL,
|
||||
code_count,
|
||||
flavor,
|
||||
old_state,
|
||||
old_state_count,
|
||||
new_state,
|
||||
new_state_count,
|
||||
destroy_complex_request);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
436
util/mach/exc_server_variants.h
Normal file
436
util/mach/exc_server_variants.h
Normal file
@ -0,0 +1,436 @@
|
||||
// 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_EXC_SERVER_VARIANTS_H_
|
||||
#define CRASHPAD_UTIL_MACH_EXC_SERVER_VARIANTS_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "util/mach/mach_message_server.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
// Routines to provide a single unified front-end to the interfaces in
|
||||
// <mach/exc.defs> and <mach/mach_exc.defs>. The two interfaces are identical,
|
||||
// except that the latter allows for 64-bit exception codes, and is requested by
|
||||
// setting the MACH_EXCEPTION_CODES behavior bit associated with an exception
|
||||
// port.
|
||||
|
||||
namespace internal {
|
||||
|
||||
//! \brief A server interface for the `exc` Mach subsystem.
|
||||
class ExcServer : public MachMessageServer::Interface {
|
||||
public:
|
||||
//! \brief An interface that the different request messages that are a part of
|
||||
//! the `exc` Mach subsystem can be dispatched to.
|
||||
class Interface {
|
||||
public:
|
||||
//! \brief Handles exceptions raised by `exception_raise()`.
|
||||
//!
|
||||
//! This behaves equivalently to a `catch_exception_raise()` function used
|
||||
//! with `exc_server()`.
|
||||
//!
|
||||
//! \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 exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
bool* destroy_request) = 0;
|
||||
|
||||
//! \brief Handles exceptions raised by `exception_raise_state()`.
|
||||
//!
|
||||
//! This behaves equivalently to a `catch_exception_raise_state()` function
|
||||
//! used with `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.
|
||||
virtual kern_return_t CatchExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) = 0;
|
||||
|
||||
//! \brief Handles exceptions raised by `exception_raise_state_identity()`.
|
||||
//!
|
||||
//! This behaves equivalently to a `catch_exception_raise_state_identity()`
|
||||
//! function used with `exc_server()`.
|
||||
//!
|
||||
//! \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 exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) = 0;
|
||||
|
||||
protected:
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
explicit ExcServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
virtual bool MachMessageServerFunction(
|
||||
mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
virtual mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
virtual mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
private:
|
||||
Interface* interface_; // weak
|
||||
};
|
||||
|
||||
//! \brief A server interface for the `mach_exc` Mach subsystem.
|
||||
class MachExcServer : public MachMessageServer::Interface {
|
||||
public:
|
||||
//! \brief An interface that the different request messages that are a part of
|
||||
//! the `mach_exc` Mach subsystem can be dispatched to.
|
||||
class Interface {
|
||||
public:
|
||||
//! \brief Handles exceptions raised by `mach_exception_raise()`.
|
||||
//!
|
||||
//! This behaves equivalently to a `catch_mach_exception_raise()` function
|
||||
//! used with `mach_exc_server()`.
|
||||
//!
|
||||
//! \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 CatchMachExceptionRaise(
|
||||
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,
|
||||
bool* destroy_request) = 0;
|
||||
|
||||
//! \brief Handles exceptions raised by `mach_exception_raise_state()`.
|
||||
//!
|
||||
//! This behaves equivalently to a `catch_mach_exception_raise_state()`
|
||||
//! function used with `mach_exc_server()`.
|
||||
//!
|
||||
//! There is no \a destroy_request parameter because, unlike
|
||||
//! CatchMachExceptionRaise() and CatchMachExceptionRaiseStateIdentity(),
|
||||
//! 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.
|
||||
virtual kern_return_t CatchMachExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const mach_exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) = 0;
|
||||
|
||||
//! \brief Handles exceptions raised by
|
||||
//! `mach_exception_raise_state_identity()`.
|
||||
//!
|
||||
//! This behaves equivalently to a
|
||||
//! `catch_mach_exception_raise_state_identity()` function used with
|
||||
//! `mach_exc_server()`.
|
||||
//!
|
||||
//! \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 CatchMachExceptionRaiseStateIdentity(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) = 0;
|
||||
|
||||
protected:
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
explicit MachExcServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
virtual bool MachMessageServerFunction(
|
||||
mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
virtual mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
virtual mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
private:
|
||||
Interface* interface_; // weak
|
||||
};
|
||||
|
||||
//! \brief A server interface for the `exc` Mach subsystem, simplified to have
|
||||
//! only a single interface method needing implementation.
|
||||
class SimplifiedExcServer : public ExcServer, public ExcServer::Interface {
|
||||
public:
|
||||
//! \brief An interface that the different request messages that are a part of
|
||||
//! the `exc` Mach subsystem can be dispatched to.
|
||||
class Interface {
|
||||
public:
|
||||
//! \brief Handles exceptions raised by `exception_raise()`,
|
||||
//! `exception_raise_state()`, and `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.
|
||||
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 exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_complex_request) = 0;
|
||||
|
||||
protected:
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
explicit SimplifiedExcServer(Interface* interface);
|
||||
|
||||
// ExcServer::Interface:
|
||||
|
||||
virtual kern_return_t CatchExceptionRaise(
|
||||
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,
|
||||
bool* destroy_request) override;
|
||||
virtual kern_return_t CatchExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) override;
|
||||
virtual kern_return_t CatchExceptionRaiseStateIdentity(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) override;
|
||||
|
||||
private:
|
||||
Interface* interface_; // weak
|
||||
};
|
||||
|
||||
//! \brief A server interface for the `mach_exc` Mach subsystem, simplified to
|
||||
//! have only a single interface method needing implementation.
|
||||
class SimplifiedMachExcServer : public MachExcServer,
|
||||
public MachExcServer::Interface {
|
||||
public:
|
||||
//! \brief An interface that the different request messages that are a part of
|
||||
//! the `mach_exc` Mach subsystem can be dispatched to.
|
||||
class Interface {
|
||||
public:
|
||||
//! \brief Handles exceptions raised by `mach_exception_raise()`,
|
||||
//! `mach_exception_raise_state()`, and
|
||||
//! `mach_exception_raise_state_identity()`.
|
||||
//!
|
||||
//! When used with UniversalMachExcServer, this also handles exceptions
|
||||
//! raised by `exception_raise()`, `exception_raise_state()`, and
|
||||
//! `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
|
||||
//! MachExcServer::Interface::CatchMachExceptionRaiseStateIdentity().
|
||||
//!
|
||||
//! \param[in] behavior `MACH_EXCEPTION_CODES | EXCEPTION_DEFAULT`,
|
||||
//! `MACH_EXCEPTION_CODES | EXCEPTION_STATE`, or
|
||||
//! `MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY`, identifying which
|
||||
//! exception request message was processed and thus which other
|
||||
//! parameters are valid. When used with UniversalMachExcServer, \a
|
||||
//! behavior can also be `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
|
||||
//! `EXCEPTION_STATE_IDENTITY`.
|
||||
virtual kern_return_t CatchMachException(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_complex_request) = 0;
|
||||
|
||||
protected:
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
explicit SimplifiedMachExcServer(Interface* interface);
|
||||
|
||||
// MachExcServer::Interface:
|
||||
|
||||
virtual kern_return_t CatchMachExceptionRaise(
|
||||
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,
|
||||
bool* destroy_request) override;
|
||||
virtual kern_return_t CatchMachExceptionRaiseState(
|
||||
exception_handler_t exception_port,
|
||||
exception_type_t exception,
|
||||
const mach_exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count) override;
|
||||
virtual kern_return_t CatchMachExceptionRaiseStateIdentity(
|
||||
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,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_request) override;
|
||||
|
||||
private:
|
||||
Interface* interface_; // weak
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
//! \brief A server interface for the `exc` and `mach_exc` Mach subsystems,
|
||||
//! unified to handle exceptions delivered to either subsystem, and
|
||||
//! simplified to have only a single interface method needing
|
||||
//! implementation.
|
||||
//!
|
||||
//! UniversalMachExcServer operates by translating messages received in the
|
||||
//! `exc` subsystem to a variant that is compatible with the `mach_exc`
|
||||
//! subsystem. This involves changing the format of \a code, the exception code
|
||||
//! field, from `exception_data_type_t` to `mach_exception_data_type_t`.
|
||||
//! This is achieved by implementing SimplifiedExcServer::Interface and having
|
||||
//! it forward translated messages to SimplifiedMachExcServer::Interface, which
|
||||
//! is left unimplemented here so that users of this class can provide their own
|
||||
//! implementations.
|
||||
class UniversalMachExcServer
|
||||
: public MachMessageServer::Interface,
|
||||
public internal::SimplifiedExcServer::Interface,
|
||||
public internal::SimplifiedMachExcServer::Interface {
|
||||
public:
|
||||
UniversalMachExcServer();
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
|
||||
virtual bool MachMessageServerFunction(
|
||||
mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
virtual mach_msg_size_t MachMessageServerRequestSize() override;
|
||||
virtual mach_msg_size_t MachMessageServerReplySize() override;
|
||||
|
||||
// internal::SimplifiedExcServer::Interface:
|
||||
|
||||
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 exception_data_type_t* code,
|
||||
mach_msg_type_number_t code_count,
|
||||
thread_state_flavor_t* flavor,
|
||||
const natural_t* old_state,
|
||||
mach_msg_type_number_t old_state_count,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t* new_state_count,
|
||||
bool* destroy_complex_request) override;
|
||||
|
||||
private:
|
||||
internal::SimplifiedExcServer exc_server_;
|
||||
internal::SimplifiedMachExcServer mach_exc_server_;
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MACH_EXC_SERVER_VARIANTS_H_
|
1072
util/mach/exc_server_variants_test.cc
Normal file
1072
util/mach/exc_server_variants_test.cc
Normal file
File diff suppressed because it is too large
Load Diff
44
util/mach/mach_extensions.h
Normal file
44
util/mach/mach_extensions.h
Normal file
@ -0,0 +1,44 @@
|
||||
// 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_MACH_EXTENSIONS_H_
|
||||
#define CRASHPAD_UTIL_MACH_MACH_EXTENSIONS_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief `MACH_PORT_NULL` with the correct type for a Mach port,
|
||||
//! `mach_port_t`.
|
||||
//!
|
||||
//! For situations where implicit conversions between signed and unsigned types
|
||||
//! are not performed, use kMachPortNull instead of an explicit `static_cast` of
|
||||
//! `MACH_PORT_NULL` to `mach_port_t`. This is useful for logging and testing
|
||||
//! assertions.
|
||||
const mach_port_t kMachPortNull = MACH_PORT_NULL;
|
||||
|
||||
// Because exception_mask_t is an int and has one bit for each defined
|
||||
// exception_type_t, it’s reasonable to assume that there cannot be any
|
||||
// officially-defined exception_type_t values higher than 31.
|
||||
// kMachExceptionSimulated uses a value well outside this range because it does
|
||||
// not require a corresponding mask value. Simulated exceptions are delivered to
|
||||
// the exception handler registered for EXC_CRASH exceptions using
|
||||
// EXC_MASK_CRASH.
|
||||
|
||||
//! \brief An exception type to use for simulated exceptions.
|
||||
const exception_type_t kMachExceptionSimulated = 'CPsx';
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MACH_MACH_EXTENSIONS_H_
|
@ -21,6 +21,7 @@
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/file/fd_io.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/test/errors.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
#include "util/test/mac/mach_multiprocess.h"
|
||||
@ -214,8 +215,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
EXPECT_EQ(kRequestMessageId, request->header.msgh_id);
|
||||
if (options_.client_send_complex) {
|
||||
EXPECT_EQ(1u, request->body.msgh_descriptor_count);
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
|
||||
request->port_descriptor.name);
|
||||
EXPECT_NE(kMachPortNull, request->port_descriptor.name);
|
||||
parent_complex_message_port_ = request->port_descriptor.name;
|
||||
EXPECT_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_MOVE_SEND),
|
||||
request->port_descriptor.disposition);
|
||||
@ -224,8 +224,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
request->port_descriptor.type);
|
||||
} else {
|
||||
EXPECT_EQ(0u, request->body.msgh_descriptor_count);
|
||||
EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
|
||||
request->port_descriptor.name);
|
||||
EXPECT_EQ(kMachPortNull, request->port_descriptor.name);
|
||||
EXPECT_EQ(0u, request->port_descriptor.disposition);
|
||||
EXPECT_EQ(0u, request->port_descriptor.type);
|
||||
}
|
||||
@ -318,8 +317,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
<< MachErrorMessage(kr, "MachMessageServer");
|
||||
|
||||
if (options_.client_send_complex) {
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL),
|
||||
parent_complex_message_port_);
|
||||
EXPECT_NE(kMachPortNull, parent_complex_message_port_);
|
||||
mach_port_type_t type;
|
||||
|
||||
if (!options_.expect_server_destroyed_complex) {
|
||||
@ -505,8 +503,7 @@ class TestMachMessageServer : public MachMessageServer::Interface,
|
||||
ASSERT_EQ(static_cast<mach_msg_bits_t>(
|
||||
MACH_MSGH_BITS(0, MACH_MSG_TYPE_MOVE_SEND)), reply.Head.msgh_bits);
|
||||
ASSERT_EQ(sizeof(ReplyMessage), reply.Head.msgh_size);
|
||||
ASSERT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL),
|
||||
reply.Head.msgh_remote_port);
|
||||
ASSERT_EQ(kMachPortNull, reply.Head.msgh_remote_port);
|
||||
ASSERT_EQ(LocalPort(), reply.Head.msgh_local_port);
|
||||
ASSERT_EQ(kReplyMessageId, reply.Head.msgh_id);
|
||||
ASSERT_EQ(0, memcmp(&reply.NDR, &NDR_record, sizeof(NDR_record)));
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "base/rand_util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/mach/bootstrap.h"
|
||||
#include "util/mach/mach_extensions.h"
|
||||
#include "util/misc/scoped_forbid_return.h"
|
||||
#include "util/test/errors.h"
|
||||
#include "util/test/mac/mach_errors.h"
|
||||
@ -105,17 +106,17 @@ void MachMultiprocess::PreFork() {
|
||||
}
|
||||
|
||||
mach_port_t MachMultiprocess::LocalPort() const {
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->local_port);
|
||||
EXPECT_NE(kMachPortNull, info_->local_port);
|
||||
return info_->local_port;
|
||||
}
|
||||
|
||||
mach_port_t MachMultiprocess::RemotePort() const {
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->remote_port);
|
||||
EXPECT_NE(kMachPortNull, info_->remote_port);
|
||||
return info_->remote_port;
|
||||
}
|
||||
|
||||
mach_port_t MachMultiprocess::ChildTask() const {
|
||||
EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), info_->child_task);
|
||||
EXPECT_NE(kMachPortNull, info_->child_task);
|
||||
return info_->child_task;
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,9 @@
|
||||
'mac/process_types/traits.h',
|
||||
'mach/bootstrap.cc',
|
||||
'mach/bootstrap.h',
|
||||
'mach/exc_server_variants.cc',
|
||||
'mach/exc_server_variants.h',
|
||||
'mach/mach_extensions.h',
|
||||
'mach/mach_message_server.cc',
|
||||
'mach/mach_message_server.h',
|
||||
'mach/task_memory.cc',
|
||||
@ -167,6 +170,7 @@
|
||||
'util_test_lib',
|
||||
'util_test_multiprocess_exec_test_child',
|
||||
'../compat/compat.gyp:compat',
|
||||
'../third_party/gmock/gmock.gyp:gmock',
|
||||
'../third_party/gtest/gtest.gyp:gtest',
|
||||
'../third_party/gtest/gtest.gyp:gtest_main',
|
||||
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
||||
@ -185,6 +189,7 @@
|
||||
'mac/process_types_test.cc',
|
||||
'mac/service_management_test.mm',
|
||||
'mach/bootstrap_test.cc',
|
||||
'mach/exc_server_variants_test.cc',
|
||||
'mach/mach_message_server_test.cc',
|
||||
'mach/task_memory_test.cc',
|
||||
'misc/initialization_state_dcheck_test.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user