mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:16:13 +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/mach_exc.h"
|
||||
#include "util/mach/mach_excServer.h"
|
||||
#include "util/mach/mach_message_util.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
@ -118,21 +119,6 @@ kern_return_t catch_mach_exception_raise_state_identity(
|
||||
|
||||
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,
|
||||
@ -208,7 +194,7 @@ ExcServer::ExcServer(ExcServer::Interface* interface)
|
||||
bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
PrepareReplyFromRequest(in_header, out_header);
|
||||
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||
|
||||
switch (in_header->msgh_id) {
|
||||
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);
|
||||
kern_return_t kr = MIGCheckRequestExceptionRaise(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -250,7 +236,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
kern_return_t kr =
|
||||
MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -290,7 +276,7 @@ bool ExcServer::MachMessageServerFunction(const mach_msg_header_t* in_header,
|
||||
kern_return_t kr =
|
||||
MIGCheckRequestExceptionRaiseStateIdentity(in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -343,7 +329,7 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
const mach_msg_header_t* in_header,
|
||||
mach_msg_header_t* out_header,
|
||||
bool* destroy_complex_request) {
|
||||
PrepareReplyFromRequest(in_header, out_header);
|
||||
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||
|
||||
switch (in_header->msgh_id) {
|
||||
case kMachMessageIDMachExceptionRaise: {
|
||||
@ -352,7 +338,7 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
const Request* in_request = reinterpret_cast<const Request*>(in_header);
|
||||
kern_return_t kr = MIGCheckRequestMachExceptionRaise(in_request);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -385,7 +371,7 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
kern_return_t kr =
|
||||
MIGCheckRequestMachExceptionRaiseState(in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -425,7 +411,7 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
kern_return_t kr = MIGCheckRequestMachExceptionRaiseStateIdentity(
|
||||
in_request, &in_request_1);
|
||||
if (kr != MACH_MSG_SUCCESS) {
|
||||
SetReplyError(out_header, kr);
|
||||
SetMIGReplyError(out_header, kr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -457,7 +443,7 @@ bool MachExcServer::MachMessageServerFunction(
|
||||
}
|
||||
}
|
||||
|
||||
SetReplyError(out_header, MIG_BAD_ID);
|
||||
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -672,8 +658,8 @@ bool UniversalMachExcServer::MachMessageServerFunction(
|
||||
|
||||
// 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);
|
||||
PrepareMIGReplyFromRequest(in_header, out_header);
|
||||
SetMIGReplyError(out_header, MIG_BAD_ID);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,9 @@ class ExcServer : public MachMessageServer::Interface {
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
//! \brief Constructs an object of this class.
|
||||
//!
|
||||
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||
explicit ExcServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
@ -189,6 +192,9 @@ class MachExcServer : public MachMessageServer::Interface {
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
//! \brief Constructs an object of this class.
|
||||
//!
|
||||
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||
explicit MachExcServer(Interface* interface);
|
||||
|
||||
// MachMessageServer::Interface:
|
||||
@ -248,6 +254,9 @@ class SimplifiedExcServer : public ExcServer, public ExcServer::Interface {
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
//! \brief Constructs an object of this class.
|
||||
//!
|
||||
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||
explicit SimplifiedExcServer(Interface* interface);
|
||||
|
||||
// ExcServer::Interface:
|
||||
@ -341,6 +350,9 @@ class SimplifiedMachExcServer : public MachExcServer,
|
||||
~Interface() {}
|
||||
};
|
||||
|
||||
//! \brief Constructs an object of this class.
|
||||
//!
|
||||
//! \param[in] interface The interface to dispatch requests to. Weak.
|
||||
explicit SimplifiedMachExcServer(Interface* interface);
|
||||
|
||||
// MachExcServer::Interface:
|
||||
@ -402,6 +414,7 @@ class UniversalMachExcServer
|
||||
public internal::SimplifiedExcServer::Interface,
|
||||
public internal::SimplifiedMachExcServer::Interface {
|
||||
public:
|
||||
//! \brief Constructs an object of this class.
|
||||
UniversalMachExcServer();
|
||||
|
||||
// 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/service_management.cc',
|
||||
'mac/service_management.h',
|
||||
'mach/child_port_server.cc',
|
||||
'mach/child_port_server.h',
|
||||
'mach/child_port_types.h',
|
||||
'mach/exc_client_variants.cc',
|
||||
'mach/exc_client_variants.h',
|
||||
@ -53,6 +55,8 @@
|
||||
'mach/mach_extensions.h',
|
||||
'mach/mach_message_server.cc',
|
||||
'mach/mach_message_server.h',
|
||||
'mach/mach_message_util.cc',
|
||||
'mach/mach_message_util.h',
|
||||
'mach/scoped_task_suspend.cc',
|
||||
'mach/scoped_task_suspend.h',
|
||||
'mach/symbolic_constants_mach.cc',
|
||||
@ -232,12 +236,14 @@
|
||||
'mac/launchd_test.mm',
|
||||
'mac/mac_util_test.mm',
|
||||
'mac/service_management_test.mm',
|
||||
'mach/child_port_server_test.cc',
|
||||
'mach/exc_client_variants_test.cc',
|
||||
'mach/exc_server_variants_test.cc',
|
||||
'mach/exception_behaviors_test.cc',
|
||||
'mach/exception_ports_test.cc',
|
||||
'mach/mach_extensions_test.cc',
|
||||
'mach/mach_message_server_test.cc',
|
||||
'mach/mach_message_util_test.cc',
|
||||
'mach/scoped_task_suspend_test.cc',
|
||||
'mach/symbolic_constants_mach_test.cc',
|
||||
'mach/task_memory_test.cc',
|
||||
|
Loading…
x
Reference in New Issue
Block a user