Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Side by Side Diff: snapshot/mac/exception_snapshot_mac.cc

Issue 1050313003: Handle EXC_RESOURCE and EXC_GUARD exceptions properly (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Better logging Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « snapshot/mac/exception_snapshot_mac.h ('k') | snapshot/mac/process_snapshot_mac.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with 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 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "snapshot/mac/exception_snapshot_mac.h" 15 #include "snapshot/mac/exception_snapshot_mac.h"
16 16
17 #include "base/logging.h" 17 #include "base/logging.h"
18 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
19 #include "snapshot/mac/cpu_context_mac.h" 19 #include "snapshot/mac/cpu_context_mac.h"
20 #include "snapshot/mac/process_reader.h" 20 #include "snapshot/mac/process_reader.h"
21 #include "util/mach/exc_server_variants.h" 21 #include "util/mach/exc_server_variants.h"
22 #include "util/mach/exception_behaviors.h"
23 #include "util/mach/symbolic_constants_mach.h"
22 #include "util/numeric/safe_assignment.h" 24 #include "util/numeric/safe_assignment.h"
23 25
24 namespace crashpad { 26 namespace crashpad {
25 namespace internal { 27 namespace internal {
26 28
27 ExceptionSnapshotMac::ExceptionSnapshotMac() 29 ExceptionSnapshotMac::ExceptionSnapshotMac()
28 : ExceptionSnapshot(), 30 : ExceptionSnapshot(),
29 context_union_(), 31 context_union_(),
30 context_(), 32 context_(),
31 codes_(), 33 codes_(),
32 thread_id_(0), 34 thread_id_(0),
33 exception_address_(0), 35 exception_address_(0),
34 exception_(0), 36 exception_(0),
35 exception_code_0_(0), 37 exception_code_0_(0),
36 initialized_() { 38 initialized_() {
37 } 39 }
38 40
39 ExceptionSnapshotMac::~ExceptionSnapshotMac() { 41 ExceptionSnapshotMac::~ExceptionSnapshotMac() {
40 } 42 }
41 43
42 bool ExceptionSnapshotMac::Initialize(ProcessReader* process_reader, 44 bool ExceptionSnapshotMac::Initialize(ProcessReader* process_reader,
45 exception_behavior_t behavior,
43 thread_t exception_thread, 46 thread_t exception_thread,
44 exception_type_t exception, 47 exception_type_t exception,
45 const mach_exception_data_type_t* code, 48 const mach_exception_data_type_t* code,
46 mach_msg_type_number_t code_count, 49 mach_msg_type_number_t code_count,
47 thread_state_flavor_t flavor, 50 thread_state_flavor_t flavor,
48 const natural_t* state, 51 const natural_t* state,
49 mach_msg_type_number_t state_count) { 52 mach_msg_type_number_t state_count) {
50 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); 53 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
51 54
52 codes_.push_back(exception); 55 codes_.push_back(exception);
53 for (mach_msg_type_number_t code_index = 0; 56 for (mach_msg_type_number_t code_index = 0;
54 code_index < code_count; 57 code_index < code_count;
55 ++code_index) { 58 ++code_index) {
56 codes_.push_back(code[code_index]); 59 codes_.push_back(code[code_index]);
57 } 60 }
58 61
59 exception_ = exception; 62 exception_ = exception;
60 mach_exception_code_t exception_code_0 = code[0]; 63 mach_exception_code_t exception_code_0 = code[0];
61 64
62 if (exception_ == EXC_CRASH) { 65 if (exception_ == EXC_CRASH) {
63 exception_ = ExcCrashRecoverOriginalException( 66 exception_ = ExcCrashRecoverOriginalException(
64 exception_code_0, &exception_code_0, nullptr); 67 exception_code_0, &exception_code_0, nullptr);
68
69 if (exception_ == EXC_RESOURCE || exception_ == EXC_GUARD) {
70 // These are software exceptions that are never mapped to EXC_CRASH. The
71 // only time EXC_CRASH is generated is for processes exiting due to an
72 // unhandled core-generating signal or being killed by SIGKILL for
73 // code-signing reasons. Neither of these applies to EXC_RESOURCE or
74 // EXC_GUARD. See 10.10 xnu-2782.1.97/bsd/kern/kern_exit.c
75 // proc_prepareexit().
76 //
77 // Receiving these exception types wrapped in EXC_CRASH would lose
78 // information because their code[0] uses all 64 bits (see below) and the
79 // code[0] recovered from EXC_CRASH only contains 20 significant bits.
80 LOG(WARNING) << base::StringPrintf(
81 "exception %s invalid in EXC_CRASH",
82 ExceptionToString(exception_, kUseFullName | kUnknownIsNumeric)
83 .c_str());
84 }
65 } 85 }
66 86
67 // ExceptionInfo() returns code[0] in a 32-bit field. This shouldn’t be a 87 // The operations that follow put exception_code_0 (a mach_exception_code_t,
68 // problem because code[0]’s values never exceed 32 bits. Only code[1] is ever 88 // a typedef for int64_t) into exception_code_0_ (a uint32_t). The range
69 // expected to be that wide. 89 // checks and bit shifts involved need the same signedness on both sides to
70 if (!AssignIfInRange(&exception_code_0_, exception_code_0)) { 90 // work properly.
71 LOG(WARNING) 91 const uint64_t unsigned_exception_code_0 = exception_code_0;
72 << base::StringPrintf("exception_code_0 0x%llx out of range", 92
73 exception_code_0); 93 // ExceptionInfo() returns code[0] as a 32-bit value, but exception_code_0 is
74 return false; 94 // a 64-bit value. The best treatment for this inconsistency depends on the
95 // exception type.
96 if (exception_ == EXC_RESOURCE || exception_ == EXC_GUARD) {
97 // All 64 bits of code[0] are significant for these exceptions. See
98 // <mach/exc_resource.h> for EXC_RESOURCE and 10.10
99 // xnu-2782.1.97/bsd/kern/kern_guarded.c fd_guard_ast() for EXC_GUARD.
100 // code[0] is structured similarly for these two exceptions.
101 //
102 // EXC_RESOURCE: see <kern/exc_resource.h>. The resource type and “flavor”
103 // together define the resource and are in the highest bits. The resource
104 // limit is in the lowest bits.
105 //
106 // EXC_GUARD: see 10.10 xnu-2782.1.97/osfmk/ipc/mach_port.c
107 // mach_port_guard_exception() and xnu-2782.1.97/bsd/kern/kern_guarded.c
108 // fd_guard_ast(). The guard type (GUARD_TYPE_MACH_PORT or GUARD_TYPE_FD)
109 // and “flavor” (from the mach_port_guard_exception_codes or
110 // guard_exception_codes enums) are in the highest bits. The violating Mach
111 // port name or file descriptor number is in the lowest bits.
112
113 // If MACH_EXCEPTION_CODES is not set in |behavior|, code[0] will only carry
114 // 32 significant bits, and the interesting high bits will have been
115 // truncated.
116 if (!ExceptionBehaviorHasMachExceptionCodes(behavior)) {
117 LOG(WARNING) << base::StringPrintf(
118 "behavior %s invalid for exception %s",
119 ExceptionBehaviorToString(
120 behavior, kUseFullName | kUnknownIsNumeric | kUseOr).c_str(),
121 ExceptionToString(exception_, kUseFullName | kUnknownIsNumeric)
122 .c_str());
123 }
124
125 // Include the more-significant information from the high bits of code[0] in
126 // the value to be returned by ExceptionInfo(). The full value of codes[0]
127 // including the less-significant lower bits is still available via Codes().
128 exception_code_0_ = unsigned_exception_code_0 >> 32;
129 } else {
130 // For other exceptions, code[0]’s values never exceed 32 bits.
131 if (!base::IsValueInRangeForNumericType<decltype(exception_code_0_)>(
132 unsigned_exception_code_0)) {
133 LOG(WARNING) << base::StringPrintf("exception_code_0 0x%llx out of range",
134 unsigned_exception_code_0);
135 }
136 exception_code_0_ = unsigned_exception_code_0;
75 } 137 }
76 138
77 const ProcessReader::Thread* thread = nullptr; 139 const ProcessReader::Thread* thread = nullptr;
78 for (const ProcessReader::Thread& loop_thread : process_reader->Threads()) { 140 for (const ProcessReader::Thread& loop_thread : process_reader->Threads()) {
79 if (exception_thread == loop_thread.port) { 141 if (exception_thread == loop_thread.port) {
80 thread = &loop_thread; 142 thread = &loop_thread;
81 break; 143 break;
82 } 144 }
83 } 145 }
84 146
85 if (!thread) { 147 if (!thread) {
86 LOG(WARNING) << "exception_thread not found in task"; 148 LOG(ERROR) << "exception_thread not found in task";
87 return false; 149 return false;
88 } 150 }
89 151
90 thread_id_ = thread->id; 152 thread_id_ = thread->id;
91 153
92 // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS 154 // Normally, the exception address is present in code[1] for EXC_BAD_ACCESS
93 // exceptions, but not for other types of exceptions. 155 // exceptions, but not for other types of exceptions.
94 bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS; 156 bool code_1_is_exception_address = exception_ == EXC_BAD_ACCESS;
95 157
96 #if defined(ARCH_CPU_X86_FAMILY) 158 #if defined(ARCH_CPU_X86_FAMILY)
(...skipping 28 matching lines...) Expand all
125 // exceptions come through 10.9.5 xnu-2422.115.4/osfmk/i386/trap.c 187 // 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]. 188 // user_page_fault_continue() and do contain the exception address in code[1].
127 if (exception_ == EXC_BAD_ACCESS && 189 if (exception_ == EXC_BAD_ACCESS &&
128 (exception_code_0_ == EXC_I386_GPFLT || 190 (exception_code_0_ == EXC_I386_GPFLT ||
129 exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) { 191 exception_code_0_ == (VM_PROT_READ | VM_PROT_EXECUTE))) {
130 code_1_is_exception_address = false; 192 code_1_is_exception_address = false;
131 } 193 }
132 #endif 194 #endif
133 195
134 if (code_1_is_exception_address) { 196 if (code_1_is_exception_address) {
197 if (process_reader->Is64Bit() &&
198 !ExceptionBehaviorHasMachExceptionCodes(behavior)) {
199 // If code[1] is an address from a 64-bit process, the exception must have
200 // been received with MACH_EXCEPTION_CODES or the address will have been
201 // truncated.
202 LOG(WARNING) << base::StringPrintf(
203 "behavior %s invalid for exception %s code %d in 64-bit process",
204 ExceptionBehaviorToString(
205 behavior, kUseFullName | kUnknownIsNumeric | kUseOr).c_str(),
206 ExceptionToString(exception_, kUseFullName | kUnknownIsNumeric)
207 .c_str(),
208 exception_code_0_);
209 }
135 exception_address_ = code[1]; 210 exception_address_ = code[1];
136 } else { 211 } else {
137 exception_address_ = context_.InstructionPointer(); 212 exception_address_ = context_.InstructionPointer();
138 } 213 }
139 214
140 INITIALIZATION_STATE_SET_VALID(initialized_); 215 INITIALIZATION_STATE_SET_VALID(initialized_);
141 return true; 216 return true;
142 } 217 }
143 218
144 const CPUContext* ExceptionSnapshotMac::Context() const { 219 const CPUContext* ExceptionSnapshotMac::Context() const {
(...skipping 21 matching lines...) Expand all
166 return exception_address_; 241 return exception_address_;
167 } 242 }
168 243
169 const std::vector<uint64_t>& ExceptionSnapshotMac::Codes() const { 244 const std::vector<uint64_t>& ExceptionSnapshotMac::Codes() const {
170 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 245 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
171 return codes_; 246 return codes_;
172 } 247 }
173 248
174 } // namespace internal 249 } // namespace internal
175 } // namespace crashpad 250 } // namespace crashpad
OLDNEW
« no previous file with comments | « snapshot/mac/exception_snapshot_mac.h ('k') | snapshot/mac/process_snapshot_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698