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, nullptr); | |
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 = nullptr; | |
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 |