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 |