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/cpu_context_mac.h" | |
16 | |
17 #include <string.h> | |
18 | |
19 #include "base/logging.h" | |
20 | |
21 namespace crashpad { | |
22 | |
23 #if defined(ARCH_CPU_X86_FAMILY) | |
24 | |
25 namespace { | |
26 | |
27 void InitializeCPUContextX86Thread( | |
28 CPUContextX86* context, | |
29 const x86_thread_state32_t* x86_thread_state32) { | |
30 context->eax = x86_thread_state32->__eax; | |
31 context->ebx = x86_thread_state32->__ebx; | |
32 context->ecx = x86_thread_state32->__ecx; | |
33 context->edx = x86_thread_state32->__edx; | |
34 context->edi = x86_thread_state32->__edi; | |
35 context->esi = x86_thread_state32->__esi; | |
36 context->ebp = x86_thread_state32->__ebp; | |
37 context->esp = x86_thread_state32->__esp; | |
38 context->eip = x86_thread_state32->__eip; | |
39 context->eflags = x86_thread_state32->__eflags; | |
40 context->cs = x86_thread_state32->__cs; | |
41 context->ds = x86_thread_state32->__ds; | |
42 context->es = x86_thread_state32->__es; | |
43 context->fs = x86_thread_state32->__fs; | |
44 context->gs = x86_thread_state32->__gs; | |
45 context->ss = x86_thread_state32->__ss; | |
46 } | |
47 | |
48 void InitializeCPUContextX86Float( | |
49 CPUContextX86* context, const x86_float_state32_t* x86_float_state32) { | |
50 // This relies on both x86_float_state32_t and context->fxsave having | |
51 // identical (fxsave) layout. | |
52 static_assert(offsetof(x86_float_state32_t, __fpu_reserved1) - | |
53 offsetof(x86_float_state32_t, __fpu_fcw) == | |
54 sizeof(context->fxsave), | |
55 "types must be equivalent"); | |
56 | |
57 memcpy( | |
58 &context->fxsave, &x86_float_state32->__fpu_fcw, sizeof(context->fxsave)); | |
59 } | |
60 | |
61 void InitializeCPUContextX86Debug( | |
62 CPUContextX86* context, const x86_debug_state32_t* x86_debug_state32) { | |
63 context->dr0 = x86_debug_state32->__dr0; | |
64 context->dr1 = x86_debug_state32->__dr1; | |
65 context->dr2 = x86_debug_state32->__dr2; | |
66 context->dr3 = x86_debug_state32->__dr3; | |
67 context->dr4 = x86_debug_state32->__dr4; | |
68 context->dr5 = x86_debug_state32->__dr5; | |
69 context->dr6 = x86_debug_state32->__dr6; | |
70 context->dr7 = x86_debug_state32->__dr7; | |
71 } | |
72 | |
73 // Initializes |context| from the native thread state structure |state|, which | |
74 // is interpreted according to |flavor|. |state_count| must be at least the | |
75 // expected size for |flavor|. This handles the architecture-specific | |
76 // x86_THREAD_STATE32, x86_FLOAT_STATE32, and x86_DEBUG_STATE32 flavors. It also | |
77 // handles the universal x86_THREAD_STATE, x86_FLOAT_STATE, and x86_DEBUG_STATE | |
78 // flavors provided that the associated structure carries 32-bit data of the | |
79 // corresponding state type. |flavor| may be THREAD_STATE_NONE to avoid setting | |
80 // any thread state in |context|. This returns the architecture-specific flavor | |
81 // value for the thread state that was actually set, or THREAD_STATE_NONE if no | |
82 // thread state was set. | |
83 thread_state_flavor_t InitializeCPUContextX86Flavor( | |
84 CPUContextX86* context, | |
85 thread_state_flavor_t flavor, | |
86 const natural_t* state, | |
87 mach_msg_type_number_t state_count) { | |
88 mach_msg_type_number_t expected_state_count; | |
89 switch (flavor) { | |
90 case x86_THREAD_STATE: | |
91 expected_state_count = x86_THREAD_STATE_COUNT; | |
92 break; | |
93 case x86_FLOAT_STATE: | |
94 expected_state_count = x86_FLOAT_STATE_COUNT; | |
95 break; | |
96 case x86_DEBUG_STATE: | |
97 expected_state_count = x86_DEBUG_STATE_COUNT; | |
98 break; | |
99 case x86_THREAD_STATE32: | |
100 expected_state_count = x86_THREAD_STATE32_COUNT; | |
101 break; | |
102 case x86_FLOAT_STATE32: | |
103 expected_state_count = x86_FLOAT_STATE32_COUNT; | |
104 break; | |
105 case x86_DEBUG_STATE32: | |
106 expected_state_count = x86_DEBUG_STATE32_COUNT; | |
107 break; | |
108 case THREAD_STATE_NONE: | |
109 expected_state_count = 0; | |
110 break; | |
111 default: | |
112 LOG(WARNING) << "unhandled flavor " << flavor; | |
113 return THREAD_STATE_NONE; | |
114 } | |
115 | |
116 if (state_count < expected_state_count) { | |
117 LOG(WARNING) << "expected state_count " << expected_state_count | |
118 << " for flavor " << flavor << ", observed " << state_count; | |
119 return THREAD_STATE_NONE; | |
120 } | |
121 | |
122 switch (flavor) { | |
123 case x86_THREAD_STATE: { | |
124 const x86_thread_state_t* x86_thread_state = | |
125 reinterpret_cast<const x86_thread_state_t*>(state); | |
126 if (x86_thread_state->tsh.flavor != x86_THREAD_STATE32) { | |
127 LOG(WARNING) << "expected flavor x86_THREAD_STATE32, observed " | |
128 << x86_thread_state->tsh.flavor; | |
129 return THREAD_STATE_NONE; | |
130 } | |
131 return InitializeCPUContextX86Flavor( | |
132 context, | |
133 x86_thread_state->tsh.flavor, | |
134 reinterpret_cast<const natural_t*>(&x86_thread_state->uts.ts32), | |
135 x86_thread_state->tsh.count); | |
136 } | |
137 | |
138 case x86_FLOAT_STATE: { | |
139 const x86_float_state_t* x86_float_state = | |
140 reinterpret_cast<const x86_float_state_t*>(state); | |
141 if (x86_float_state->fsh.flavor != x86_FLOAT_STATE32) { | |
142 LOG(WARNING) << "expected flavor x86_FLOAT_STATE32, observed " | |
143 << x86_float_state->fsh.flavor; | |
144 return THREAD_STATE_NONE; | |
145 } | |
146 return InitializeCPUContextX86Flavor( | |
147 context, | |
148 x86_float_state->fsh.flavor, | |
149 reinterpret_cast<const natural_t*>(&x86_float_state->ufs.fs32), | |
150 x86_float_state->fsh.count); | |
151 } | |
152 | |
153 case x86_DEBUG_STATE: { | |
154 const x86_debug_state_t* x86_debug_state = | |
155 reinterpret_cast<const x86_debug_state_t*>(state); | |
156 if (x86_debug_state->dsh.flavor != x86_DEBUG_STATE32) { | |
157 LOG(WARNING) << "expected flavor x86_DEBUG_STATE32, observed " | |
158 << x86_debug_state->dsh.flavor; | |
159 return THREAD_STATE_NONE; | |
160 } | |
161 return InitializeCPUContextX86Flavor( | |
162 context, | |
163 x86_debug_state->dsh.flavor, | |
164 reinterpret_cast<const natural_t*>(&x86_debug_state->uds.ds32), | |
165 x86_debug_state->dsh.count); | |
166 } | |
167 | |
168 case x86_THREAD_STATE32: { | |
169 const x86_thread_state32_t* x86_thread_state32 = | |
170 reinterpret_cast<const x86_thread_state32_t*>(state); | |
171 InitializeCPUContextX86Thread(context, x86_thread_state32); | |
172 return flavor; | |
173 } | |
174 | |
175 case x86_FLOAT_STATE32: { | |
176 const x86_float_state32_t* x86_float_state32 = | |
177 reinterpret_cast<const x86_float_state32_t*>(state); | |
178 InitializeCPUContextX86Float(context, x86_float_state32); | |
179 return flavor; | |
180 } | |
181 | |
182 case x86_DEBUG_STATE32: { | |
183 const x86_debug_state32_t* x86_debug_state32 = | |
184 reinterpret_cast<const x86_debug_state32_t*>(state); | |
185 InitializeCPUContextX86Debug(context, x86_debug_state32); | |
186 return flavor; | |
187 } | |
188 | |
189 case THREAD_STATE_NONE: { | |
190 // This may happen without error when called without exception-style | |
191 // flavor data, or even from an exception handler when the exception | |
192 // behavior is EXCEPTION_DEFAULT. | |
193 return flavor; | |
194 } | |
195 | |
196 default: { | |
197 NOTREACHED(); | |
198 return THREAD_STATE_NONE; | |
199 } | |
200 } | |
201 } | |
202 | |
203 void InitializeCPUContextX86_64Thread( | |
204 CPUContextX86_64* context, const x86_thread_state64_t* x86_thread_state64) { | |
205 context->rax = x86_thread_state64->__rax; | |
206 context->rbx = x86_thread_state64->__rbx; | |
207 context->rcx = x86_thread_state64->__rcx; | |
208 context->rdx = x86_thread_state64->__rdx; | |
209 context->rdi = x86_thread_state64->__rdi; | |
210 context->rsi = x86_thread_state64->__rsi; | |
211 context->rbp = x86_thread_state64->__rbp; | |
212 context->rsp = x86_thread_state64->__rsp; | |
213 context->r8 = x86_thread_state64->__r8; | |
214 context->r9 = x86_thread_state64->__r9; | |
215 context->r10 = x86_thread_state64->__r10; | |
216 context->r11 = x86_thread_state64->__r11; | |
217 context->r12 = x86_thread_state64->__r12; | |
218 context->r13 = x86_thread_state64->__r13; | |
219 context->r14 = x86_thread_state64->__r14; | |
220 context->r15 = x86_thread_state64->__r15; | |
221 context->rip = x86_thread_state64->__rip; | |
222 context->rflags = x86_thread_state64->__rflags; | |
223 context->cs = x86_thread_state64->__cs; | |
224 context->fs = x86_thread_state64->__fs; | |
225 context->gs = x86_thread_state64->__gs; | |
226 } | |
227 | |
228 void InitializeCPUContextX86_64Float( | |
229 CPUContextX86_64* context, const x86_float_state64_t* x86_float_state64) { | |
230 // This relies on both x86_float_state64_t and context->fxsave having | |
231 // identical (fxsave) layout. | |
232 static_assert(offsetof(x86_float_state64_t, __fpu_reserved1) - | |
233 offsetof(x86_float_state64_t, __fpu_fcw) == | |
234 sizeof(context->fxsave), | |
235 "types must be equivalent"); | |
236 | |
237 memcpy(&context->fxsave, | |
238 &x86_float_state64->__fpu_fcw, | |
239 sizeof(context->fxsave)); | |
240 } | |
241 | |
242 void InitializeCPUContextX86_64Debug( | |
243 CPUContextX86_64* context, const x86_debug_state64_t* x86_debug_state64) { | |
244 context->dr0 = x86_debug_state64->__dr0; | |
245 context->dr1 = x86_debug_state64->__dr1; | |
246 context->dr2 = x86_debug_state64->__dr2; | |
247 context->dr3 = x86_debug_state64->__dr3; | |
248 context->dr4 = x86_debug_state64->__dr4; | |
249 context->dr5 = x86_debug_state64->__dr5; | |
250 context->dr6 = x86_debug_state64->__dr6; | |
251 context->dr7 = x86_debug_state64->__dr7; | |
252 } | |
253 | |
254 // Initializes |context| from the native thread state structure |state|, which | |
255 // is interpreted according to |flavor|. |state_count| must be at least the | |
256 // expected size for |flavor|. This handles the architecture-specific | |
257 // x86_THREAD_STATE64, x86_FLOAT_STATE64, and x86_DEBUG_STATE64 flavors. It also | |
258 // handles the universal x86_THREAD_STATE, x86_FLOAT_STATE, and x86_DEBUG_STATE | |
259 // flavors provided that the associated structure carries 64-bit data of the | |
260 // corresponding state type. |flavor| may be THREAD_STATE_NONE to avoid setting | |
261 // any thread state in |context|. This returns the architecture-specific flavor | |
262 // value for the thread state that was actually set, or THREAD_STATE_NONE if no | |
263 // thread state was set. | |
264 thread_state_flavor_t InitializeCPUContextX86_64Flavor( | |
265 CPUContextX86_64* context, | |
266 thread_state_flavor_t flavor, | |
267 const natural_t* state, | |
268 mach_msg_type_number_t state_count) { | |
269 mach_msg_type_number_t expected_state_count; | |
270 switch (flavor) { | |
271 case x86_THREAD_STATE: | |
272 expected_state_count = x86_THREAD_STATE_COUNT; | |
273 break; | |
274 case x86_FLOAT_STATE: | |
275 expected_state_count = x86_FLOAT_STATE_COUNT; | |
276 break; | |
277 case x86_DEBUG_STATE: | |
278 expected_state_count = x86_DEBUG_STATE_COUNT; | |
279 break; | |
280 case x86_THREAD_STATE64: | |
281 expected_state_count = x86_THREAD_STATE64_COUNT; | |
282 break; | |
283 case x86_FLOAT_STATE64: | |
284 expected_state_count = x86_FLOAT_STATE64_COUNT; | |
285 break; | |
286 case x86_DEBUG_STATE64: | |
287 expected_state_count = x86_DEBUG_STATE64_COUNT; | |
288 break; | |
289 case THREAD_STATE_NONE: | |
290 expected_state_count = 0; | |
291 break; | |
292 default: | |
293 LOG(WARNING) << "unhandled flavor " << flavor; | |
294 return THREAD_STATE_NONE; | |
295 } | |
296 | |
297 if (state_count < expected_state_count) { | |
298 LOG(WARNING) << "expected state_count " << expected_state_count | |
299 << " for flavor " << flavor << ", observed " << state_count; | |
300 return THREAD_STATE_NONE; | |
301 } | |
302 | |
303 switch (flavor) { | |
304 case x86_THREAD_STATE: { | |
305 const x86_thread_state_t* x86_thread_state = | |
306 reinterpret_cast<const x86_thread_state_t*>(state); | |
307 if (x86_thread_state->tsh.flavor != x86_THREAD_STATE64) { | |
308 LOG(WARNING) << "expected flavor x86_THREAD_STATE64, observed " | |
309 << x86_thread_state->tsh.flavor; | |
310 return THREAD_STATE_NONE; | |
311 } | |
312 return InitializeCPUContextX86_64Flavor( | |
313 context, | |
314 x86_thread_state->tsh.flavor, | |
315 reinterpret_cast<const natural_t*>(&x86_thread_state->uts.ts64), | |
316 x86_thread_state->tsh.count); | |
317 } | |
318 | |
319 case x86_FLOAT_STATE: { | |
320 const x86_float_state_t* x86_float_state = | |
321 reinterpret_cast<const x86_float_state_t*>(state); | |
322 if (x86_float_state->fsh.flavor != x86_FLOAT_STATE64) { | |
323 LOG(WARNING) << "expected flavor x86_FLOAT_STATE64, observed " | |
324 << x86_float_state->fsh.flavor; | |
325 return THREAD_STATE_NONE; | |
326 } | |
327 return InitializeCPUContextX86_64Flavor( | |
328 context, | |
329 x86_float_state->fsh.flavor, | |
330 reinterpret_cast<const natural_t*>(&x86_float_state->ufs.fs64), | |
331 x86_float_state->fsh.count); | |
332 } | |
333 | |
334 case x86_DEBUG_STATE: { | |
335 const x86_debug_state_t* x86_debug_state = | |
336 reinterpret_cast<const x86_debug_state_t*>(state); | |
337 if (x86_debug_state->dsh.flavor != x86_DEBUG_STATE64) { | |
338 LOG(WARNING) << "expected flavor x86_DEBUG_STATE64, observed " | |
339 << x86_debug_state->dsh.flavor; | |
340 return THREAD_STATE_NONE; | |
341 } | |
342 return InitializeCPUContextX86_64Flavor( | |
343 context, | |
344 x86_debug_state->dsh.flavor, | |
345 reinterpret_cast<const natural_t*>(&x86_debug_state->uds.ds64), | |
346 x86_debug_state->dsh.count); | |
347 } | |
348 | |
349 case x86_THREAD_STATE64: { | |
350 const x86_thread_state64_t* x86_thread_state64 = | |
351 reinterpret_cast<const x86_thread_state64_t*>(state); | |
352 InitializeCPUContextX86_64Thread(context, x86_thread_state64); | |
353 return flavor; | |
354 } | |
355 | |
356 case x86_FLOAT_STATE64: { | |
357 const x86_float_state64_t* x86_float_state64 = | |
358 reinterpret_cast<const x86_float_state64_t*>(state); | |
359 InitializeCPUContextX86_64Float(context, x86_float_state64); | |
360 return flavor; | |
361 } | |
362 | |
363 case x86_DEBUG_STATE64: { | |
364 const x86_debug_state64_t* x86_debug_state64 = | |
365 reinterpret_cast<const x86_debug_state64_t*>(state); | |
366 InitializeCPUContextX86_64Debug(context, x86_debug_state64); | |
367 return flavor; | |
368 } | |
369 | |
370 case THREAD_STATE_NONE: { | |
371 // This may happen without error when called without exception-style | |
372 // flavor data, or even from an exception handler when the exception | |
373 // behavior is EXCEPTION_DEFAULT. | |
374 return flavor; | |
375 } | |
376 | |
377 default: { | |
378 NOTREACHED(); | |
379 return THREAD_STATE_NONE; | |
380 } | |
381 } | |
382 } | |
383 | |
384 } // namespace | |
385 | |
386 namespace internal { | |
387 | |
388 void InitializeCPUContextX86(CPUContextX86* context, | |
389 thread_state_flavor_t flavor, | |
390 const natural_t* state, | |
391 mach_msg_type_number_t state_count, | |
392 const x86_thread_state32_t* x86_thread_state32, | |
393 const x86_float_state32_t* x86_float_state32, | |
394 const x86_debug_state32_t* x86_debug_state32) { | |
395 thread_state_flavor_t set_flavor = THREAD_STATE_NONE; | |
396 if (flavor != THREAD_STATE_NONE) { | |
397 set_flavor = | |
398 InitializeCPUContextX86Flavor(context, flavor, state, state_count); | |
399 } | |
400 | |
401 if (set_flavor != x86_THREAD_STATE32) { | |
402 InitializeCPUContextX86Thread(context, x86_thread_state32); | |
403 } | |
404 if (set_flavor != x86_FLOAT_STATE32) { | |
405 InitializeCPUContextX86Float(context, x86_float_state32); | |
406 } | |
407 if (set_flavor != x86_DEBUG_STATE32) { | |
408 InitializeCPUContextX86Debug(context, x86_debug_state32); | |
409 } | |
410 } | |
411 | |
412 void InitializeCPUContextX86_64(CPUContextX86_64* context, | |
413 thread_state_flavor_t flavor, | |
414 const natural_t* state, | |
415 mach_msg_type_number_t state_count, | |
416 const x86_thread_state64_t* x86_thread_state64, | |
417 const x86_float_state64_t* x86_float_state64, | |
418 const x86_debug_state64_t* x86_debug_state64) { | |
419 thread_state_flavor_t set_flavor = THREAD_STATE_NONE; | |
420 if (flavor != THREAD_STATE_NONE) { | |
421 set_flavor = | |
422 InitializeCPUContextX86_64Flavor(context, flavor, state, state_count); | |
423 } | |
424 | |
425 if (set_flavor != x86_THREAD_STATE64) { | |
426 InitializeCPUContextX86_64Thread(context, x86_thread_state64); | |
427 } | |
428 if (set_flavor != x86_FLOAT_STATE64) { | |
429 InitializeCPUContextX86_64Float(context, x86_float_state64); | |
430 } | |
431 if (set_flavor != x86_DEBUG_STATE64) { | |
432 InitializeCPUContextX86_64Debug(context, x86_debug_state64); | |
433 } | |
434 } | |
435 | |
436 } // namespace internal | |
437 | |
438 #endif | |
439 | |
440 } // namespace crashpad | |
OLD | NEW |