OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 #include "client/capture_context_mac.h" |
| 16 |
| 17 #include <mach/mach.h> |
| 18 #include <stdint.h> |
| 19 |
| 20 #include <algorithm> |
| 21 |
| 22 #include "build/build_config.h" |
| 23 #include "gtest/gtest.h" |
| 24 |
| 25 namespace { |
| 26 |
| 27 using namespace crashpad; |
| 28 |
| 29 // If the context structure has fields that tell whether it’s valid, such as |
| 30 // magic numbers or size fields, sanity-checks those fields for validity with |
| 31 // fatal gtest assertions. For other fields, where it’s possible to reason about |
| 32 // their validity based solely on their contents, sanity-checks via nonfatal |
| 33 // gtest assertions. |
| 34 void SanityCheckContext(NativeCPUContext* context) { |
| 35 #if defined(ARCH_CPU_X86) |
| 36 ASSERT_EQ(x86_THREAD_STATE32, context->tsh.flavor); |
| 37 ASSERT_EQ(static_cast<int>(x86_THREAD_STATE32_COUNT), context->tsh.count); |
| 38 #elif defined(ARCH_CPU_X86_64) |
| 39 ASSERT_EQ(x86_THREAD_STATE64, context->tsh.flavor); |
| 40 ASSERT_EQ(static_cast<int>(x86_THREAD_STATE64_COUNT), context->tsh.count); |
| 41 #endif |
| 42 |
| 43 #if defined(ARCH_CPU_X86_FAMILY) |
| 44 // The segment registers are only capable of storing 16-bit quantities, but |
| 45 // the context structure provides native integer-width fields for them. Ensure |
| 46 // that the high bits are all clear. |
| 47 // |
| 48 // Many bit positions in the flags register are reserved and will always read |
| 49 // a known value. Most reservd bits are always 0, but bit 1 is always 1. Check |
| 50 // that the reserved bits are all set to their expected values. Note that the |
| 51 // set of reserved bits may be relaxed over time with newer CPUs, and that |
| 52 // this test may need to be changed to reflect these developments. The current |
| 53 // set of reserved bits are 1, 3, 5, 15, and 22 and higher. See Intel Software |
| 54 // Developer’s Manual, Volume 1: Basic Architecture (253665-051), 3.4.3 |
| 55 // “EFLAGS Register”, and AMD Architecture Programmer’s Manual, Volume 2: |
| 56 // System Programming (24593-2.53), 3.1.6 “RFLAGS Register”. |
| 57 #if defined(ARCH_CPU_X86) |
| 58 EXPECT_EQ(0u, context->uts.ts32.__cs & ~0xffff); |
| 59 EXPECT_EQ(0u, context->uts.ts32.__ds & ~0xffff); |
| 60 EXPECT_EQ(0u, context->uts.ts32.__es & ~0xffff); |
| 61 EXPECT_EQ(0u, context->uts.ts32.__fs & ~0xffff); |
| 62 EXPECT_EQ(0u, context->uts.ts32.__gs & ~0xffff); |
| 63 EXPECT_EQ(0u, context->uts.ts32.__ss & ~0xffff); |
| 64 EXPECT_EQ(2u, context->uts.ts32.__eflags & 0xffc0802a); |
| 65 #elif defined(ARCH_CPU_X86_64) |
| 66 EXPECT_EQ(0u, context->uts.ts64.__cs & ~UINT64_C(0xffff)); |
| 67 EXPECT_EQ(0u, context->uts.ts64.__fs & ~UINT64_C(0xffff)); |
| 68 EXPECT_EQ(0u, context->uts.ts64.__gs & ~UINT64_C(0xffff)); |
| 69 EXPECT_EQ(2u, context->uts.ts64.__rflags & UINT64_C(0xffffffffffc0802a)); |
| 70 #endif |
| 71 #endif |
| 72 } |
| 73 |
| 74 // A CPU-independent function to return the program counter. |
| 75 uintptr_t ProgramCounterFromContext(NativeCPUContext* context) { |
| 76 #if defined(ARCH_CPU_X86) |
| 77 return context->uts.ts32.__eip; |
| 78 #elif defined(ARCH_CPU_X86_64) |
| 79 return context->uts.ts64.__rip; |
| 80 #endif |
| 81 } |
| 82 |
| 83 // A CPU-independent function to return the stack pointer. |
| 84 uintptr_t StackPointerFromContext(NativeCPUContext* context) { |
| 85 #if defined(ARCH_CPU_X86) |
| 86 return context->uts.ts32.__esp; |
| 87 #elif defined(ARCH_CPU_X86_64) |
| 88 return context->uts.ts64.__rsp; |
| 89 #endif |
| 90 } |
| 91 |
| 92 void TestCaptureContext() { |
| 93 NativeCPUContext context_1; |
| 94 CaptureContext(&context_1); |
| 95 |
| 96 { |
| 97 SCOPED_TRACE("context_1"); |
| 98 SanityCheckContext(&context_1); |
| 99 } |
| 100 if (testing::Test::HasFatalFailure()) { |
| 101 return; |
| 102 } |
| 103 |
| 104 // The program counter reference value is this function’s address. The |
| 105 // captured program counter should be slightly greater than or equal to the |
| 106 // reference program counter. |
| 107 const uintptr_t kReferencePC = |
| 108 reinterpret_cast<uintptr_t>(TestCaptureContext); |
| 109 uintptr_t pc = ProgramCounterFromContext(&context_1); |
| 110 EXPECT_LT(pc - kReferencePC, 64u); |
| 111 |
| 112 // Declare sp and context_2 here because all local variables need to be |
| 113 // declared before computing the stack pointer reference value, so that the |
| 114 // reference value can be the lowest value possible. |
| 115 uintptr_t sp; |
| 116 NativeCPUContext context_2; |
| 117 |
| 118 // The stack pointer reference value is the lowest address of a local variable |
| 119 // in this function. The captured program counter will be slightly less than |
| 120 // or equal to the reference stack pointer. |
| 121 const uintptr_t kReferenceSP = |
| 122 std::min(std::min(reinterpret_cast<uintptr_t>(&context_1), |
| 123 reinterpret_cast<uintptr_t>(&context_2)), |
| 124 std::min(reinterpret_cast<uintptr_t>(&pc), |
| 125 reinterpret_cast<uintptr_t>(&sp))); |
| 126 sp = StackPointerFromContext(&context_1); |
| 127 EXPECT_LT(kReferenceSP - sp, 512u); |
| 128 |
| 129 // Capture the context again, expecting that the stack pointer stays the same |
| 130 // and the program counter increases. Strictly speaking, there’s no guarantee |
| 131 // that these conditions will hold, although they do for known compilers even |
| 132 // under typical optimization. |
| 133 CaptureContext(&context_2); |
| 134 |
| 135 { |
| 136 SCOPED_TRACE("context_2"); |
| 137 SanityCheckContext(&context_2); |
| 138 } |
| 139 if (testing::Test::HasFatalFailure()) { |
| 140 return; |
| 141 } |
| 142 |
| 143 EXPECT_EQ(sp, StackPointerFromContext(&context_2)); |
| 144 EXPECT_GT(ProgramCounterFromContext(&context_2), pc); |
| 145 } |
| 146 |
| 147 TEST(CaptureContextMac, CaptureContext) { |
| 148 TestCaptureContext(); |
| 149 if (Test::HasFatalFailure()) { |
| 150 return; |
| 151 } |
| 152 } |
| 153 |
| 154 } // namespace |
OLD | NEW |