Chromium Code Reviews| Index: snapshot/exception_snapshot_mac.cc |
| diff --git a/snapshot/exception_snapshot_mac.cc b/snapshot/exception_snapshot_mac.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..df2fd1a169c7e33cc0bc0546590d678ebe919459 |
| --- /dev/null |
| +++ b/snapshot/exception_snapshot_mac.cc |
| @@ -0,0 +1,179 @@ |
| +// 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 "snapshot/exception_snapshot_mac.h" |
| + |
| +#include "base/logging.h" |
| +#include "snapshot/cpu_context_mac.h" |
| +#include "util/mac/process_reader.h" |
| + |
| +namespace crashpad { |
| +namespace internal { |
| + |
| +ExceptionSnapshotMac::ExceptionSnapshotMac() |
| + : ExceptionSnapshot(), |
| + context_union_(), |
| + context_(), |
| + codes_(), |
| + thread_id_(0), |
| + exception_address_(0), |
| + exception_(0), |
| + exception_code_0_(0), |
| + initialized_() { |
| +} |
| + |
| +ExceptionSnapshotMac::~ExceptionSnapshotMac() { |
| +} |
| + |
| +bool ExceptionSnapshotMac::Initialize(ProcessReader* process_reader, |
| + thread_t exception_thread, |
| + exception_type_t exception, |
| + const mach_exception_data_type_t* code, |
| + mach_msg_type_number_t code_count, |
| + thread_state_flavor_t flavor, |
| + const natural_t* state, |
| + mach_msg_type_number_t state_count) { |
| + INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| + |
| + codes_.push_back(exception); |
| + for (mach_msg_type_number_t code_index = 0; |
| + code_index < code_count; |
| + ++code_index) { |
| + codes_.push_back(code[code_index]); |
| + } |
| + |
| + exception_ = exception; |
| + exception_code_0_ = code[0]; |
| + |
| + if (exception == EXC_CRASH) { |
| + // Recover the original exception and the original code[0] from code[0]. See |
| + // 10.9.5 xnu-2422.115.4/bsd/kern/kern_exit.c proc_prepareexit(). |
| + // |
| + // This is only done if the EXC_CRASH exception originated from a previous |
| + // exception. This is not the case for certain software-triggered |
| + // terminations, such as exiting on a signal that causes termination. This |
| + // happens by default for SIGABRT, for example, so abort() calls will |
| + // ordinarily lead to EXC_CRASH showing up in Exception(). |
| + // |
| + // Note: the signal number is stored at (code[0] >> 24) & 0xff. |
| + exception_type_t original_exception = (code[0] >> 20) & 0xf; |
|
Robert Sesek
2014/10/13 21:04:54
This is ExcCrashRecoverOriginalException() right?
|
| + if (original_exception > 0) { |
| + exception_ = original_exception; |
| + exception_code_0_ = code[0] & 0xfffff; |
| + } |
| + } |
| + |
| + const std::vector<ProcessReader::Thread>& threads = process_reader->Threads(); |
| + const ProcessReader::Thread* thread = NULL; |
| + for (std::vector<ProcessReader::Thread>::const_iterator thread_iterator = |
|
Robert Sesek
2014/10/13 21:04:54
C++11 loop ?
|
| + threads.begin(); |
| + thread_iterator != threads.end(); |
| + ++thread_iterator) { |
| + if (exception_thread == thread_iterator->port) { |
| + thread = &*thread_iterator; |
| + break; |
| + } |
| + } |
| + |
| + if (!thread) { |
| + LOG(WARNING) << "exception_thread not found in task"; |
| + return false; |
| + } |
| + |
| + thread_id_ = thread->id; |
| + |
| + // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS |
| + // exceptions, but not for other types of exceptions. |
| + bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; |
| + |
| +#if defined(ARCH_CPU_X86_FAMILY) |
| + if (process_reader->Is64Bit()) { |
| + context_.architecture = kCPUArchitectureX86_64; |
| + context_.x86_64 = &context_union_.x86_64; |
| + InitializeCPUContextX86_64(context_.x86_64, |
| + flavor, |
| + state, |
| + state_count, |
| + &thread->thread_context.t64, |
| + &thread->float_context.f64, |
| + &thread->debug_context.d64); |
| + } else { |
| + context_.architecture = kCPUArchitectureX86; |
| + context_.x86 = &context_union_.x86; |
| + InitializeCPUContextX86(context_.x86, |
| + flavor, |
| + state, |
| + state_count, |
| + &thread->thread_context.t32, |
| + &thread->float_context.f32, |
| + &thread->debug_context.d32); |
| + } |
| + |
| + // For x86 and x86_64 EXC_BAD_ACCESS exceptions, some code[0] values indicate |
| + // that code[1] does not (or may not) carry the exception address: |
| + // EXC_I386_GPFLT (10.9.5 xnu-2422.115.4/osfmk/i386/trap.c user_trap() for |
| + // T_GENERAL_PROTECTION) and the oddball (VM_PROT_READ | VM_PROT_EXECUTE) |
| + // which collides with EXC_I386_BOUNDFLT (10.9.5 |
| + // xnu-2422.115.4/osfmk/i386/fpu.c fpextovrflt()). Other EXC_BAD_ACCESS |
| + // exceptions come through 10.9.5 xnu-2422.115.4/osfmk/i386/trap.c |
| + // user_page_fault_continue() and do contain the exception address in code[1]. |
| + if (exception_ == EXC_BAD_ACCESS && |
| + (exception_code_0_ == EXC_I386_GPFLT || |
| + exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) { |
| + code_1_is_exception_address = false; |
| + } |
| +#endif |
| + |
| + if (code_1_is_exception_address) { |
| + exception_address_ = code[1]; |
| + } else { |
| + exception_address_ = context_.InstructionPointer(); |
| + } |
| + |
| + INITIALIZATION_STATE_SET_VALID(initialized_); |
| + return true; |
| +} |
| + |
| +const CPUContext* ExceptionSnapshotMac::Context() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return &context_; |
| +} |
| + |
| +uint64_t ExceptionSnapshotMac::ThreadID() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return thread_id_; |
| +} |
| + |
| +uint32_t ExceptionSnapshotMac::Exception() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_; |
| +} |
| + |
| +uint32_t ExceptionSnapshotMac::ExceptionInfo() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_code_0_; |
| +} |
| + |
| +uint64_t ExceptionSnapshotMac::ExceptionAddress() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return exception_address_; |
| +} |
| + |
| +const std::vector<uint64_t>& ExceptionSnapshotMac::Codes() const { |
| + INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| + return codes_; |
| +} |
| + |
| +} // namespace internal |
| +} // namespace crashpad |