Add exception_behaviors and its test.

This includes the functions ExceptionBehaviorHasState(),
ExceptionBehaviorHasIdentity(),
ExceptionBehaviorHasMachExceptionCodes(), and ExceptionBehaviorBasic().

TEST=util_test
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/565793005
This commit is contained in:
Mark Mentovai 2014-09-16 17:32:35 -04:00
parent 850ec0657d
commit 06d48e4b0a
7 changed files with 215 additions and 19 deletions

View File

@ -22,6 +22,7 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "util/mach/exc_server_variants.h" #include "util/mach/exc_server_variants.h"
#include "util/mach/exception_behaviors.h"
#include "util/mach/mach_extensions.h" #include "util/mach/mach_extensions.h"
#include "util/test/mac/mach_errors.h" #include "util/test/mac/mach_errors.h"
#include "util/test/mac/mach_multiprocess.h" #include "util/test/mac/mach_multiprocess.h"
@ -206,20 +207,12 @@ class TestExcClientVariants : public UniversalMachExcServer,
} }
} }
exception_behavior_t BasicBehavior() const {
return behavior_ & ~MACH_EXCEPTION_CODES;
}
bool HasIdentity() const { bool HasIdentity() const {
exception_behavior_t basic_behavior = BasicBehavior(); return ExceptionBehaviorHasIdentity(behavior_);
return basic_behavior == EXCEPTION_DEFAULT ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
} }
bool HasState() const { bool HasState() const {
exception_behavior_t basic_behavior = BasicBehavior(); return ExceptionBehaviorHasState(behavior_);
return basic_behavior == EXCEPTION_STATE ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
} }
// The behavior to test. // The behavior to test.

View File

@ -21,6 +21,7 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "util/mach/exception_behaviors.h"
#include "util/mach/mach_extensions.h" #include "util/mach/mach_extensions.h"
#include "util/test/mac/mach_errors.h" #include "util/test/mac/mach_errors.h"
#include "util/test/mac/mach_multiprocess.h" #include "util/test/mac/mach_multiprocess.h"
@ -894,15 +895,10 @@ class TestExcServerVariants : public UniversalMachExcServer,
handled_ = true; handled_ = true;
EXPECT_EQ(behavior_, behavior); EXPECT_EQ(behavior_, behavior);
exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
const bool has_identity = basic_behavior == EXCEPTION_DEFAULT ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
const bool has_state = basic_behavior == EXCEPTION_STATE ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
EXPECT_EQ(LocalPort(), exception_port); EXPECT_EQ(LocalPort(), exception_port);
if (has_identity) { if (ExceptionBehaviorHasIdentity(behavior)) {
EXPECT_NE(kMachPortNull, thread); EXPECT_NE(kMachPortNull, thread);
EXPECT_EQ(ChildTask(), task); EXPECT_EQ(ChildTask(), task);
} else { } else {
@ -921,6 +917,7 @@ class TestExcServerVariants : public UniversalMachExcServer,
SetExpectedChildTermination(kTerminationSignal, sig); SetExpectedChildTermination(kTerminationSignal, sig);
} }
const bool has_state = ExceptionBehaviorHasState(behavior);
if (has_state) { if (has_state) {
EXPECT_EQ(flavor_, *flavor); EXPECT_EQ(flavor_, *flavor);
EXPECT_EQ(state_count_, old_state_count); EXPECT_EQ(state_count_, old_state_count);

View File

@ -0,0 +1,39 @@
// 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/exception_behaviors.h"
namespace crashpad {
bool ExceptionBehaviorHasState(exception_behavior_t behavior) {
const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior);
return basic_behavior == EXCEPTION_STATE ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
}
bool ExceptionBehaviorHasIdentity(exception_behavior_t behavior) {
const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior);
return basic_behavior == EXCEPTION_DEFAULT ||
basic_behavior == EXCEPTION_STATE_IDENTITY;
}
bool ExceptionBehaviorHasMachExceptionCodes(exception_behavior_t behavior) {
return (behavior & MACH_EXCEPTION_CODES) != 0;
}
exception_behavior_t ExceptionBehaviorBasic(exception_behavior_t behavior) {
return behavior & ~MACH_EXCEPTION_CODES;
}
} // namespace crashpad

