Index: util/mach/exc_server_variants_test.cc |
diff --git a/util/mach/exc_server_variants_test.cc b/util/mach/exc_server_variants_test.cc |
index 8ca041eb3891ffbc322cf7ea06bfbf7349da2e6b..36439f48d91a94f76d91d5d963ab0ac5dbd14c3e 100644 |
--- a/util/mach/exc_server_variants_test.cc |
+++ b/util/mach/exc_server_variants_test.cc |
@@ -15,6 +15,7 @@ |
#include "util/mach/exc_server_variants.h" |
#include <mach/mach.h> |
+#include <signal.h> |
#include <string.h> |
#include "base/basictypes.h" |
@@ -904,15 +905,13 @@ class TestExcServerVariants : public UniversalMachExcServer, |
EXPECT_EQ(EXC_CRASH, exception); |
EXPECT_EQ(2u, code_count); |
- // The code_count check above would ideally use ASSERT_EQ so that the next |
- // conditional would not be necessary, but ASSERT_* requires a function |
- // returning type void, and the interface dictates otherwise here. |
- if (code_count >= 1) { |
- // The signal that terminated the process is stored in code[0] along with |
- // some other data. See 10.9.4 xnu-2422.110.17/bsd/kern/kern_exit.c |
- // proc_prepareexit(). |
- int sig = (code[0] >> 24) & 0xff; |
- SetExpectedChildTermination(kTerminationSignal, sig); |
+ // The exception and code_count checks above would ideally use ASSERT_EQ so |
+ // that the next conditional would not be necessary, but ASSERT_* requires a |
+ // function returning type void, and the interface dictates otherwise here. |
+ if (exception == EXC_CRASH && code_count >= 1) { |
+ int signal; |
+ ExcCrashRecoverOriginalException(code[0], NULL, &signal); |
+ SetExpectedChildTermination(kTerminationSignal, signal); |
} |
const bool has_state = ExceptionBehaviorHasState(behavior); |
@@ -1075,6 +1074,61 @@ TEST(ExcServerVariants, ThreadStates) { |
} |
} |
+TEST(ExcServerVariants, ExcCrashRecoverOriginalException) { |
+ struct TestData { |
+ mach_exception_data_type_t code_0; |
+ exception_type_t exception; |
+ mach_exception_data_type_t original_code_0; |
+ int signal; |
+ }; |
+ const TestData kTestData[] = { |
+ {0xb100001, EXC_BAD_ACCESS, KERN_INVALID_ADDRESS, SIGSEGV}, |
+ {0xb100002, EXC_BAD_ACCESS, KERN_PROTECTION_FAILURE, SIGSEGV}, |
+ {0xa100002, EXC_BAD_ACCESS, KERN_PROTECTION_FAILURE, SIGBUS}, |
+ {0x4200001, EXC_BAD_INSTRUCTION, 1, SIGILL}, |
+ {0x8300001, EXC_ARITHMETIC, 1, SIGFPE}, |
+ {0x5600002, EXC_BREAKPOINT, 2, SIGTRAP}, |
+ {0x6000000, 0, 0, SIGABRT}, |
+ {0, 0, 0, 0}, |
+ }; |
+ |
+ for (size_t index = 0; index < arraysize(kTestData); ++index) { |
+ const TestData& test_data = kTestData[index]; |
+ SCOPED_TRACE(base::StringPrintf("index %zu, code_0 0x%llx", |
+ index, |
+ test_data.code_0)); |
+ |
+ mach_exception_data_type_t original_code_0; |
+ int signal; |
+ exception_type_t exception = |
+ ExcCrashRecoverOriginalException(test_data.code_0, |
+ &original_code_0, |
+ &signal); |
+ |
+ EXPECT_EQ(test_data.exception, exception); |
+ EXPECT_EQ(test_data.original_code_0, original_code_0); |
+ EXPECT_EQ(test_data.signal, signal); |
+ } |
+ |
+ // Now make sure that ExcCrashRecoverOriginalException() properly ignores |
+ // optional arguments. |
+ COMPILE_ASSERT(arraysize(kTestData) >= 1, must_have_something_to_test); |
+ const TestData& test_data = kTestData[0]; |
+ EXPECT_EQ(test_data.exception, |
+ ExcCrashRecoverOriginalException(test_data.code_0, NULL, NULL)); |
+ |
+ mach_exception_data_type_t original_code_0; |
+ EXPECT_EQ(test_data.exception, |
+ ExcCrashRecoverOriginalException( |
+ test_data.code_0, &original_code_0, NULL)); |
+ EXPECT_EQ(test_data.original_code_0, original_code_0); |
+ |
+ int signal; |
+ EXPECT_EQ(test_data.exception, |
+ ExcCrashRecoverOriginalException(test_data.code_0, NULL, &signal)); |
+ EXPECT_EQ(test_data.signal, signal); |
+} |
+ |
TEST(ExcServerVariants, ExcServerSuccessfulReturnValue) { |
struct TestData { |
exception_behavior_t behavior; |