Chromium Code Reviews| 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 "snapshot/cpu_context_mac.h" | |
| 19 #include "util/mac/process_reader.h" | |
| 20 | |
| 21 namespace crashpad { | |
| 22 namespace internal { | |
| 23 | |
| 24 ExceptionSnapshotMac::ExceptionSnapshotMac() | |
| 25 : ExceptionSnapshot(), | |
| 26 context_union_(), | |
| 27 context_(), | |
| 28 codes_(), | |
| 29 thread_id_(0), | |
| 30 exception_address_(0), | |
| 31 exception_(0), | |
| 32 exception_code_0_(0), | |
| 33 initialized_() { | |
| 34 } | |
| 35 | |
| 36 ExceptionSnapshotMac::~ExceptionSnapshotMac() { | |
| 37 } | |
| 38 | |
| 39 bool ExceptionSnapshotMac::Initialize(ProcessReader* process_reader, | |
| 40 thread_t exception_thread, | |
| 41 exception_type_t exception, | |
| 42 const mach_exception_data_type_t* code, | |
| 43 mach_msg_type_number_t code_count, | |
| 44 thread_state_flavor_t flavor, | |
| 45 const natural_t* state, | |
| 46 mach_msg_type_number_t state_count) { | |
| 47 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | |
| 48 | |
| 49 codes_.push_back(exception); | |
| 50 for (mach_msg_type_number_t code_index = 0; | |
| 51 code_index < code_count; | |
| 52 ++code_index) { | |
| 53 codes_.push_back(code[code_index]); | |
| 54 } | |
| 55 | |
| 56 exception_ = exception; | |
| 57 exception_code_0_ = code[0]; | |
| 58 | |
| 59 if (exception == EXC_CRASH) { | |
| 60 // Recover the original exception and the original code[0] from code[0]. See | |
| 61 // 10.9.5 xnu-2422.115.4/bsd/kern/kern_exit.c proc_prepareexit(). | |
| 62 // | |
| 63 // This is only done if the EXC_CRASH exception originated from a previous | |
| 64 // exception. This is not the case for certain software-triggered | |
| 65 // terminations, such as exiting on a signal that causes termination. This | |
| 66 // happens by default for SIGABRT, for example, so abort() calls will | |
| 67 // ordinarily lead to EXC_CRASH showing up in Exception(). | |
| 68 // | |
| 69 // Note: the signal number is stored at (code[0] >> 24) & 0xff. | |
| 70 exception_type_t original_exception = (code[0] >> 20) & 0xf; | |
|
Robert Sesek
2014/10/13 21:04:54
This is ExcCrashRecoverOriginalException() right?
| |
| 71 if (original_exception > 0) { | |
| 72 exception_ = original_exception; | |
| 73 exception_code_0_ = code[0] & 0xfffff; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 const std::vector<ProcessReader::Thread>& threads = process_reader->Threads(); | |
| 78 const ProcessReader::Thread* thread = NULL; | |
| 79 for (std::vector<ProcessReader::Thread>::const_iterator thread_iterator = | |
|
Robert Sesek
2014/10/13 21:04:54
C++11 loop ?
| |
| 80 threads.begin(); | |
| 81 thread_iterator != threads.end(); | |
| 82 ++thread_iterator) { | |
| 83 if (exception_thread == thread_iterator->port) { | |
| 84 thread = &*thread_iterator; | |
| 85 break; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 if (!thread) { | |
| 90 LOG(WARNING) << "exception_thread not found in task"; | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 thread_id_ = thread->id; | |
| 95 | |
| 96 // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS | |
| 97 // exceptions, but not for other types of exceptions. | |
| 98 bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; | |
| 99 | |
| 100 #if defined(ARCH_CPU_X86_FAMILY) | |
| 101 if (process_reader->Is64Bit()) { | |
| 102 context_.architecture = kCPUArchitectureX86_64; | |
| 103 context_.x86_64 = &context_union_.x86_64; | |
| 104 InitializeCPUContextX86_64(context_.x86_64, | |
| 105 flavor, | |
| 106 state, | |
| 107 state_count, | |
| 108 &thread->thread_context.t64, | |
| 109 &thread->float_context.f64, | |
| 110 &thread->debug_context.d64); | |
| 111 } else { | |
| 112 context_.architecture = kCPUArchitectureX86; | |
| 113 context_.x86 = &context_union_.x86; | |
| 114 InitializeCPUContextX86(context_.x86, | |
| 115 flavor, | |
| 116 state, | |
| 117 state_count, | |
| 118 &thread->thread_context.t32, | |
| 119 &thread->float_context.f32, | |
| 120 &thread->debug_context.d32); | |
| 121 } | |
| 122 | |
| 123 // For x86 and x86_64 EXC_BAD_ACCESS exceptions, some code[0] values indicate | |
| 124 // that code[1] does not (or may not) carry the exception address: | |
| 125 // EXC_I386_GPFLT (10.9.5 xnu-2422.115.4/osfmk/i386/trap.c user_trap() for | |
| 126 // T_GENERAL_PROTECTION) and the oddball (VM_PROT_READ | VM_PROT_EXECUTE) | |
| 127 // which collides with EXC_I386_BOUNDFLT (10.9.5 | |
| 128 // xnu-2422.115.4/osfmk/i386/fpu.c fpextovrflt()). Other EXC_BAD_ACCESS | |
| 129 // exceptions come through 10.9.5 xnu-2422.115.4/osfmk/i386/trap.c | |
| 130 // user_page_fault_continue() and do contain the exception address in code[1]. | |
| 131 if (exception_ == EXC_BAD_ACCESS && | |
| 132 (exception_code_0_ == EXC_I386_GPFLT || | |
| 133 exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) { | |
| 134 code_1_is_exception_address = false; | |
| 135 } | |
| 136 #endif | |
| 137 | |
| 138 if (code_1_is_exception_address) { | |
| 139 exception_address_ = code[1]; | |
| 140 } else { | |
| 141 exception_address_ = context_.InstructionPointer(); | |
| 142 } | |
| 143 | |
| 144 INITIALIZATION_STATE_SET_VALID(initialized_); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 const CPUContext* ExceptionSnapshotMac::Context() const { | |
| 149 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 150 return &context_; | |
| 151 } | |
| 152 | |
| 153 uint64_t ExceptionSnapshotMac::ThreadID() const { | |
| 154 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 155 return thread_id_; | |
| 156 } | |
| 157 | |
| 158 uint32_t ExceptionSnapshotMac::Exception() const { | |
| 159 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 160 return exception_; | |
| 161 } | |
| 162 | |
| 163 uint32_t ExceptionSnapshotMac::ExceptionInfo() const { | |
| 164 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 165 return exception_code_0_; | |
| 166 } | |
| 167 | |
| 168 uint64_t ExceptionSnapshotMac::ExceptionAddress() const { | |
| 169 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 170 return exception_address_; | |
| 171 } | |
| 172 | |
| 173 const std::vector<uint64_t>& ExceptionSnapshotMac::Codes() const { | |
| 174 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | |
| 175 return codes_; | |
| 176 } | |
| 177 | |
| 178 } // namespace internal | |
| 179 } // namespace crashpad | |
| OLD | NEW |