View File

@ -0,0 +1,94 @@
// 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_EXCEPTION_BEHAVIORS_H_
#define CRASHPAD_UTIL_MACH_EXCEPTION_BEHAVIORS_H_
#include <mach/mach.h>
namespace crashpad {
//! \brief Determines whether \a behavior indicates an exception behavior that
//! carries thread state information.
//!
//! When this function returns `true`, an exception message of \a behavior will
//! carry thread state information. Its \a flavor, \a old_state, \a
//! old_state_count, \a new_state, and \a new_state_count fields will be valid.
//! When this function returns `false`, these fields will not be valid.
//!
//! Exception behaviors that carry thread state information are
//! `EXCEPTION_STATE` and `EXCEPTION_STATE_IDENTITY`. `MACH_EXCEPTION_CODES` may
//! also be set. These behaviors correspond to `exception_raise_state()`,
//! `exception_raise_state_identity()`, `mach_exception_raise_state()`, and
//! `mach_exception_raise_state_identity()`.
//!
//! \param[in] behavior An exception behavior value.
//!
//! \return `true` if \a behavior is `EXCEPTION_STATE` or
//! `EXCEPTION_STATE_IDENTITY`, possibly with `MACH_EXCEPTION_CODES` also
//! set.
bool ExceptionBehaviorHasState(exception_behavior_t behavior);
//! \brief Determines whether \a behavior indicates an exception behavior that
//! carries thread and task identities.
//!
//! When this function returns `true`, an exception message of \a behavior will
//! carry thread and task identities in the form of send rights to the thread
//! and task ports. Its \a thread and \a task fields will be valid. When this
//! function returns `false`, these fields will not be valid.
//!
//! Exception behaviors that carry thread and task identity information are
//! `EXCEPTION_DEFAULT` and `EXCEPTION_STATE_IDENTITY`. `MACH_EXCEPTION_CODES`
//! may also be set. These behaviors correspond to `exception_raise()`,
//! `exception_raise_state_identity()`, `mach_exception_raise()`, and
//! `mach_exception_raise_state_identity()`.
//!
//! \param[in] behavior An exception behavior value.
//!
//! \return `true` if \a behavior is `EXCEPTION_DEFAULT` or
//! `EXCEPTION_STATE_IDENTITY`, possibly with `MACH_EXCEPTION_CODES` also
//! set.
bool ExceptionBehaviorHasIdentity(exception_behavior_t behavior);
//! \brief Determines whether \a behavior indicates an exception behavior that
//! carries 64-bit exception codes (“Mach exception codes”).
//!
//! When this function returns `true`, an exception message of \a behavior will
//! carry 64-bit exception codes of type `mach_exception_code_t` in its \a code
//! field. When this function returns `false`, the exception message will carry
//! 32-bit exception codes of type `exception_data_type_t` in its \a code field.
//!
//! Exception behaviors that carry 64-bit exception codes are those that have
//! `MACH_EXCEPTION_CODES` set. These behaviors correspond to
//! `mach_exception_raise()`, `mach_exception_raise_state()`, and
//! `mach_exception_raise_state_identity()`.
//!
//! \param[in] behavior An exception behavior value.
//!
//! \return `true` if `MACH_EXCEPTION_CODES` is set in \a behavior.
bool ExceptionBehaviorHasMachExceptionCodes(exception_behavior_t behavior);
//! \brief Returns the basic behavior value of \a behavior, its value without
//! `MACH_EXCEPTION_CODES` set.
//!
//! \param[in] behavior An exception behavior value.
//!
//! \return `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
//! `EXCEPTION_STATE_IDENTITY`, assuming \a behavior was a correct exception
//! behavior value.
exception_behavior_t ExceptionBehaviorBasic(exception_behavior_t behavior);
} // namespace crashpad
#endif // CRASHPAD_UTIL_MACH_EXCEPTION_BEHAVIORS_H_

View File

