| 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 |