mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-10 06:36:02 +00:00
Add ChildPortServer, a MachMessageServer::Interface implementation for
the child_port subsystem. Common routines shared with the ExcServer family of classes have been moved to a new file, where they can be shared between different MachMessageServer::Interface implementations. TEST=util_test ChildPortServer.*:MachMessageUtil.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/754123002
This commit is contained in:
parent
af1c7eb098
commit
04aaa36026
110
util/mach/child_port_server.cc
Normal file
110
util/mach/child_port_server.cc
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// 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/child_port_server.h"
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "util/mach/child_portServer.h"
|
||||||
|
#include "util/mach/mach_message_util.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// This function is not used, and is in fact obsoleted by the other
|
||||||
|
// functionality implemented in this file. The standard MIG-generated
|
||||||
|
// child_port_server() (in child_portServer.c) server dispatch routine usable
|
||||||
|
// with the standard mach_msg_server() function calls out to this function.
|
||||||
|
// child_port_server() is unused and is replaced by the more flexible
|
||||||
|
// ChildPortServer, but the linker still needs to see this function definition.
|
||||||
|
|
||||||
|
kern_return_t handle_child_port_check_in(child_port_server_t server,
|
||||||
|
child_port_token_t token,
|
||||||
|
mach_port_t port,
|
||||||
|
mach_msg_type_name_t right_type) {
|
||||||
|
NOTREACHED();
|
||||||
|
return KERN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// There is no predefined constant for this.
|
||||||
|
enum MachMessageID : mach_msg_id_t {
|
||||||
|
kMachMessageIDChildPortCheckIn = 10011,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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. This wrapper function is provided to bridge the const gap
|
||||||
|
// between the code in this file, which is const-correct and treats request
|
||||||
|
// message data as const, and the generated function.
|
||||||
|
|
||||||
|
kern_return_t MIGCheckRequestChildPortCheckIn(
|
||||||
|
const __Request__child_port_check_in_t* in_request) {
|
||||||
|
using Request = __Request__child_port_check_in_t;
|
||||||
|
return __MIG_check__Request__child_port_check_in_t(
|
||||||
|
const_cast<Request*>(in_request));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
ChildPortServer::ChildPortServer(ChildPortServer::Interface* interface)
|
||||||
|
: MachMessageServer::Interface(),
|
||||||
|
interface_(interface) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChildPortServer::MachMessageServerFunction(
|
||||||
|
const mach_msg_header_t* in_header,
|
||||||
|
mach_msg_header_t* out_header,
|
||||||
|
bool* destroy_complex_request) {
|
||||||
|
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||||
|
|
||||||
|
switch (in_header->msgh_id) {
|
||||||
|
case kMachMessageIDChildPortCheckIn: {
|
||||||
|
// child_port_check_in(), handle_child_port_check_in().
|
||||||
|
using Request = __Request__child_port_check_in_t;
|
||||||
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||||
|
kern_return_t kr = MIGCheckRequestChildPortCheckIn(in_request);
|
||||||
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
|
SetMIGReplyError(out_header, kr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Reply = __Reply__child_port_check_in_t;
|
||||||
|
Reply* out_reply = reinterpret_cast<Reply*>(out_header);
|
||||||
|
out_reply->RetCode =
|
||||||
|
interface_->HandleChildPortCheckIn(in_header->msgh_local_port,
|
||||||
|
in_request->token,
|
||||||
|
in_request->port.name,
|
||||||
|
in_request->port.disposition,
|
||||||
|
destroy_complex_request);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_msg_size_t ChildPortServer::MachMessageServerRequestSize() {
|
||||||
|
return sizeof(__RequestUnion__handle_child_port_subsystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_msg_size_t ChildPortServer::MachMessageServerReplySize() {
|
||||||
|
return sizeof(__ReplyUnion__handle_child_port_subsystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
74
util/mach/child_port_server.h
Normal file
74
util/mach/child_port_server.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// 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_CHILD_PORT_SERVER_H_
|
||||||
|
#define CRASHPAD_UTIL_MACH_CHILD_PORT_SERVER_H_
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "util/mach/child_port_types.h"
|
||||||
|
#include "util/mach/mach_message_server.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
//! \brief A server interface for the `child_port` Mach subsystem.
|
||||||
|
class ChildPortServer : public MachMessageServer::Interface {
|
||||||
|
public:
|
||||||
|
//! \brief An interface that the request message that is a part of the
|
||||||
|
//! `child_port` Mach subsystem can be dispatched to.
|
||||||
|
class Interface {
|
||||||
|
public:
|
||||||
|
//! \brief Handles check-ins sent by `child_port_check_in()`.
|
||||||
|
//!
|
||||||
|
//! This behaves equivalently to a `handle_child_port_check_in()` function
|
||||||
|
//! used with `child_port_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 HandleChildPortCheckIn(
|
||||||
|
child_port_server_t server,
|
||||||
|
const child_port_token_t token,
|
||||||
|
mach_port_t port,
|
||||||
|
mach_msg_type_name_t right_type,
|
||||||
|
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 ChildPortServer(Interface* interface);
|
||||||
|
|
||||||
|
// MachMessageServer::Interface:
|
||||||
|
|
||||||
|
bool MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||||
|
mach_msg_header_t* out_header,
|
||||||
|
bool* destroy_complex_request) override;
|
||||||
|
|
||||||
|
mach_msg_size_t MachMessageServerRequestSize() override;
|
||||||
|
mach_msg_size_t MachMessageServerReplySize() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Interface* interface_; // weak
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ChildPortServer);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_MACH_CHILD_PORT_SERVER_H_
|
133
util/mach/child_port_server_test.cc
Normal file
133
util/mach/child_port_server_test.cc
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// 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/child_port_server.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "util/mach/mach_extensions.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using testing::Eq;
|
||||||
|
using testing::Pointee;
|
||||||
|
using testing::Return;
|
||||||
|
|
||||||
|
// Fake Mach ports. These aren’t used as ports in these tests, they’re just used
|
||||||
|
// as cookies to make sure that the correct values get passed to the correct
|
||||||
|
// places.
|
||||||
|
const mach_port_t kServerLocalPort = 0x05050505;
|
||||||
|
const mach_port_t kCheckInPort = 0x06060606;
|
||||||
|
|
||||||
|
// Other fake values.
|
||||||
|
const mach_msg_type_name_t kCheckInPortRightType = MACH_MSG_TYPE_PORT_SEND;
|
||||||
|
const child_port_token_t kCheckInToken = 0xfedcba9876543210;
|
||||||
|
|
||||||
|
// The definition of the request structure from child_port.h isn’t available
|
||||||
|
// here. It needs custom initialization code, so duplicate the expected
|
||||||
|
// definition of the structure from child_port.h here in this file, and provide
|
||||||
|
// the initialization code as a method in true object-oriented fashion.
|
||||||
|
|
||||||
|
struct __attribute__((packed, aligned(4))) ChildPortCheckInRequest {
|
||||||
|
ChildPortCheckInRequest() {
|
||||||
|
memset(this, 0xa5, sizeof(*this));
|
||||||
|
Head.msgh_bits =
|
||||||
|
MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND) | MACH_MSGH_BITS_COMPLEX;
|
||||||
|
Head.msgh_size = sizeof(*this);
|
||||||
|
Head.msgh_remote_port = MACH_PORT_NULL;
|
||||||
|
Head.msgh_local_port = kServerLocalPort;
|
||||||
|
Head.msgh_id = 10011;
|
||||||
|
msgh_body.msgh_descriptor_count = 1;
|
||||||
|
port.name = kCheckInPort;
|
||||||
|
port.disposition = kCheckInPortRightType;
|
||||||
|
port.type = MACH_MSG_PORT_DESCRIPTOR;
|
||||||
|
NDR = NDR_record;
|
||||||
|
token = kCheckInToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_msg_header_t Head;
|
||||||
|
mach_msg_body_t msgh_body;
|
||||||
|
mach_msg_port_descriptor_t port;
|
||||||
|
NDR_record_t NDR;
|
||||||
|
child_port_token_t token;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((packed, aligned(4))) MIGReply {
|
||||||
|
MIGReply() {
|
||||||
|
memset(this, 0x5a, sizeof(*this));
|
||||||
|
RetCode = KERN_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_msg_header_t Head;
|
||||||
|
NDR_record_t NDR;
|
||||||
|
kern_return_t RetCode;
|
||||||
|
|
||||||
|
void Verify() {
|
||||||
|
EXPECT_EQ(implicit_cast<mach_msg_bits_t>(MACH_MSGH_BITS(0, 0)),
|
||||||
|
Head.msgh_bits);
|
||||||
|
EXPECT_EQ(sizeof(*this), Head.msgh_size);
|
||||||
|
EXPECT_EQ(kMachPortNull, Head.msgh_remote_port);
|
||||||
|
EXPECT_EQ(kMachPortNull, Head.msgh_local_port);
|
||||||
|
EXPECT_EQ(10111, Head.msgh_id);
|
||||||
|
EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR)));
|
||||||
|
EXPECT_EQ(MIG_NO_REPLY, RetCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockChildPortServerInterface : public ChildPortServer::Interface {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD5(HandleChildPortCheckIn,
|
||||||
|
kern_return_t(child_port_server_t server,
|
||||||
|
const child_port_token_t token,
|
||||||
|
mach_port_t port,
|
||||||
|
mach_msg_type_name_t right_type,
|
||||||
|
bool* destroy_complex_request));
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(ChildPortServer, MockChildPortCheckIn) {
|
||||||
|
MockChildPortServerInterface server_interface;
|
||||||
|
ChildPortServer server(&server_interface);
|
||||||
|
|
||||||
|
ChildPortCheckInRequest request;
|
||||||
|
EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
|
||||||
|
|
||||||
|
MIGReply reply;
|
||||||
|
EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
|
||||||
|
|
||||||
|
EXPECT_CALL(server_interface,
|
||||||
|
HandleChildPortCheckIn(kServerLocalPort,
|
||||||
|
kCheckInToken,
|
||||||
|
kCheckInPort,
|
||||||
|
kCheckInPortRightType,
|
||||||
|
Pointee(Eq(false))))
|
||||||
|
.WillOnce(Return(MIG_NO_REPLY))
|
||||||
|
.RetiresOnSaturation();
|
||||||
|
|
||||||
|
bool destroy_complex_request = false;
|
||||||
|
EXPECT_TRUE(server.MachMessageServerFunction(
|
||||||
|
reinterpret_cast<mach_msg_header_t*>(&request),
|
||||||
|
reinterpret_cast<mach_msg_header_t*>(&reply),
|
||||||
|
&destroy_complex_request));
|
||||||
|
EXPECT_FALSE(destroy_complex_request);
|
||||||
|
|
||||||
|
reply.Verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
@ -23,6 +23,7 @@
|
|||||||
#include "util/mach/excServer.h"
|
#include "util/mach/excServer.h"
|
||||||
#include "util/mach/mach_exc.h"
|
#include "util/mach/mach_exc.h"
|
||||||
#include "util/mach/mach_excServer.h"
|
#include "util/mach/mach_excServer.h"
|
||||||
|
#include "util/mach/mach_message_util.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@ -118,21 +119,6 @@ kern_return_t catch_mach_exception_raise_state_identity(
|
|||||||
|
|
||||||
namespace {
|
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.
|
// There are no predefined constants for these.
|
||||||
enum MachMessageID : mach_msg_id_t {
|
enum MachMessageID : mach_msg_id_t {
|
||||||
kMachMessageIDExceptionRaise = 2401,
|
kMachMessageIDExceptionRaise = 2401,
|
||||||
@ -208,7 +194,7 @@ ExcServer::ExcServer(ExcServer::Interface* interface)
|
|||||||
bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||||
mach_msg_header_t* out_header,
|
mach_msg_header_t* out_header,
|
||||||
bool* destroy_complex_request) {
|
bool* destroy_complex_request) {
|
||||||
PrepareReplyFromRequest(in_header, out_header);
|
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||||
|
|
||||||
switch (in_header->msgh_id) {
|
switch (in_header->msgh_id) {
|
||||||
case kMachMessageIDExceptionRaise: {
|
case kMachMessageIDExceptionRaise: {
|
||||||
@ -217,7 +203,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
|||||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||||
kern_return_t kr = MIGCheckRequestExceptionRaise(in_request);
|
kern_return_t kr = MIGCheckRequestExceptionRaise(in_request);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +236,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
|||||||
kern_return_t kr =
|
kern_return_t kr =
|
||||||
MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
|
MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,7 +276,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
|||||||
kern_return_t kr =
|
kern_return_t kr =
|
||||||
MIGCheckRequestExceptionRaiseStateIdentity(in_request, &in_request_1);
|
MIGCheckRequestExceptionRaiseStateIdentity(in_request, &in_request_1);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +308,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetReplyError(out_header, MIG_BAD_ID);
|
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +329,7 @@ bool MachExcServer::MachMessageServerFunction(
|
|||||||
const mach_msg_header_t* in_header,
|
const mach_msg_header_t* in_header,
|
||||||
mach_msg_header_t* out_header,
|
mach_msg_header_t* out_header,
|
||||||
bool* destroy_complex_request) {
|
bool* destroy_complex_request) {
|
||||||
PrepareReplyFromRequest(in_header, out_header);
|
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||||
|
|
||||||
switch (in_header->msgh_id) {
|
switch (in_header->msgh_id) {
|
||||||
case kMachMessageIDMachExceptionRaise: {
|
case kMachMessageIDMachExceptionRaise: {
|
||||||
@ -352,7 +338,7 @@ bool MachExcServer::MachMessageServerFunction(
|
|||||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||||
kern_return_t kr = MIGCheckRequestMachExceptionRaise(in_request);
|
kern_return_t kr = MIGCheckRequestMachExceptionRaise(in_request);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,7 +371,7 @@ bool MachExcServer::MachMessageServerFunction(
|
|||||||
kern_return_t kr =
|
kern_return_t kr =
|
||||||
MIGCheckRequestMachExceptionRaiseState(in_request, &in_request_1);
|
MIGCheckRequestMachExceptionRaiseState(in_request, &in_request_1);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +411,7 @@ bool MachExcServer::MachMessageServerFunction(
|
|||||||
kern_return_t kr = MIGCheckRequestMachExceptionRaiseStateIdentity(
|
kern_return_t kr = MIGCheckRequestMachExceptionRaiseStateIdentity(
|
||||||
in_request, &in_request_1);
|
in_request, &in_request_1);
|
||||||
if (kr != MACH_MSG_SUCCESS) {
|
if (kr != MACH_MSG_SUCCESS) {
|
||||||
SetReplyError(out_header, kr);
|
SetMIGReplyError(out_header, kr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,7 +443,7 @@ bool MachExcServer::MachMessageServerFunction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetReplyError(out_header, MIG_BAD_ID);
|
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,8 +658,8 @@ bool UniversalMachExcServer::MachMessageServerFunction(
|
|||||||
|
|
||||||
// Do what the MIG-generated server routines do when they can’t dispatch a
|
// Do what the MIG-generated server routines do when they can’t dispatch a
|
||||||
// message.
|
// message.
|
||||||
PrepareReplyFromRequest(in_header, out_header);
|
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||||
SetReplyError(out_header, MIG_BAD_ID);
|
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +100,9 @@ class ExcServer : public MachMessageServer::Interface {
|
|||||||
~Interface() {}
|
~Interface() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief Constructs an object of this class.
|
||||||
|
//!
|
||||||
|
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||||
explicit ExcServer(Interface* interface);
|
explicit ExcServer(Interface* interface);
|
||||||
|
|
||||||
// MachMessageServer::Interface:
|
// MachMessageServer::Interface:
|
||||||
@ -189,6 +192,9 @@ class MachExcServer : public MachMessageServer::Interface {
|
|||||||
~Interface() {}
|
~Interface() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief Constructs an object of this class.
|
||||||
|
//!
|
||||||
|
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||||
explicit MachExcServer(Interface* interface);
|
explicit MachExcServer(Interface* interface);
|
||||||
|
|
||||||
// MachMessageServer::Interface:
|
// MachMessageServer::Interface:
|
||||||
@ -248,6 +254,9 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface {
|
|||||||
~Interface() {}
|
~Interface() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief Constructs an object of this class.
|
||||||
|
//!
|
||||||
|
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||||
explicit SimplifiedExcServer(Interface* interface);
|
explicit SimplifiedExcServer(Interface* interface);
|
||||||
|
|
||||||
// ExcServer::Interface:
|
// ExcServer::Interface:
|
||||||
@ -341,6 +350,9 @@ class SimplifiedMachExcServer : public MachExcServer,
|
|||||||
~Interface() {}
|
~Interface() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \brief Constructs an object of this class.
|
||||||
|
//!
|
||||||
|
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||||
explicit SimplifiedMachExcServer(Interface* interface);
|
explicit SimplifiedMachExcServer(Interface* interface);
|
||||||
|
|
||||||
// MachExcServer::Interface:
|
// MachExcServer::Interface:
|
||||||
@ -402,6 +414,7 @@ class UniversalMachExcServer
|
|||||||
public internal::SimplifiedExcServer::Interface,
|
public internal::SimplifiedExcServer::Interface,
|
||||||
public internal::SimplifiedMachExcServer::Interface {
|
public internal::SimplifiedMachExcServer::Interface {
|
||||||
public:
|
public:
|
||||||
|
//! \brief Constructs an object of this class.
|
||||||
UniversalMachExcServer();
|
UniversalMachExcServer();
|
||||||
|
|
||||||
// MachMessageServer::Interface:
|
// MachMessageServer::Interface:
|
||||||
|
37
util/mach/mach_message_util.cc
Normal file
37
util/mach/mach_message_util.cc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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/mach_message_util.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
void PrepareMIGReplyFromRequest(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;
|
||||||
|
|
||||||
|
// MIG-generated dispatch routines don’t do this, but they should.
|
||||||
|
out_header->msgh_reserved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error) {
|
||||||
|
reinterpret_cast<mig_reply_error_t*>(out_header)->RetCode = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
53
util/mach/mach_message_util.h
Normal file
53
util/mach/mach_message_util.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// 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_MESSAGE_UTIL_H_
|
||||||
|
#define CRASHPAD_UTIL_MACH_MACH_MESSAGE_UTIL_H_
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
//! \brief Initializes a reply message for a MIG server routine based on its
|
||||||
|
//! corresponding request.
|
||||||
|
//!
|
||||||
|
//! If a request is handled by a server routine, it may be necessary to revise
|
||||||
|
//! some of the fields set by this function, such as `msgh_size` and any fields
|
||||||
|
//! defined in a routine’s reply structure type.
|
||||||
|
//!
|
||||||
|
//! \param[in] in_header The request message to base the reply on.
|
||||||
|
//! \param[out] out_header The reply message to initialize. \a out_header will
|
||||||
|
//! be treated as a `mig_reply_error_t*` and all of its fields will be set
|
||||||
|
//! except for `RetCode`, which must be set by SetMIGReplyError(). This
|
||||||
|
//! argument is accepted as a `mach_msg_header_t*` instead of a
|
||||||
|
//! `mig_reply_error_t*` because that is the type that callers are expected
|
||||||
|
//! to possess in the C API.
|
||||||
|
void PrepareMIGReplyFromRequest(const mach_msg_header_t* in_header,
|
||||||
|
mach_msg_header_t* out_header);
|
||||||
|
|
||||||
|
//! \brief Sets the error code in a reply message for a MIG server routine.
|
||||||
|
//!
|
||||||
|
//! \param[inout] out_header The reply message to operate on. \a out_header will
|
||||||
|
//! be treated as a `mig_reply_error_t*` and its `RetCode` field will be
|
||||||
|
//! set. This argument is accepted as a `mach_msg_header_t*` instead of a
|
||||||
|
//! `mig_reply_error_t*` because that is the type that callers are expected
|
||||||
|
//! to possess in the C API.
|
||||||
|
//! \param[in] error The error code to store in \a out_header.
|
||||||
|
//!
|
||||||
|
//! \sa PrepareMIGReplyFromRequest()
|
||||||
|
void SetMIGReplyError(mach_msg_header_t* out_header, kern_return_t error);
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_MACH_MACH_MESSAGE_UTIL_H_
|
68
util/mach/mach_message_util_test.cc
Normal file
68
util/mach/mach_message_util_test.cc
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// 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/mach_message_util.h"
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "util/mach/mach_extensions.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(MachMessageUtil, PrepareMIGReplyFromRequest_SetMIGReplyError) {
|
||||||
|
mach_msg_header_t request;
|
||||||
|
request.msgh_bits =
|
||||||
|
MACH_MSGH_BITS_COMPLEX |
|
||||||
|
MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, MACH_MSG_TYPE_PORT_SEND);
|
||||||
|
request.msgh_size = 64;
|
||||||
|
request.msgh_remote_port = 0x01234567;
|
||||||
|
request.msgh_local_port = 0x89abcdef;
|
||||||
|
request.msgh_reserved = 0xa5a5a5a5;
|
||||||
|
request.msgh_id = 1011;
|
||||||
|
|
||||||
|
mig_reply_error_t reply;
|
||||||
|
|
||||||
|
// PrepareMIGReplyFromRequest() doesn’t touch this field.
|
||||||
|
reply.RetCode = MIG_TYPE_ERROR;
|
||||||
|
|
||||||
|
PrepareMIGReplyFromRequest(&request, &reply.Head);
|
||||||
|
|
||||||
|
EXPECT_EQ(implicit_cast<mach_msg_bits_t>(
|
||||||
|
MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0)),
|
||||||
|
reply.Head.msgh_bits);
|
||||||
|
EXPECT_EQ(sizeof(reply), reply.Head.msgh_size);
|
||||||
|
EXPECT_EQ(request.msgh_remote_port, reply.Head.msgh_remote_port);
|
||||||
|
EXPECT_EQ(kMachPortNull, reply.Head.msgh_local_port);
|
||||||
|
EXPECT_EQ(0u, reply.Head.msgh_reserved);
|
||||||
|
EXPECT_EQ(1111, reply.Head.msgh_id);
|
||||||
|
EXPECT_EQ(NDR_record.mig_vers, reply.NDR.mig_vers);
|
||||||
|
EXPECT_EQ(NDR_record.if_vers, reply.NDR.if_vers);
|
||||||
|
EXPECT_EQ(NDR_record.reserved1, reply.NDR.reserved1);
|
||||||
|
EXPECT_EQ(NDR_record.mig_encoding, reply.NDR.mig_encoding);
|
||||||
|
EXPECT_EQ(NDR_record.int_rep, reply.NDR.int_rep);
|
||||||
|
EXPECT_EQ(NDR_record.char_rep, reply.NDR.char_rep);
|
||||||
|
EXPECT_EQ(NDR_record.float_rep, reply.NDR.float_rep);
|
||||||
|
EXPECT_EQ(NDR_record.reserved2, reply.NDR.reserved2);
|
||||||
|
EXPECT_EQ(MIG_TYPE_ERROR, reply.RetCode);
|
||||||
|
|
||||||
|
SetMIGReplyError(&reply.Head, MIG_BAD_ID);
|
||||||
|
|
||||||
|
EXPECT_EQ(MIG_BAD_ID, reply.RetCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
@ -40,6 +40,8 @@
|
|||||||
'mac/mac_util.h',
|
'mac/mac_util.h',
|
||||||
'mac/service_management.cc',
|
'mac/service_management.cc',
|
||||||
'mac/service_management.h',
|
'mac/service_management.h',
|
||||||
|
'mach/child_port_server.cc',
|
||||||
|
'mach/child_port_server.h',
|
||||||
'mach/child_port_types.h',
|
'mach/child_port_types.h',
|
||||||
'mach/exc_client_variants.cc',
|
'mach/exc_client_variants.cc',
|
||||||
'mach/exc_client_variants.h',
|
'mach/exc_client_variants.h',
|
||||||
@ -53,6 +55,8 @@
|
|||||||
'mach/mach_extensions.h',
|
'mach/mach_extensions.h',
|
||||||
'mach/mach_message_server.cc',
|
'mach/mach_message_server.cc',
|
||||||
'mach/mach_message_server.h',
|
'mach/mach_message_server.h',
|
||||||
|
'mach/mach_message_util.cc',
|
||||||
|
'mach/mach_message_util.h',
|
||||||
'mach/scoped_task_suspend.cc',
|
'mach/scoped_task_suspend.cc',
|
||||||
'mach/scoped_task_suspend.h',
|
'mach/scoped_task_suspend.h',
|
||||||
'mach/symbolic_constants_mach.cc',
|
'mach/symbolic_constants_mach.cc',
|
||||||
@ -232,12 +236,14 @@
|
|||||||
'mac/launchd_test.mm',
|
'mac/launchd_test.mm',
|
||||||
'mac/mac_util_test.mm',
|
'mac/mac_util_test.mm',
|
||||||
'mac/service_management_test.mm',
|
'mac/service_management_test.mm',
|
||||||
|
'mach/child_port_server_test.cc',
|
||||||
'mach/exc_client_variants_test.cc',
|
'mach/exc_client_variants_test.cc',
|
||||||
'mach/exc_server_variants_test.cc',
|
'mach/exc_server_variants_test.cc',
|
||||||
'mach/exception_behaviors_test.cc',
|
'mach/exception_behaviors_test.cc',
|
||||||
'mach/exception_ports_test.cc',
|
'mach/exception_ports_test.cc',
|
||||||
'mach/mach_extensions_test.cc',
|
'mach/mach_extensions_test.cc',
|
||||||
'mach/mach_message_server_test.cc',
|
'mach/mach_message_server_test.cc',
|
||||||
|
'mach/mach_message_util_test.cc',
|
||||||
'mach/scoped_task_suspend_test.cc',
|
'mach/scoped_task_suspend_test.cc',
|
||||||
'mach/symbolic_constants_mach_test.cc',
|
'mach/symbolic_constants_mach_test.cc',
|
||||||
'mach/task_memory_test.cc',
|
'mach/task_memory_test.cc',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user