@ -0,0 +1,70 @@
// 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/exception_behaviors.h"
#include "base/basictypes.h"
#include "base/strings/stringprintf.h"
#include "gtest/gtest.h"
#include "util/mach/mach_extensions.h"
namespace {
using namespace crashpad;
TEST(ExceptionBehaviors, ExceptionBehaviors) {
struct TestData {
exception_behavior_t behavior;
bool state;
bool identity;
bool mach_exception_codes;
exception_behavior_t basic_behavior;
};
const TestData kTestData[] = {
{EXCEPTION_DEFAULT, false, true, false, EXCEPTION_DEFAULT},
{EXCEPTION_STATE, true, false, false, EXCEPTION_STATE},
{EXCEPTION_STATE_IDENTITY, true, true, false, EXCEPTION_STATE_IDENTITY},
{kMachExceptionCodes | EXCEPTION_DEFAULT,
false,
true,
true,
EXCEPTION_DEFAULT},
{kMachExceptionCodes | EXCEPTION_STATE,
true,
false,
true,
EXCEPTION_STATE},
{kMachExceptionCodes | EXCEPTION_STATE_IDENTITY,
true,
true,
true,
EXCEPTION_STATE_IDENTITY},
};
for (size_t index = 0; index < arraysize(kTestData); ++index) {
const TestData& test_data = kTestData[index];
SCOPED_TRACE(base::StringPrintf(
"index %zu, behavior %d", index, test_data.behavior));
EXPECT_EQ(test_data.state, ExceptionBehaviorHasState(test_data.behavior));
EXPECT_EQ(test_data.identity,
ExceptionBehaviorHasIdentity(test_data.behavior));
EXPECT_EQ(test_data.mach_exception_codes,
ExceptionBehaviorHasMachExceptionCodes(test_data.behavior));
EXPECT_EQ(test_data.basic_behavior,
ExceptionBehaviorBasic(test_data.behavior));
}
}
} // namespace

View File

@ -18,6 +18,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "util/mach/exception_behaviors.h"
#include "util/mach/mach_extensions.h" #include "util/mach/mach_extensions.h"
#include "util/stdlib/string_number_conversion.h" #include "util/stdlib/string_number_conversion.h"
@ -357,8 +358,7 @@ bool StringToExceptionMask(const base::StringPiece& string,
std::string ExceptionBehaviorToString(exception_behavior_t behavior, std::string ExceptionBehaviorToString(exception_behavior_t behavior,
SymbolicConstantToStringOptions options) { SymbolicConstantToStringOptions options) {
bool mach_exception_codes = behavior & MACH_EXCEPTION_CODES; const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior);
exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
const char* behavior_name = const char* behavior_name =
static_cast<size_t>(basic_behavior) < arraysize(kBehaviorNames) static_cast<size_t>(basic_behavior) < arraysize(kBehaviorNames)
@ -379,7 +379,7 @@ std::string ExceptionBehaviorToString(exception_behavior_t behavior,
"%s%s", kBehaviorPrefix, behavior_name)); "%s%s", kBehaviorPrefix, behavior_name));
} }
if (mach_exception_codes) { if (ExceptionBehaviorHasMachExceptionCodes(behavior)) {
behavior_string.append("|"); behavior_string.append("|");
behavior_string.append((options & kUseShortName) ? kMachExceptionCodesShort behavior_string.append((options & kUseShortName) ? kMachExceptionCodesShort
: kMachExceptionCodesFull); : kMachExceptionCodesFull);

View File

@ -63,6 +63,8 @@
'mach/exc_client_variants.h', 'mach/exc_client_variants.h',
'mach/exc_server_variants.cc', 'mach/exc_server_variants.cc',
'mach/exc_server_variants.h', 'mach/exc_server_variants.h',
'mach/exception_behaviors.cc',
'mach/exception_behaviors.h',
'mach/mach_extensions.cc', 'mach/mach_extensions.cc',
'mach/mach_extensions.h', 'mach/mach_extensions.h',
'mach/mach_message_server.cc', 'mach/mach_message_server.cc',
@ -196,6 +198,7 @@
'mac/service_management_test.mm', 'mac/service_management_test.mm',
'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/mach_extensions_test.cc', 'mach/mach_extensions_test.cc',
'mach/mach_message_server_test.cc', 'mach/mach_message_server_test.cc',
'mach/symbolic_constants_mach_test.cc', 'mach/symbolic_constants_mach_test.cc',