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 "snapshot/exception_snapshot_mac.h" |
| 16 |
| 17 #include "base/logging.h" |
| 18 #include "base/strings/stringprintf.h" |
| 19 #include "snapshot/cpu_context_mac.h" |
| 20 #include "util/mac/process_reader.h" |
| 21 #include "util/mach/exc_server_variants.h" |
| 22 #include "util/numeric/safe_assignment.h" |
| 23 |
| 24 namespace crashpad { |
| 25 namespace internal { |
| 26 |
| 27 ExceptionSnapshotMac::ExceptionSnapshotMac() |
| 28 : ExceptionSnapshot(), |
| 29 context_union_(), |
| 30 context_(), |
| 31 codes_(), |
| 32 thread_id_(0), |
| 33 exception_address_(0), |
| 34 exception_(0), |
| 35 exception_code_0_(0), |
| 36 initialized_() { |
| 37 } |
| 38 |
| 39 ExceptionSnapshotMac::~ExceptionSnapshotMac() { |
| 40 } |
| 41 |
| 42 bool ExceptionSnapshotMac::Initialize(ProcessReader* process_reader, |
| 43 thread_t exception_thread, |
| 44 exception_type_t exception, |
| 45 const mach_exception_data_type_t* code, |
| 46 mach_msg_type_number_t code_count, |
| 47 thread_state_flavor_t flavor, |
| 48 const natural_t* state, |
| 49 mach_msg_type_number_t state_count) { |
| 50 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| 51 |
| 52 codes_.push_back(exception); |
| 53 for (mach_msg_type_number_t code_index = 0; |
| 54 code_index < code_count; |
| 55 ++code_index) { |
| 56 codes_.push_back(code[code_index]); |
| 57 } |
| 58 |
| 59 exception_ = exception; |
| 60 mach_exception_code_t exception_code_0 = code[0]; |
| 61 |
| 62 if (exception_ == EXC_CRASH) { |
| 63 exception_ = ExcCrashRecoverOriginalException( |
| 64 exception_code_0, &exception_code_0, NULL); |
| 65 } |
| 66 |
| 67 // ExceptionInfo() returns code[0] in a 32-bit field. This shouldn’t be a |
| 68 // problem because code[0]’s values never exceed 32 bits. Only code[1] is ever |
| 69 // expected to be that wide. |
| 70 if (!AssignIfInRange(&exception_code_0_, exception_code_0)) { |
| 71 LOG(WARNING) |
| 72 << base::StringPrintf("exception_code_0 0x%llx out of range", |
| 73 exception_code_0); |
| 74 return false; |
| 75 } |
| 76 |
| 77 const ProcessReader::Thread* thread = NULL; |
| 78 for (const ProcessReader::Thread& loop_thread : process_reader->Threads()) { |
| 79 if (exception_thread == loop_thread.port) { |
| 80 thread = &loop_thread; |
| 81 break; |
| 82 } |
| 83 } |
| 84 |
| 85 if (!thread) { |
| 86 LOG(WARNING) << "exception_thread not found in task"; |
| 87 return false; |
| 88 } |
| 89 |
| 90 thread_id_ = thread->id; |
| 91 |
| 92 // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS |
| 93 // exceptions, but not for other types of exceptions. |
| 94 bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; |
| 95 |
| 96 #if defined(ARCH_CPU_X86_FAMILY) |
| 97 if (process_reader->Is64Bit()) { |
| 98 context_.architecture = kCPUArchitectureX86_64; |
| 99 context_.x86_64 = &context_union_.x86_64; |
| 100 InitializeCPUContextX86_64(context_.x86_64, |
| 101 flavor, |
| 102 state, |
| 103 state_count, |
| 104 &thread->thread_context.t64, |
| 105 &thread->float_context.f64, |
| 106 &thread->debug_context.d64); |
| 107 } else { |
| 108 context_.architecture = kCPUArchitectureX86; |
| 109 context_.x86 = &context_union_.x86; |
| 110 InitializeCPUContextX86(context_.x86, |
| 111 flavor, |
| 112 state, |
| 113 state_count, |
| 114 &thread->thread_context.t32, |
| 115 &thread->float_context.f32, |
| 116 &thread->debug_context.d32); |
| 117 } |
| 118 |
| 119 // For x86 and x86_64 EXC_BAD_ACCESS exceptions, some code[0] values indicate |
| 120 // that code[1] does not (or may not) carry the exception address: |
| 121 // EXC_I386_GPFLT (10.9.5 xnu-2422.115.4/osfmk/i386/trap.c user_trap() for |
| 122 // T_GENERAL_PROTECTION) and the oddball (VM_PROT_READ | VM_PROT_EXECUTE) |
| 123 // which collides with EXC_I386_BOUNDFLT (10.9.5 |
| 124 // xnu-2422.115.4/osfmk/i386/fpu.c fpextovrflt()). Other EXC_BAD_ACCESS |
| 125 // exceptions come through 10.9.5 xnu-2422.115.4/osfmk/i386/trap.c |
| 126 // user_page_fault_continue() and do contain the exception address in code[1]. |
| 127 if (exception_ == EXC_BAD_ACCESS && |
| 128 (exception_code_0_ == EXC_I386_GPFLT || |
| 129 exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) { |
| 130 code_1_is_exception_address = false; |
| 131 } |
| 132 #endif |
| 133 |
| 134 if (code_1_is_exception_address) { |
| 135 exception_address_ = code[1]; |
| 136 } else { |
| 137 exception_address_ = context_.InstructionPointer(); |
| 138 } |
| 139 |
| 140 INITIALIZATION_STATE_SET_VALID(initialized_); |
| 141 return true; |
| 142 } |
| 143 |
| 144 const CPUContext* ExceptionSnapshotMac::Context() const { |
| 145 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 146 return &context_; |
| 147 } |
| 148 |
| 149 uint64_t ExceptionSnapshotMac::ThreadID() const { |
| 150 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 151 return thread_id_; |
| 152 } |
| 153 |
| 154 uint32_t ExceptionSnapshotMac::Exception() const { |
| 155 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 156 return exception_; |
| 157 } |
| 158 |
| 159 uint32_t ExceptionSnapshotMac::ExceptionInfo() const { |
| 160 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 161 return exception_code_0_; |
| 162 } |
| 163 |
| 164 uint64_t ExceptionSnapshotMac::ExceptionAddress() const { |
| 165 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 166 return exception_address_; |
| 167 } |
| 168 |
| 169 const std::vector<uint64_t>& ExceptionSnapshotMac::Codes() const { |
| 170 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| 171 return codes_; |
| 172 } |
| 173 |
| 174 } // namespace internal |
| 175 } // namespace crashpad |
OLD | NEW |