From 06d48e4b0a3db2ce331193303cf4f5505d88dccc Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 16 Sep 2014 17:32:35 -0400 Subject: [PATCH] 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 --- util/mach/exc_client_variants_test.cc | 13 +--- util/mach/exc_server_variants_test.cc | 9 +-- util/mach/exception_behaviors.cc | 39 +++++++++++ util/mach/exception_behaviors.h | 94 +++++++++++++++++++++++++++ util/mach/exception_behaviors_test.cc | 70 ++++++++++++++++++++ util/mach/symbolic_constants_mach.cc | 6 +- util/util.gyp | 3 + 7 files changed, 215 insertions(+), 19 deletions(-) create mode 100644 util/mach/exception_behaviors.cc create mode 100644 util/mach/exception_behaviors.h create mode 100644 util/mach/exception_behaviors_test.cc diff --git a/util/mach/exc_client_variants_test.cc b/util/mach/exc_client_variants_test.cc index 9948f4d8..c8692ab9 100644 --- a/util/mach/exc_client_variants_test.cc +++ b/util/mach/exc_client_variants_test.cc @@ -22,6 +22,7 @@ #include "base/strings/stringprintf.h" #include "gtest/gtest.h" #include "util/mach/exc_server_variants.h" +#include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" #include "util/test/mac/mach_errors.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 { - exception_behavior_t basic_behavior = BasicBehavior(); - return basic_behavior == EXCEPTION_DEFAULT || - basic_behavior == EXCEPTION_STATE_IDENTITY; + return ExceptionBehaviorHasIdentity(behavior_); } bool HasState() const { - exception_behavior_t basic_behavior = BasicBehavior(); - return basic_behavior == EXCEPTION_STATE || - basic_behavior == EXCEPTION_STATE_IDENTITY; + return ExceptionBehaviorHasState(behavior_); } // The behavior to test. diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc index 101ab053..6800b438 100644 --- a/util/mach/exc_server_variants_test.cc +++ b/util/mach/exc_server_variants_test.cc @@ -21,6 +21,7 @@ #include "base/strings/stringprintf.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.h" #include "util/test/mac/mach_errors.h" #include "util/test/mac/mach_multiprocess.h" @@ -894,15 +895,10 @@ class TestExcServerVariants : public UniversalMachExcServer, handled_ = true; 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); - if (has_identity) { + if (ExceptionBehaviorHasIdentity(behavior)) { EXPECT_NE(kMachPortNull, thread); EXPECT_EQ(ChildTask(), task); } else { @@ -921,6 +917,7 @@ class TestExcServerVariants : public UniversalMachExcServer, SetExpectedChildTermination(kTerminationSignal, sig); } + const bool has_state = ExceptionBehaviorHasState(behavior); if (has_state) { EXPECT_EQ(flavor_, *flavor); EXPECT_EQ(state_count_, old_state_count); diff --git a/util/mach/exception_behaviors.cc b/util/mach/exception_behaviors.cc new file mode 100644 index 00000000..eb2a80ca --- /dev/null +++ b/util/mach/exception_behaviors.cc @@ -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 diff --git a/util/mach/exception_behaviors.h b/util/mach/exception_behaviors.h new file mode 100644 index 00000000..14b5448a --- /dev/null +++ b/util/mach/exception_behaviors.h @@ -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 + +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_ diff --git a/util/mach/exception_behaviors_test.cc b/util/mach/exception_behaviors_test.cc new file mode 100644 index 00000000..c4497d61 --- /dev/null +++ b/util/mach/exception_behaviors_test.cc @@ -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 diff --git a/util/mach/symbolic_constants_mach.cc b/util/mach/symbolic_constants_mach.cc index 0efb5409..4bba92af 100644 --- a/util/mach/symbolic_constants_mach.cc +++ b/util/mach/symbolic_constants_mach.cc @@ -18,6 +18,7 @@ #include "base/basictypes.h" #include "base/strings/stringprintf.h" +#include "util/mach/exception_behaviors.h" #include "util/mach/mach_extensions.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, SymbolicConstantToStringOptions options) { - bool mach_exception_codes = behavior & MACH_EXCEPTION_CODES; - exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES; + const exception_behavior_t basic_behavior = ExceptionBehaviorBasic(behavior); const char* behavior_name = static_cast(basic_behavior) < arraysize(kBehaviorNames) @@ -379,7 +379,7 @@ std::string ExceptionBehaviorToString(exception_behavior_t behavior, "%s%s", kBehaviorPrefix, behavior_name)); } - if (mach_exception_codes) { + if (ExceptionBehaviorHasMachExceptionCodes(behavior)) { behavior_string.append("|"); behavior_string.append((options & kUseShortName) ? kMachExceptionCodesShort : kMachExceptionCodesFull); diff --git a/util/util.gyp b/util/util.gyp index 2bd18842..9f90da57 100644 --- a/util/util.gyp +++ b/util/util.gyp @@ -63,6 +63,8 @@ 'mach/exc_client_variants.h', 'mach/exc_server_variants.cc', 'mach/exc_server_variants.h', + 'mach/exception_behaviors.cc', + 'mach/exception_behaviors.h', 'mach/mach_extensions.cc', 'mach/mach_extensions.h', 'mach/mach_message_server.cc', @@ -196,6 +198,7 @@ 'mac/service_management_test.mm', 'mach/exc_client_variants_test.cc', 'mach/exc_server_variants_test.cc', + 'mach/exception_behaviors_test.cc', 'mach/mach_extensions_test.cc', 'mach/mach_message_server_test.cc', 'mach/symbolic_constants_mach_test.cc',