mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add snapshot/cpu_context_mac*, including InitializeCPUContextX86() and
InitializeCPUContextX86_64(), and their tests. TEST=snapshot_test CPUContextMac.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/630513003
This commit is contained in:
parent
56503fef86
commit
49c03db129
440
snapshot/cpu_context_mac.cc
Normal file
440
snapshot/cpu_context_mac.cc
Normal file
@ -0,0 +1,440 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "snapshot/cpu_context_mac.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
|
||||
namespace {
|
||||
|
||||
void InitializeCPUContextX86Thread(
|
||||
CPUContextX86* context,
|
||||
const x86_thread_state32_t* x86_thread_state32) {
|
||||
context->eax = x86_thread_state32->__eax;
|
||||
context->ebx = x86_thread_state32->__ebx;
|
||||
context->ecx = x86_thread_state32->__ecx;
|
||||
context->edx = x86_thread_state32->__edx;
|
||||
context->edi = x86_thread_state32->__edi;
|
||||
context->esi = x86_thread_state32->__esi;
|
||||
context->ebp = x86_thread_state32->__ebp;
|
||||
context->esp = x86_thread_state32->__esp;
|
||||
context->eip = x86_thread_state32->__eip;
|
||||
context->eflags = x86_thread_state32->__eflags;
|
||||
context->cs = x86_thread_state32->__cs;
|
||||
context->ds = x86_thread_state32->__ds;
|
||||
context->es = x86_thread_state32->__es;
|
||||
context->fs = x86_thread_state32->__fs;
|
||||
context->gs = x86_thread_state32->__gs;
|
||||
context->ss = x86_thread_state32->__ss;
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86Float(
|
||||
CPUContextX86* context, const x86_float_state32_t* x86_float_state32) {
|
||||
// This relies on both x86_float_state32_t and context->fxsave having
|
||||
// identical (fxsave) layout.
|
||||
static_assert(offsetof(x86_float_state32_t, __fpu_reserved1) -
|
||||
offsetof(x86_float_state32_t, __fpu_fcw) ==
|
||||
sizeof(context->fxsave),
|
||||
"types must be equivalent");
|
||||
|
||||
memcpy(
|
||||
&context->fxsave, &x86_float_state32->__fpu_fcw, sizeof(context->fxsave));
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86Debug(
|
||||
CPUContextX86* context, const x86_debug_state32_t* x86_debug_state32) {
|
||||
context->dr0 = x86_debug_state32->__dr0;
|
||||
context->dr1 = x86_debug_state32->__dr1;
|
||||
context->dr2 = x86_debug_state32->__dr2;
|
||||
context->dr3 = x86_debug_state32->__dr3;
|
||||
context->dr4 = x86_debug_state32->__dr4;
|
||||
context->dr5 = x86_debug_state32->__dr5;
|
||||
context->dr6 = x86_debug_state32->__dr6;
|
||||
context->dr7 = x86_debug_state32->__dr7;
|
||||
}
|
||||
|
||||
// Initializes |context| from the native thread state structure |state|, which
|
||||
// is interpreted according to |flavor|. |state_count| must be at least the
|
||||
// expected size for |flavor|. This handles the architecture-specific
|
||||
// x86_THREAD_STATE32, x86_FLOAT_STATE32, and x86_DEBUG_STATE32 flavors. It also
|
||||
// handles the universal x86_THREAD_STATE, x86_FLOAT_STATE, and x86_DEBUG_STATE
|
||||
// flavors provided that the associated structure carries 32-bit data of the
|
||||
// corresponding state type. |flavor| may be THREAD_STATE_NONE to avoid setting
|
||||
// any thread state in |context|. This returns the architecture-specific flavor
|
||||
// value for the thread state that was actually set, or THREAD_STATE_NONE if no
|
||||
// thread state was set.
|
||||
thread_state_flavor_t InitializeCPUContextX86Flavor(
|
||||
CPUContextX86* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count) {
|
||||
mach_msg_type_number_t expected_state_count;
|
||||
switch (flavor) {
|
||||
case x86_THREAD_STATE:
|
||||
expected_state_count = x86_THREAD_STATE_COUNT;
|
||||
break;
|
||||
case x86_FLOAT_STATE:
|
||||
expected_state_count = x86_FLOAT_STATE_COUNT;
|
||||
break;
|
||||
case x86_DEBUG_STATE:
|
||||
expected_state_count = x86_DEBUG_STATE_COUNT;
|
||||
break;
|
||||
case x86_THREAD_STATE32:
|
||||
expected_state_count = x86_THREAD_STATE32_COUNT;
|
||||
break;
|
||||
case x86_FLOAT_STATE32:
|
||||
expected_state_count = x86_FLOAT_STATE32_COUNT;
|
||||
break;
|
||||
case x86_DEBUG_STATE32:
|
||||
expected_state_count = x86_DEBUG_STATE32_COUNT;
|
||||
break;
|
||||
case THREAD_STATE_NONE:
|
||||
expected_state_count = 0;
|
||||
break;
|
||||
default:
|
||||
LOG(WARNING) << "unhandled flavor " << flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
|
||||
if (state_count < expected_state_count) {
|
||||
LOG(WARNING) << "expected state_count " << expected_state_count
|
||||
<< " for flavor " << flavor << ", observed " << state_count;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
|
||||
switch (flavor) {
|
||||
case x86_THREAD_STATE: {
|
||||
const x86_thread_state_t* x86_thread_state =
|
||||
reinterpret_cast<const x86_thread_state_t*>(state);
|
||||
if (x86_thread_state->tsh.flavor != x86_THREAD_STATE32) {
|
||||
LOG(WARNING) << "expected flavor x86_THREAD_STATE32, observed "
|
||||
<< x86_thread_state->tsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86Flavor(
|
||||
context,
|
||||
x86_thread_state->tsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_thread_state->uts.ts32),
|
||||
x86_thread_state->tsh.count);
|
||||
}
|
||||
|
||||
case x86_FLOAT_STATE: {
|
||||
const x86_float_state_t* x86_float_state =
|
||||
reinterpret_cast<const x86_float_state_t*>(state);
|
||||
if (x86_float_state->fsh.flavor != x86_FLOAT_STATE32) {
|
||||
LOG(WARNING) << "expected flavor x86_FLOAT_STATE32, observed "
|
||||
<< x86_float_state->fsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86Flavor(
|
||||
context,
|
||||
x86_float_state->fsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_float_state->ufs.fs32),
|
||||
x86_float_state->fsh.count);
|
||||
}
|
||||
|
||||
case x86_DEBUG_STATE: {
|
||||
const x86_debug_state_t* x86_debug_state =
|
||||
reinterpret_cast<const x86_debug_state_t*>(state);
|
||||
if (x86_debug_state->dsh.flavor != x86_DEBUG_STATE32) {
|
||||
LOG(WARNING) << "expected flavor x86_DEBUG_STATE32, observed "
|
||||
<< x86_debug_state->dsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86Flavor(
|
||||
context,
|
||||
x86_debug_state->dsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_debug_state->uds.ds32),
|
||||
x86_debug_state->dsh.count);
|
||||
}
|
||||
|
||||
case x86_THREAD_STATE32: {
|
||||
const x86_thread_state32_t* x86_thread_state32 =
|
||||
reinterpret_cast<const x86_thread_state32_t*>(state);
|
||||
InitializeCPUContextX86Thread(context, x86_thread_state32);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case x86_FLOAT_STATE32: {
|
||||
const x86_float_state32_t* x86_float_state32 =
|
||||
reinterpret_cast<const x86_float_state32_t*>(state);
|
||||
InitializeCPUContextX86Float(context, x86_float_state32);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case x86_DEBUG_STATE32: {
|
||||
const x86_debug_state32_t* x86_debug_state32 =
|
||||
reinterpret_cast<const x86_debug_state32_t*>(state);
|
||||
InitializeCPUContextX86Debug(context, x86_debug_state32);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case THREAD_STATE_NONE: {
|
||||
// This may happen without error when called without exception-style
|
||||
// flavor data, or even from an exception handler when the exception
|
||||
// behavior is EXCEPTION_DEFAULT.
|
||||
return flavor;
|
||||
}
|
||||
|
||||
default: {
|
||||
NOTREACHED();
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86_64Thread(
|
||||
CPUContextX86_64* context, const x86_thread_state64_t* x86_thread_state64) {
|
||||
context->rax = x86_thread_state64->__rax;
|
||||
context->rbx = x86_thread_state64->__rbx;
|
||||
context->rcx = x86_thread_state64->__rcx;
|
||||
context->rdx = x86_thread_state64->__rdx;
|
||||
context->rdi = x86_thread_state64->__rdi;
|
||||
context->rsi = x86_thread_state64->__rsi;
|
||||
context->rbp = x86_thread_state64->__rbp;
|
||||
context->rsp = x86_thread_state64->__rsp;
|
||||
context->r8 = x86_thread_state64->__r8;
|
||||
context->r9 = x86_thread_state64->__r9;
|
||||
context->r10 = x86_thread_state64->__r10;
|
||||
context->r11 = x86_thread_state64->__r11;
|
||||
context->r12 = x86_thread_state64->__r12;
|
||||
context->r13 = x86_thread_state64->__r13;
|
||||
context->r14 = x86_thread_state64->__r14;
|
||||
context->r15 = x86_thread_state64->__r15;
|
||||
context->rip = x86_thread_state64->__rip;
|
||||
context->rflags = x86_thread_state64->__rflags;
|
||||
context->cs = x86_thread_state64->__cs;
|
||||
context->fs = x86_thread_state64->__fs;
|
||||
context->gs = x86_thread_state64->__gs;
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86_64Float(
|
||||
CPUContextX86_64* context, const x86_float_state64_t* x86_float_state64) {
|
||||
// This relies on both x86_float_state64_t and context->fxsave64 having
|
||||
// identical (fxsave64) layout.
|
||||
static_assert(offsetof(x86_float_state64_t, __fpu_reserved1) -
|
||||
offsetof(x86_float_state64_t, __fpu_fcw) ==
|
||||
sizeof(context->fxsave64),
|
||||
"types must be equivalent");
|
||||
|
||||
memcpy(&context->fxsave64,
|
||||
&x86_float_state64->__fpu_fcw,
|
||||
sizeof(context->fxsave64));
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86_64Debug(
|
||||
CPUContextX86_64* context, const x86_debug_state64_t* x86_debug_state64) {
|
||||
context->dr0 = x86_debug_state64->__dr0;
|
||||
context->dr1 = x86_debug_state64->__dr1;
|
||||
context->dr2 = x86_debug_state64->__dr2;
|
||||
context->dr3 = x86_debug_state64->__dr3;
|
||||
context->dr4 = x86_debug_state64->__dr4;
|
||||
context->dr5 = x86_debug_state64->__dr5;
|
||||
context->dr6 = x86_debug_state64->__dr6;
|
||||
context->dr7 = x86_debug_state64->__dr7;
|
||||
}
|
||||
|
||||
// Initializes |context| from the native thread state structure |state|, which
|
||||
// is interpreted according to |flavor|. |state_count| must be at least the
|
||||
// expected size for |flavor|. This handles the architecture-specific
|
||||
// x86_THREAD_STATE64, x86_FLOAT_STATE64, and x86_DEBUG_STATE64 flavors. It also
|
||||
// handles the universal x86_THREAD_STATE, x86_FLOAT_STATE, and x86_DEBUG_STATE
|
||||
// flavors provided that the associated structure carries 64-bit data of the
|
||||
// corresponding state type. |flavor| may be THREAD_STATE_NONE to avoid setting
|
||||
// any thread state in |context|. This returns the architecture-specific flavor
|
||||
// value for the thread state that was actually set, or THREAD_STATE_NONE if no
|
||||
// thread state was set.
|
||||
thread_state_flavor_t InitializeCPUContextX86_64Flavor(
|
||||
CPUContextX86_64* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count) {
|
||||
mach_msg_type_number_t expected_state_count;
|
||||
switch (flavor) {
|
||||
case x86_THREAD_STATE:
|
||||
expected_state_count = x86_THREAD_STATE_COUNT;
|
||||
break;
|
||||
case x86_FLOAT_STATE:
|
||||
expected_state_count = x86_FLOAT_STATE_COUNT;
|
||||
break;
|
||||
case x86_DEBUG_STATE:
|
||||
expected_state_count = x86_DEBUG_STATE_COUNT;
|
||||
break;
|
||||
case x86_THREAD_STATE64:
|
||||
expected_state_count = x86_THREAD_STATE64_COUNT;
|
||||
break;
|
||||
case x86_FLOAT_STATE64:
|
||||
expected_state_count = x86_FLOAT_STATE64_COUNT;
|
||||
break;
|
||||
case x86_DEBUG_STATE64:
|
||||
expected_state_count = x86_DEBUG_STATE64_COUNT;
|
||||
break;
|
||||
case THREAD_STATE_NONE:
|
||||
expected_state_count = 0;
|
||||
break;
|
||||
default:
|
||||
LOG(WARNING) << "unhandled flavor " << flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
|
||||
if (state_count < expected_state_count) {
|
||||
LOG(WARNING) << "expected state_count " << expected_state_count
|
||||
<< " for flavor " << flavor << ", observed " << state_count;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
|
||||
switch (flavor) {
|
||||
case x86_THREAD_STATE: {
|
||||
const x86_thread_state_t* x86_thread_state =
|
||||
reinterpret_cast<const x86_thread_state_t*>(state);
|
||||
if (x86_thread_state->tsh.flavor != x86_THREAD_STATE64) {
|
||||
LOG(WARNING) << "expected flavor x86_THREAD_STATE64, observed "
|
||||
<< x86_thread_state->tsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86_64Flavor(
|
||||
context,
|
||||
x86_thread_state->tsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_thread_state->uts.ts64),
|
||||
x86_thread_state->tsh.count);
|
||||
}
|
||||
|
||||
case x86_FLOAT_STATE: {
|
||||
const x86_float_state_t* x86_float_state =
|
||||
reinterpret_cast<const x86_float_state_t*>(state);
|
||||
if (x86_float_state->fsh.flavor != x86_FLOAT_STATE64) {
|
||||
LOG(WARNING) << "expected flavor x86_FLOAT_STATE64, observed "
|
||||
<< x86_float_state->fsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86_64Flavor(
|
||||
context,
|
||||
x86_float_state->fsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_float_state->ufs.fs64),
|
||||
x86_float_state->fsh.count);
|
||||
}
|
||||
|
||||
case x86_DEBUG_STATE: {
|
||||
const x86_debug_state_t* x86_debug_state =
|
||||
reinterpret_cast<const x86_debug_state_t*>(state);
|
||||
if (x86_debug_state->dsh.flavor != x86_DEBUG_STATE64) {
|
||||
LOG(WARNING) << "expected flavor x86_DEBUG_STATE64, observed "
|
||||
<< x86_debug_state->dsh.flavor;
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
return InitializeCPUContextX86_64Flavor(
|
||||
context,
|
||||
x86_debug_state->dsh.flavor,
|
||||
reinterpret_cast<const natural_t*>(&x86_debug_state->uds.ds64),
|
||||
x86_debug_state->dsh.count);
|
||||
}
|
||||
|
||||
case x86_THREAD_STATE64: {
|
||||
const x86_thread_state64_t* x86_thread_state64 =
|
||||
reinterpret_cast<const x86_thread_state64_t*>(state);
|
||||
InitializeCPUContextX86_64Thread(context, x86_thread_state64);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case x86_FLOAT_STATE64: {
|
||||
const x86_float_state64_t* x86_float_state64 =
|
||||
reinterpret_cast<const x86_float_state64_t*>(state);
|
||||
InitializeCPUContextX86_64Float(context, x86_float_state64);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case x86_DEBUG_STATE64: {
|
||||
const x86_debug_state64_t* x86_debug_state64 =
|
||||
reinterpret_cast<const x86_debug_state64_t*>(state);
|
||||
InitializeCPUContextX86_64Debug(context, x86_debug_state64);
|
||||
return flavor;
|
||||
}
|
||||
|
||||
case THREAD_STATE_NONE: {
|
||||
// This may happen without error when called without exception-style
|
||||
// flavor data, or even from an exception handler when the exception
|
||||
// behavior is EXCEPTION_DEFAULT.
|
||||
return flavor;
|
||||
}
|
||||
|
||||
default: {
|
||||
NOTREACHED();
|
||||
return THREAD_STATE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
void InitializeCPUContextX86(CPUContextX86* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count,
|
||||
const x86_thread_state32_t* x86_thread_state32,
|
||||
const x86_float_state32_t* x86_float_state32,
|
||||
const x86_debug_state32_t* x86_debug_state32) {
|
||||
thread_state_flavor_t set_flavor = THREAD_STATE_NONE;
|
||||
if (flavor != THREAD_STATE_NONE) {
|
||||
set_flavor =
|
||||
InitializeCPUContextX86Flavor(context, flavor, state, state_count);
|
||||
}
|
||||
|
||||
if (set_flavor != x86_THREAD_STATE32) {
|
||||
InitializeCPUContextX86Thread(context, x86_thread_state32);
|
||||
}
|
||||
if (set_flavor != x86_FLOAT_STATE32) {
|
||||
InitializeCPUContextX86Float(context, x86_float_state32);
|
||||
}
|
||||
if (set_flavor != x86_DEBUG_STATE32) {
|
||||
InitializeCPUContextX86Debug(context, x86_debug_state32);
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeCPUContextX86_64(CPUContextX86_64* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count,
|
||||
const x86_thread_state64_t* x86_thread_state64,
|
||||
const x86_float_state64_t* x86_float_state64,
|
||||
const x86_debug_state64_t* x86_debug_state64) {
|
||||
thread_state_flavor_t set_flavor = THREAD_STATE_NONE;
|
||||
if (flavor != THREAD_STATE_NONE) {
|
||||
set_flavor =
|
||||
InitializeCPUContextX86_64Flavor(context, flavor, state, state_count);
|
||||
}
|
||||
|
||||
if (set_flavor != x86_THREAD_STATE64) {
|
||||
InitializeCPUContextX86_64Thread(context, x86_thread_state64);
|
||||
}
|
||||
if (set_flavor != x86_FLOAT_STATE64) {
|
||||
InitializeCPUContextX86_64Float(context, x86_float_state64);
|
||||
}
|
||||
if (set_flavor != x86_DEBUG_STATE64) {
|
||||
InitializeCPUContextX86_64Debug(context, x86_debug_state64);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace crashpad
|
115
snapshot/cpu_context_mac.h
Normal file
115
snapshot/cpu_context_mac.h
Normal file
@ -0,0 +1,115 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_MAC_H_
|
||||
#define CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_MAC_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "snapshot/cpu_context.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY) || DOXYGEN
|
||||
|
||||
//! \brief Initializes a CPUContextX86 structure from native context structures
|
||||
//! on Mac OS X.
|
||||
//!
|
||||
//! \a flavor, \a state, and \a state_count may be supplied by exception
|
||||
//! handlers in order for the \a context parameter to be initialized by the
|
||||
//! thread state received by the exception handler to the extent possible. In
|
||||
//! that case, whatever thread state specified by these three parameters will
|
||||
//! supersede \a x86_thread_state32, \a x86_float_state32, or \a
|
||||
//! x86_debug_state32. If thread state in this format is not available, \a
|
||||
//! flavor may be set to `THREAD_STATE_NONE`, and all of \a x86_thread_state32,
|
||||
//! \a x86_float_state32, and \a x86_debug_state32 will be honored.
|
||||
//!
|
||||
//! If \a flavor, \a state, and \a state_count are provided but do not contain
|
||||
//! valid values, a message will be logged and their values will be ignored as
|
||||
//! though \a flavor were specified as `THREAD_STATE_NONE`.
|
||||
//!
|
||||
//! \param[out] context The CPUContextX86 structure to initialize.
|
||||
//! \param[in] flavor The native thread state flavor of \a state. This may be
|
||||
//! `x86_THREAD_STATE32`, `x86_FLOAT_STATE32`, `x86_DEBUG_STATE32`,
|
||||
//! `x86_THREAD_STATE`, `x86_FLOAT_STATE`, or `x86_DEBUG_STATE`. It may also
|
||||
//! be `THREAD_STATE_NONE` if \a state is not supplied (and is `NULL`).
|
||||
//! \param[in] state The native thread state, which may be a casted pointer to
|
||||
//! `x86_thread_state32_t`, `x86_float_state32_t`, `x86_debug_state32_t`,
|
||||
//! `x86_thread_state`, `x86_float_state`, or `x86_debug_state`. This
|
||||
//! parameter may be `NULL` to not supply this data, in which case \a flavor
|
||||
//! must be `THREAD_STATE_NONE`. If a “universal” structure is used, it must
|
||||
//! carry 32-bit state data of the correct type.
|
||||
//! \param[in] state_count The number of `natural_t`-sized (`int`-sized) units
|
||||
//! in \a state. This may be 0 if \a state is `NULL`.
|
||||
//! \param[in] x86_thread_state32 The state of the thread’s integer registers.
|
||||
//! \param[in] x86_float_state32 The state of the thread’s floating-point
|
||||
//! registers.
|
||||
//! \param[in] x86_debug_state32 The state of the thread’s debug registers.
|
||||
void InitializeCPUContextX86(CPUContextX86* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count,
|
||||
const x86_thread_state32_t* x86_thread_state32,
|
||||
const x86_float_state32_t* x86_float_state32,
|
||||
const x86_debug_state32_t* x86_debug_state32);
|
||||
|
||||
//! \brief Initializes a CPUContextX86_64 structure from native context
|
||||
//! structures on Mac OS X.
|
||||
//!
|
||||
//! \a flavor, \a state, and \a state_count may be supplied by exception
|
||||
//! handlers in order for the \a context parameter to be initialized by the
|
||||
//! thread state received by the exception handler to the extent possible. In
|
||||
//! that case, whatever thread state specified by these three parameters will
|
||||
//! supersede \a x86_thread_state64, \a x86_float_state64, or \a
|
||||
//! x86_debug_state64. If thread state in this format is not available, \a
|
||||
//! flavor may be set to `THREAD_STATE_NONE`, and all of \a x86_thread_state64,
|
||||
//! \a x86_float_state64, and \a x86_debug_state64 will be honored.
|
||||
//!
|
||||
//! If \a flavor, \a state, and \a state_count are provided but do not contain
|
||||
//! valid values, a message will be logged and their values will be ignored as
|
||||
//! though \a flavor were specified as `THREAD_STATE_NONE`.
|
||||
//!
|
||||
//! \param[out] context The CPUContextX86_64 structure to initialize.
|
||||
//! \param[in] flavor The native thread state flavor of \a state. This may be
|
||||
//! `x86_THREAD_STATE64`, `x86_FLOAT_STATE64`, `x86_DEBUG_STATE64`,
|
||||
//! `x86_THREAD_STATE`, `x86_FLOAT_STATE`, or `x86_DEBUG_STATE`. It may also
|
||||
//! be `THREAD_STATE_NONE` if \a state is not supplied (and is `NULL`).
|
||||
//! \param[in] state The native thread state, which may be a casted pointer to
|
||||
//! `x86_thread_state64_t`, `x86_float_state64_t`, `x86_debug_state64_t`,
|
||||
//! `x86_thread_state`, `x86_float_state`, or `x86_debug_state`. This
|
||||
//! parameter may be `NULL` to not supply this data, in which case \a flavor
|
||||
//! must be `THREAD_STATE_NONE`. If a “universal” structure is used, it must
|
||||
//! carry 64-bit state data of the correct type.
|
||||
//! \param[in] state_count The number of `int`-sized units in \a state. This may
|
||||
//! be 0 if \a state is `NULL`.
|
||||
//! \param[in] x86_thread_state64 The state of the thread’s integer registers.
|
||||
//! \param[in] x86_float_state64 The state of the thread’s floating-point
|
||||
//! registers.
|
||||
//! \param[in] x86_debug_state64 The state of the thread’s debug registers.
|
||||
void InitializeCPUContextX86_64(CPUContextX86_64* context,
|
||||
thread_state_flavor_t flavor,
|
||||
const natural_t* state,
|
||||
mach_msg_type_number_t state_count,
|
||||
const x86_thread_state64_t* x86_thread_state64,
|
||||
const x86_float_state64_t* x86_float_state64,
|
||||
const x86_debug_state64_t* x86_debug_state64);
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_MAC_H_
|
419
snapshot/cpu_context_mac_test.cc
Normal file
419
snapshot/cpu_context_mac_test.cc
Normal file
@ -0,0 +1,419 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "snapshot/cpu_context_mac.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace crashpad;
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
|
||||
TEST(CPUContextMac, InitializeContextX86) {
|
||||
x86_thread_state32_t x86_thread_state32 = {};
|
||||
x86_float_state32_t x86_float_state32 = {};
|
||||
x86_debug_state32_t x86_debug_state32 = {};
|
||||
x86_thread_state32.__eax = 1;
|
||||
x86_float_state32.__fpu_ftw = 2;
|
||||
x86_debug_state32.__dr0 = 3;
|
||||
|
||||
// Test the simple case, where everything in the CPUContextX86 argument is set
|
||||
// directly from the supplied thread, float, and debug state parameters.
|
||||
{
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(&cpu_context_x86,
|
||||
THREAD_STATE_NONE,
|
||||
NULL,
|
||||
0,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
// Supply context in a CPU-specific “flavor” parameter expected to be used
|
||||
// instead of the supplied thread, float, or debug state parameters. Do this
|
||||
// once for each of the three valid flavors. This simulates how
|
||||
// InitializeCPUContextX86() might be used to initialize the context in an
|
||||
// exception handler, where the exception handler may have received the
|
||||
// “flavor” parameter and this context should be used to initialize the
|
||||
// CPUContextX86.
|
||||
|
||||
{
|
||||
x86_thread_state32_t alt_x86_thread_state32 = {};
|
||||
alt_x86_thread_state32.__eax = 4;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_THREAD_STATE32,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_thread_state32),
|
||||
x86_THREAD_STATE32_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(4u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_float_state32_t alt_x86_float_state32 = {};
|
||||
alt_x86_float_state32.__fpu_ftw = 5;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_FLOAT_STATE32,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_float_state32),
|
||||
x86_FLOAT_STATE32_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(5u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_debug_state32_t alt_x86_debug_state32 = {};
|
||||
alt_x86_debug_state32.__dr0 = 6;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_DEBUG_STATE32,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_debug_state32),
|
||||
x86_DEBUG_STATE32_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(6u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
// Supply context in a universal “flavor” parameter expected to be used
|
||||
// instead of the supplied thread, float, or debug state parameters. The
|
||||
// universal format allows an exception handler to be registered to receive
|
||||
// thread, float, or debug state without having to know in advance whether it
|
||||
// will be receiving the state from a 32-bit or 64-bit process. For
|
||||
// CPUContextX86, only the 32-bit form is supported.
|
||||
|
||||
{
|
||||
x86_thread_state x86_thread_state_3264 = {};
|
||||
x86_thread_state_3264.tsh.flavor = x86_THREAD_STATE32;
|
||||
x86_thread_state_3264.tsh.count = x86_THREAD_STATE32_COUNT;
|
||||
x86_thread_state_3264.uts.ts32.__eax = 7;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_THREAD_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state_3264),
|
||||
x86_THREAD_STATE_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(7u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_float_state x86_float_state_3264 = {};
|
||||
x86_float_state_3264.fsh.flavor = x86_FLOAT_STATE32;
|
||||
x86_float_state_3264.fsh.count = x86_FLOAT_STATE32_COUNT;
|
||||
x86_float_state_3264.ufs.fs32.__fpu_ftw = 8;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_FLOAT_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_float_state_3264),
|
||||
x86_FLOAT_STATE_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(8u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_debug_state x86_debug_state_3264 = {};
|
||||
x86_debug_state_3264.dsh.flavor = x86_DEBUG_STATE32;
|
||||
x86_debug_state_3264.dsh.count = x86_DEBUG_STATE32_COUNT;
|
||||
x86_debug_state_3264.uds.ds32.__dr0 = 9;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_DEBUG_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_debug_state_3264),
|
||||
x86_DEBUG_STATE_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(9u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
// Supply inappropriate “flavor” contexts to test that
|
||||
// InitializeCPUContextX86() detects the problem and refuses to use the
|
||||
// supplied “flavor” context, falling back to the thread, float, and debug
|
||||
// states.
|
||||
|
||||
{
|
||||
x86_thread_state64_t x86_thread_state64 = {};
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_THREAD_STATE64,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state64),
|
||||
x86_THREAD_STATE64_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_thread_state x86_thread_state_3264 = {};
|
||||
x86_thread_state_3264.tsh.flavor = x86_THREAD_STATE64;
|
||||
x86_thread_state_3264.tsh.count = x86_THREAD_STATE64_COUNT;
|
||||
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
internal::InitializeCPUContextX86(
|
||||
&cpu_context_x86,
|
||||
x86_THREAD_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state_3264),
|
||||
x86_THREAD_STATE_COUNT,
|
||||
&x86_thread_state32,
|
||||
&x86_float_state32,
|
||||
&x86_debug_state32);
|
||||
EXPECT_EQ(1u, cpu_context_x86.eax);
|
||||
EXPECT_EQ(2u, cpu_context_x86.fxsave.ftw);
|
||||
EXPECT_EQ(3u, cpu_context_x86.dr0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CPUContextMac, InitializeContextX86_64) {
|
||||
x86_thread_state64_t x86_thread_state64 = {};
|
||||
x86_float_state64_t x86_float_state64 = {};
|
||||
x86_debug_state64_t x86_debug_state64 = {};
|
||||
x86_thread_state64.__rax = 10;
|
||||
x86_float_state64.__fpu_ftw = 11;
|
||||
x86_debug_state64.__dr0 = 12;
|
||||
|
||||
// Test the simple case, where everything in the CPUContextX86_64 argument is
|
||||
// set directly from the supplied thread, float, and debug state parameters.
|
||||
{
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(&cpu_context_x86_64,
|
||||
THREAD_STATE_NONE,
|
||||
NULL,
|
||||
0,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
// Supply context in a CPU-specific “flavor” parameter expected to be used
|
||||
// instead of the supplied thread, float, or debug state parameters. Do this
|
||||
// once for each of the three valid flavors. This simulates how
|
||||
// InitializeCPUContextX86_64() might be used to initialize the context in an
|
||||
// exception handler, where the exception handler may have received the
|
||||
// “flavor” parameter and this context should be used to initialize the
|
||||
// CPUContextX86_64.
|
||||
|
||||
{
|
||||
x86_thread_state64_t alt_x86_thread_state64 = {};
|
||||
alt_x86_thread_state64.__rax = 13;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_THREAD_STATE64,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_thread_state64),
|
||||
x86_THREAD_STATE64_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(13u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_float_state64_t alt_x86_float_state64 = {};
|
||||
alt_x86_float_state64.__fpu_ftw = 14;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_FLOAT_STATE64,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_float_state64),
|
||||
x86_FLOAT_STATE64_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(14u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_debug_state64_t alt_x86_debug_state64 = {};
|
||||
alt_x86_debug_state64.__dr0 = 15;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_DEBUG_STATE64,
|
||||
reinterpret_cast<natural_t*>(&alt_x86_debug_state64),
|
||||
x86_DEBUG_STATE64_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(15u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
// Supply context in a universal “flavor” parameter expected to be used
|
||||
// instead of the supplied thread, float, or debug state parameters. The
|
||||
// universal format allows an exception handler to be registered to receive
|
||||
// thread, float, or debug state without having to know in advance whether it
|
||||
// will be receiving the state from a 32-bit or 64-bit process. For
|
||||
// CPUContextX86_64, only the 64-bit form is supported.
|
||||
|
||||
{
|
||||
x86_thread_state x86_thread_state_3264 = {};
|
||||
x86_thread_state_3264.tsh.flavor = x86_THREAD_STATE64;
|
||||
x86_thread_state_3264.tsh.count = x86_THREAD_STATE64_COUNT;
|
||||
x86_thread_state_3264.uts.ts64.__rax = 16;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_THREAD_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state_3264),
|
||||
x86_THREAD_STATE_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(16u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_float_state x86_float_state_3264 = {};
|
||||
x86_float_state_3264.fsh.flavor = x86_FLOAT_STATE64;
|
||||
x86_float_state_3264.fsh.count = x86_FLOAT_STATE64_COUNT;
|
||||
x86_float_state_3264.ufs.fs64.__fpu_ftw = 17;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_FLOAT_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_float_state_3264),
|
||||
x86_FLOAT_STATE_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(17u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_debug_state x86_debug_state_3264 = {};
|
||||
x86_debug_state_3264.dsh.flavor = x86_DEBUG_STATE64;
|
||||
x86_debug_state_3264.dsh.count = x86_DEBUG_STATE64_COUNT;
|
||||
x86_debug_state_3264.uds.ds64.__dr0 = 18;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_DEBUG_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_debug_state_3264),
|
||||
x86_DEBUG_STATE_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(18u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
// Supply inappropriate “flavor” contexts to test that
|
||||
// InitializeCPUContextX86() detects the problem and refuses to use the
|
||||
// supplied “flavor” context, falling back to the thread, float, and debug
|
||||
// states.
|
||||
|
||||
{
|
||||
x86_thread_state32_t x86_thread_state32 = {};
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_THREAD_STATE32,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state32),
|
||||
x86_THREAD_STATE32_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
|
||||
{
|
||||
x86_thread_state x86_thread_state_3264 = {};
|
||||
x86_thread_state_3264.tsh.flavor = x86_THREAD_STATE32;
|
||||
x86_thread_state_3264.tsh.count = x86_THREAD_STATE32_COUNT;
|
||||
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
internal::InitializeCPUContextX86_64(
|
||||
&cpu_context_x86_64,
|
||||
x86_THREAD_STATE,
|
||||
reinterpret_cast<natural_t*>(&x86_thread_state_3264),
|
||||
x86_THREAD_STATE_COUNT,
|
||||
&x86_thread_state64,
|
||||
&x86_float_state64,
|
||||
&x86_debug_state64);
|
||||
EXPECT_EQ(10u, cpu_context_x86_64.rax);
|
||||
EXPECT_EQ(11u, cpu_context_x86_64.fxsave64.ftw);
|
||||
EXPECT_EQ(12u, cpu_context_x86_64.dr0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
@ -29,6 +29,8 @@
|
||||
'cpu_architecture.h',
|
||||
'cpu_context.cc',
|
||||
'cpu_context.h',
|
||||
'cpu_context_mac.cc',
|
||||
'cpu_context_mac.h',
|
||||
'exception_snapshot.h',
|
||||
'memory_snapshot.h',
|
||||
'memory_snapshot_mac.cc',
|
||||
@ -57,6 +59,7 @@
|
||||
'..',
|
||||
],
|
||||
'sources': [
|
||||
'cpu_context_mac_test.cc',
|
||||
'system_snapshot_mac_test.cc',
|
||||
],
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user