mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Thread snapshots on Windows can have varying size
In a future CL we will make use of InitializeContext2 which can produce contexts of varying sizes - this makes the existing use of a union for wow/x64 contexts no longer feasible. The context union in process_reader_win is replaced with a (moveable, copyable) helper struct which currently only knows how to allocate the replaced WOW or CONTEXT sized unions. As this field is no longer a member of the Thread struct it cannot be passed into other functions as a reference, so instead a pointer is used in these functions. Bug: 1250098 Change-Id: Ied3fe971c0073bbdafc071217e1bb0f72350bb4e Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3538668 Commit-Queue: Alex Gough <ajgo@chromium.org> Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
4581a355b1
commit
a5b7e504c6
@ -36,12 +36,12 @@ static_assert(sizeof(CPUContextX86::Fsave) ==
|
||||
#endif // ARCH_CPU_X86
|
||||
|
||||
template <typename T>
|
||||
bool HasContextPart(const T& context, uint32_t bits) {
|
||||
return (context.ContextFlags & bits) == bits;
|
||||
bool HasContextPart(const T* context, uint32_t bits) {
|
||||
return (context->ContextFlags & bits) == bits;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
|
||||
void CommonInitializeX86Context(const T* context, CPUContextX86* out) {
|
||||
// This function assumes that the WOW64_CONTEXT_* and x86 CONTEXT_* values
|
||||
// for ContextFlags are identical. This can be tested when targeting 32-bit
|
||||
// x86.
|
||||
@ -72,54 +72,54 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
|
||||
<< "non-x86 context";
|
||||
|
||||
if (HasContextPart(context, WOW64_CONTEXT_CONTROL)) {
|
||||
out->ebp = context.Ebp;
|
||||
out->eip = context.Eip;
|
||||
out->cs = static_cast<uint16_t>(context.SegCs);
|
||||
out->eflags = context.EFlags;
|
||||
out->esp = context.Esp;
|
||||
out->ss = static_cast<uint16_t>(context.SegSs);
|
||||
out->ebp = context->Ebp;
|
||||
out->eip = context->Eip;
|
||||
out->cs = static_cast<uint16_t>(context->SegCs);
|
||||
out->eflags = context->EFlags;
|
||||
out->esp = context->Esp;
|
||||
out->ss = static_cast<uint16_t>(context->SegSs);
|
||||
}
|
||||
|
||||
if (HasContextPart(context, WOW64_CONTEXT_INTEGER)) {
|
||||
out->eax = context.Eax;
|
||||
out->ebx = context.Ebx;
|
||||
out->ecx = context.Ecx;
|
||||
out->edx = context.Edx;
|
||||
out->edi = context.Edi;
|
||||
out->esi = context.Esi;
|
||||
out->eax = context->Eax;
|
||||
out->ebx = context->Ebx;
|
||||
out->ecx = context->Ecx;
|
||||
out->edx = context->Edx;
|
||||
out->edi = context->Edi;
|
||||
out->esi = context->Esi;
|
||||
}
|
||||
|
||||
if (HasContextPart(context, WOW64_CONTEXT_SEGMENTS)) {
|
||||
out->ds = static_cast<uint16_t>(context.SegDs);
|
||||
out->es = static_cast<uint16_t>(context.SegEs);
|
||||
out->fs = static_cast<uint16_t>(context.SegFs);
|
||||
out->gs = static_cast<uint16_t>(context.SegGs);
|
||||
out->ds = static_cast<uint16_t>(context->SegDs);
|
||||
out->es = static_cast<uint16_t>(context->SegEs);
|
||||
out->fs = static_cast<uint16_t>(context->SegFs);
|
||||
out->gs = static_cast<uint16_t>(context->SegGs);
|
||||
}
|
||||
|
||||
if (HasContextPart(context, WOW64_CONTEXT_DEBUG_REGISTERS)) {
|
||||
out->dr0 = context.Dr0;
|
||||
out->dr1 = context.Dr1;
|
||||
out->dr2 = context.Dr2;
|
||||
out->dr3 = context.Dr3;
|
||||
out->dr0 = context->Dr0;
|
||||
out->dr1 = context->Dr1;
|
||||
out->dr2 = context->Dr2;
|
||||
out->dr3 = context->Dr3;
|
||||
|
||||
// DR4 and DR5 are obsolete synonyms for DR6 and DR7, see
|
||||
// https://en.wikipedia.org/wiki/X86_debug_register.
|
||||
out->dr4 = context.Dr6;
|
||||
out->dr5 = context.Dr7;
|
||||
out->dr4 = context->Dr6;
|
||||
out->dr5 = context->Dr7;
|
||||
|
||||
out->dr6 = context.Dr6;
|
||||
out->dr7 = context.Dr7;
|
||||
out->dr6 = context->Dr6;
|
||||
out->dr7 = context->Dr7;
|
||||
}
|
||||
|
||||
if (HasContextPart(context, WOW64_CONTEXT_EXTENDED_REGISTERS)) {
|
||||
static_assert(sizeof(out->fxsave) == sizeof(context.ExtendedRegisters),
|
||||
static_assert(sizeof(out->fxsave) == sizeof(context->ExtendedRegisters),
|
||||
"fxsave types must be equivalent");
|
||||
memcpy(&out->fxsave, &context.ExtendedRegisters, sizeof(out->fxsave));
|
||||
memcpy(&out->fxsave, &context->ExtendedRegisters, sizeof(out->fxsave));
|
||||
} else if (HasContextPart(context, WOW64_CONTEXT_FLOATING_POINT)) {
|
||||
// The static_assert that validates this cast can’t be here because it
|
||||
// relies on field names that vary based on the template parameter.
|
||||
CPUContextX86::FsaveToFxsave(
|
||||
*reinterpret_cast<const CPUContextX86::Fsave*>(&context.FloatSave),
|
||||
*reinterpret_cast<const CPUContextX86::Fsave*>(&context->FloatSave),
|
||||
&out->fxsave);
|
||||
}
|
||||
}
|
||||
@ -128,101 +128,101 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
|
||||
|
||||
#if defined(ARCH_CPU_X86)
|
||||
|
||||
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) {
|
||||
void InitializeX86Context(const CONTEXT* context, CPUContextX86* out) {
|
||||
CommonInitializeX86Context(context, out);
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
|
||||
void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out) {
|
||||
void InitializeX86Context(const WOW64_CONTEXT* context, CPUContextX86* out) {
|
||||
CommonInitializeX86Context(context, out);
|
||||
}
|
||||
|
||||
void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out) {
|
||||
void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
LOG_IF(ERROR, !HasContextPart(context, CONTEXT_AMD64)) << "non-x64 context";
|
||||
|
||||
if (HasContextPart(context, CONTEXT_CONTROL)) {
|
||||
out->cs = context.SegCs;
|
||||
out->rflags = context.EFlags;
|
||||
out->rip = context.Rip;
|
||||
out->rsp = context.Rsp;
|
||||
out->cs = context->SegCs;
|
||||
out->rflags = context->EFlags;
|
||||
out->rip = context->Rip;
|
||||
out->rsp = context->Rsp;
|
||||
// SegSs ignored.
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_INTEGER)) {
|
||||
out->rax = context.Rax;
|
||||
out->rbx = context.Rbx;
|
||||
out->rcx = context.Rcx;
|
||||
out->rdx = context.Rdx;
|
||||
out->rdi = context.Rdi;
|
||||
out->rsi = context.Rsi;
|
||||
out->rbp = context.Rbp;
|
||||
out->r8 = context.R8;
|
||||
out->r9 = context.R9;
|
||||
out->r10 = context.R10;
|
||||
out->r11 = context.R11;
|
||||
out->r12 = context.R12;
|
||||
out->r13 = context.R13;
|
||||
out->r14 = context.R14;
|
||||
out->r15 = context.R15;
|
||||
out->rax = context->Rax;
|
||||
out->rbx = context->Rbx;
|
||||
out->rcx = context->Rcx;
|
||||
out->rdx = context->Rdx;
|
||||
out->rdi = context->Rdi;
|
||||
out->rsi = context->Rsi;
|
||||
out->rbp = context->Rbp;
|
||||
out->r8 = context->R8;
|
||||
out->r9 = context->R9;
|
||||
out->r10 = context->R10;
|
||||
out->r11 = context->R11;
|
||||
out->r12 = context->R12;
|
||||
out->r13 = context->R13;
|
||||
out->r14 = context->R14;
|
||||
out->r15 = context->R15;
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_SEGMENTS)) {
|
||||
out->fs = context.SegFs;
|
||||
out->gs = context.SegGs;
|
||||
out->fs = context->SegFs;
|
||||
out->gs = context->SegGs;
|
||||
// SegDs ignored.
|
||||
// SegEs ignored.
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_DEBUG_REGISTERS)) {
|
||||
out->dr0 = context.Dr0;
|
||||
out->dr1 = context.Dr1;
|
||||
out->dr2 = context.Dr2;
|
||||
out->dr3 = context.Dr3;
|
||||
out->dr0 = context->Dr0;
|
||||
out->dr1 = context->Dr1;
|
||||
out->dr2 = context->Dr2;
|
||||
out->dr3 = context->Dr3;
|
||||
|
||||
// DR4 and DR5 are obsolete synonyms for DR6 and DR7, see
|
||||
// https://en.wikipedia.org/wiki/X86_debug_register.
|
||||
out->dr4 = context.Dr6;
|
||||
out->dr5 = context.Dr7;
|
||||
out->dr4 = context->Dr6;
|
||||
out->dr5 = context->Dr7;
|
||||
|
||||
out->dr6 = context.Dr6;
|
||||
out->dr7 = context.Dr7;
|
||||
out->dr6 = context->Dr6;
|
||||
out->dr7 = context->Dr7;
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_FLOATING_POINT)) {
|
||||
static_assert(sizeof(out->fxsave) == sizeof(context.FltSave),
|
||||
static_assert(sizeof(out->fxsave) == sizeof(context->FltSave),
|
||||
"types must be equivalent");
|
||||
memcpy(&out->fxsave, &context.FltSave, sizeof(out->fxsave));
|
||||
memcpy(&out->fxsave, &context->FltSave, sizeof(out->fxsave));
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
|
||||
void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out) {
|
||||
void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
LOG_IF(ERROR, !HasContextPart(context, CONTEXT_ARM64)) << "non-arm64 context";
|
||||
|
||||
if (HasContextPart(context, CONTEXT_CONTROL)) {
|
||||
out->spsr = context.Cpsr;
|
||||
out->pc = context.Pc;
|
||||
out->regs[30] = context.Lr;
|
||||
out->sp = context.Sp;
|
||||
out->regs[29] = context.Fp;
|
||||
out->spsr = context->Cpsr;
|
||||
out->pc = context->Pc;
|
||||
out->regs[30] = context->Lr;
|
||||
out->sp = context->Sp;
|
||||
out->regs[29] = context->Fp;
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_INTEGER)) {
|
||||
memcpy(&out->regs[0], &context.X0, 18 * sizeof(context.X0));
|
||||
memcpy(&out->regs[0], &context->X0, 18 * sizeof(context->X0));
|
||||
// Don't copy x18 which is reserved as platform register.
|
||||
memcpy(&out->regs[19], &context.X19, 10 * sizeof(context.X0));
|
||||
memcpy(&out->regs[19], &context->X19, 10 * sizeof(context->X0));
|
||||
}
|
||||
|
||||
if (HasContextPart(context, CONTEXT_FLOATING_POINT)) {
|
||||
static_assert(sizeof(out->fpsimd) == sizeof(context.V),
|
||||
static_assert(sizeof(out->fpsimd) == sizeof(context->V),
|
||||
"types must be equivalent");
|
||||
memcpy(&out->fpsimd, &context.V, sizeof(out->fpsimd));
|
||||
memcpy(&out->fpsimd, &context->V, sizeof(out->fpsimd));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ struct CPUContextARM64;
|
||||
|
||||
//! \brief Initializes a CPUContextX86 structure from a native context structure
|
||||
//! on Windows.
|
||||
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out);
|
||||
void InitializeX86Context(const CONTEXT* context, CPUContextX86* out);
|
||||
|
||||
#endif // ARCH_CPU_X86
|
||||
|
||||
@ -37,11 +37,12 @@ void InitializeX86Context(const CONTEXT& context, CPUContextX86* out);
|
||||
|
||||
//! \brief Initializes a CPUContextX86 structure from a native context structure
|
||||
//! on Windows.
|
||||
void InitializeX86Context(const WOW64_CONTEXT& context, CPUContextX86* out);
|
||||
void InitializeX86Context(const WOW64_CONTEXT* context, CPUContextX86* out);
|
||||
|
||||
//! \brief Initializes a CPUContextX86_64 structure from a native context
|
||||
//! structure on Windows.
|
||||
void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out);
|
||||
//! Only reads a max of sizeof(CONTEXT) so will not initialize extended values.
|
||||
void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out);
|
||||
|
||||
#endif // ARCH_CPU_X86_64
|
||||
|
||||
@ -49,7 +50,7 @@ void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out);
|
||||
|
||||
//! \brief Initializes a CPUContextARM64 structure from a native context
|
||||
//! structure on Windows.
|
||||
void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out);
|
||||
void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out);
|
||||
|
||||
#endif // ARCH_CPU_ARM64
|
||||
|
||||
|
@ -41,7 +41,7 @@ void TestInitializeX86Context() {
|
||||
// directly from the supplied thread, float, and debug state parameters.
|
||||
{
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
InitializeX86Context(context, &cpu_context_x86);
|
||||
InitializeX86Context(&context, &cpu_context_x86);
|
||||
EXPECT_EQ(cpu_context_x86.eax, 1u);
|
||||
EXPECT_EQ(cpu_context_x86.fxsave.ftw, 2u);
|
||||
EXPECT_EQ(cpu_context_x86.dr0, 3u);
|
||||
@ -73,7 +73,7 @@ void TestInitializeX86Context_FsaveWithoutFxsave() {
|
||||
|
||||
{
|
||||
CPUContextX86 cpu_context_x86 = {};
|
||||
InitializeX86Context(context, &cpu_context_x86);
|
||||
InitializeX86Context(&context, &cpu_context_x86);
|
||||
|
||||
EXPECT_EQ(cpu_context_x86.eax, 1u);
|
||||
|
||||
@ -117,7 +117,7 @@ TEST(CPUContextWin, InitializeX64Context) {
|
||||
// set directly from the supplied thread, float, and debug state parameters.
|
||||
{
|
||||
CPUContextX86_64 cpu_context_x86_64 = {};
|
||||
InitializeX64Context(context, &cpu_context_x86_64);
|
||||
InitializeX64Context(&context, &cpu_context_x86_64);
|
||||
EXPECT_EQ(cpu_context_x86_64.rax, 10u);
|
||||
EXPECT_EQ(cpu_context_x86_64.fxsave.ftw, 11u);
|
||||
EXPECT_EQ(cpu_context_x86_64.dr0, 12u);
|
||||
|
@ -36,7 +36,7 @@ using Context32 = CONTEXT;
|
||||
using Context32 = WOW64_CONTEXT;
|
||||
#endif
|
||||
|
||||
void NativeContextToCPUContext32(const Context32& context_record,
|
||||
void NativeContextToCPUContext32(const Context32* context_record,
|
||||
CPUContext* context,
|
||||
CPUContextUnion* context_union) {
|
||||
context->architecture = kCPUArchitectureX86;
|
||||
@ -46,7 +46,7 @@ void NativeContextToCPUContext32(const Context32& context_record,
|
||||
#endif // ARCH_CPU_X86_FAMILY
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
void NativeContextToCPUContext64(const CONTEXT& context_record,
|
||||
void NativeContextToCPUContext64(const CONTEXT* context_record,
|
||||
CPUContext* context,
|
||||
CPUContextUnion* context_union) {
|
||||
#if defined(ARCH_CPU_X86_64)
|
||||
@ -190,7 +190,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
|
||||
ProcessReaderWin* process_reader,
|
||||
WinVMAddress exception_pointers_address,
|
||||
DWORD exception_thread_id,
|
||||
void (*native_to_cpu_context)(const ContextType& context_record,
|
||||
void (*native_to_cpu_context)(const ContextType* context_record,
|
||||
CPUContext* context,
|
||||
CPUContextUnion* context_union)) {
|
||||
ExceptionPointersType exception_pointers;
|
||||
@ -232,10 +232,9 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
|
||||
for (const auto& thread : process_reader->Threads()) {
|
||||
if (thread.id == blame_thread_id) {
|
||||
thread_id_ = blame_thread_id;
|
||||
native_to_cpu_context(
|
||||
*reinterpret_cast<const ContextType*>(&thread.context),
|
||||
&context_,
|
||||
&context_union_);
|
||||
native_to_cpu_context(thread.context.context<const ContextType>(),
|
||||
&context_,
|
||||
&context_union_);
|
||||
exception_address_ = context_.InstructionPointer();
|
||||
break;
|
||||
}
|
||||
@ -266,7 +265,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
|
||||
return false;
|
||||
}
|
||||
|
||||
native_to_cpu_context(context_record, &context_, &context_union_);
|
||||
native_to_cpu_context(&context_record, &context_, &context_union_);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -93,7 +93,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot {
|
||||
ProcessReaderWin* process_reader,
|
||||
WinVMAddress exception_pointers_address,
|
||||
DWORD exception_thread_id,
|
||||
void (*native_to_cpu_context)(const ContextType& context_record,
|
||||
void (*native_to_cpu_context)(const ContextType* context_record,
|
||||
CPUContext* context,
|
||||
CPUContextUnion* context_union));
|
||||
|
||||
|
@ -143,7 +143,7 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
|
||||
DCHECK(suspension_state == ProcessSuspensionState::kRunning);
|
||||
thread->suspend_count = 0;
|
||||
DCHECK(!is_64_reading_32);
|
||||
CaptureContext(&thread->context.native);
|
||||
thread->context.InitializeFromCurrentThread();
|
||||
} else {
|
||||
DWORD previous_suspend_count = SuspendThread(thread_handle);
|
||||
if (previous_suspend_count == static_cast<DWORD>(-1)) {
|
||||
@ -162,25 +162,18 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
|
||||
(suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0);
|
||||
}
|
||||
|
||||
memset(&thread->context, 0, sizeof(thread->context));
|
||||
#if defined(ARCH_CPU_32_BITS)
|
||||
const bool is_native = true;
|
||||
#elif defined(ARCH_CPU_64_BITS)
|
||||
const bool is_native = !is_64_reading_32;
|
||||
if (is_64_reading_32) {
|
||||
thread->context.wow64.ContextFlags = CONTEXT_ALL;
|
||||
if (!Wow64GetThreadContext(thread_handle, &thread->context.wow64)) {
|
||||
PLOG(ERROR) << "Wow64GetThreadContext";
|
||||
if (!thread->context.InitializeWow64(thread_handle))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (is_native) {
|
||||
thread->context.native.ContextFlags = CONTEXT_ALL;
|
||||
if (!GetThreadContext(thread_handle, &thread->context.native)) {
|
||||
PLOG(ERROR) << "GetThreadContext";
|
||||
if (!thread->context.InitializeNative(thread_handle))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ResumeThread(thread_handle)) {
|
||||
@ -194,6 +187,39 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
|
||||
|
||||
} // namespace
|
||||
|
||||
ProcessReaderWin::ThreadContext::ThreadContext()
|
||||
: offset_(0), initialized_(false), data_() {}
|
||||
|
||||
void ProcessReaderWin::ThreadContext::InitializeFromCurrentThread() {
|
||||
data_.resize(sizeof(CONTEXT));
|
||||
initialized_ = true;
|
||||
CaptureContext(context<CONTEXT>());
|
||||
}
|
||||
|
||||
bool ProcessReaderWin::ThreadContext::InitializeNative(HANDLE thread_handle) {
|
||||
data_.resize(sizeof(CONTEXT));
|
||||
initialized_ = true;
|
||||
context<CONTEXT>()->ContextFlags = CONTEXT_ALL;
|
||||
if (!GetThreadContext(thread_handle, context<CONTEXT>())) {
|
||||
PLOG(ERROR) << "GetThreadContext";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
bool ProcessReaderWin::ThreadContext::InitializeWow64(HANDLE thread_handle) {
|
||||
data_.resize(sizeof(WOW64_CONTEXT));
|
||||
initialized_ = true;
|
||||
context<WOW64_CONTEXT>()->ContextFlags = CONTEXT_ALL;
|
||||
if (!Wow64GetThreadContext(thread_handle, context<WOW64_CONTEXT>())) {
|
||||
PLOG(ERROR) << "Wow64GetThreadContext";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
ProcessReaderWin::Thread::Thread()
|
||||
: context(),
|
||||
id(0),
|
||||
@ -203,8 +229,7 @@ ProcessReaderWin::Thread::Thread()
|
||||
stack_region_size(0),
|
||||
suspend_count(0),
|
||||
priority_class(0),
|
||||
priority(0) {
|
||||
}
|
||||
priority(0) {}
|
||||
|
||||
ProcessReaderWin::ProcessReaderWin()
|
||||
: process_(INVALID_HANDLE_VALUE),
|
||||
|
@ -40,17 +40,39 @@ enum class ProcessSuspensionState : bool {
|
||||
//! \brief Accesses information about another process, identified by a `HANDLE`.
|
||||
class ProcessReaderWin {
|
||||
public:
|
||||
//! \brief Helper to make the context copyable and resizable.
|
||||
class ThreadContext {
|
||||
public:
|
||||
ThreadContext();
|
||||
~ThreadContext() {}
|
||||
|
||||
template <typename T>
|
||||
T* context() const {
|
||||
DCHECK(initialized_);
|
||||
return reinterpret_cast<T*>(
|
||||
const_cast<unsigned char*>(data_.data() + offset_));
|
||||
}
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
bool InitializeWow64(HANDLE thread_handle);
|
||||
#endif
|
||||
void InitializeFromCurrentThread();
|
||||
bool InitializeNative(HANDLE thread_handle);
|
||||
|
||||
private:
|
||||
// This is usually 0 but Windows might cause it to be positive when
|
||||
// fetching the extended context. This needs to be adjusted after
|
||||
// calls to InitializeContext2().
|
||||
size_t offset_;
|
||||
bool initialized_;
|
||||
std::vector<unsigned char> data_;
|
||||
};
|
||||
|
||||
//! \brief Contains information about a thread that belongs to a process.
|
||||
struct Thread {
|
||||
Thread();
|
||||
~Thread() {}
|
||||
|
||||
union {
|
||||
CONTEXT native;
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
WOW64_CONTEXT wow64;
|
||||
#endif
|
||||
} context;
|
||||
ThreadContext context;
|
||||
uint64_t id;
|
||||
WinVMAddress teb_address;
|
||||
WinVMSize teb_size;
|
||||
|
@ -111,7 +111,8 @@ TEST(ProcessReaderWin, SelfOneThread) {
|
||||
ASSERT_GE(threads.size(), 1u);
|
||||
|
||||
EXPECT_EQ(threads[0].id, GetCurrentThreadId());
|
||||
EXPECT_NE(ProgramCounterFromCONTEXT(&threads[0].context.native), nullptr);
|
||||
EXPECT_NE(ProgramCounterFromCONTEXT(threads[0].context.context<CONTEXT>()),
|
||||
nullptr);
|
||||
EXPECT_EQ(threads[0].suspend_count, 0u);
|
||||
}
|
||||
|
||||
|
@ -67,21 +67,25 @@ bool ThreadSnapshotWin::Initialize(
|
||||
#if defined(ARCH_CPU_X86)
|
||||
context_.architecture = kCPUArchitectureX86;
|
||||
context_.x86 = &context_union_.x86;
|
||||
InitializeX86Context(process_reader_thread.context.native, context_.x86);
|
||||
InitializeX86Context(process_reader_thread.context.context<CONTEXT>(),
|
||||
context_.x86);
|
||||
#elif defined(ARCH_CPU_X86_64)
|
||||
if (process_reader->Is64Bit()) {
|
||||
context_.architecture = kCPUArchitectureX86_64;
|
||||
context_.x86_64 = &context_union_.x86_64;
|
||||
InitializeX64Context(process_reader_thread.context.native, context_.x86_64);
|
||||
InitializeX64Context(process_reader_thread.context.context<CONTEXT>(),
|
||||
context_.x86_64);
|
||||
} else {
|
||||
context_.architecture = kCPUArchitectureX86;
|
||||
context_.x86 = &context_union_.x86;
|
||||
InitializeX86Context(process_reader_thread.context.wow64, context_.x86);
|
||||
InitializeX86Context(process_reader_thread.context.context<WOW64_CONTEXT>(),
|
||||
context_.x86);
|
||||
}
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
context_.architecture = kCPUArchitectureARM64;
|
||||
context_.arm64 = &context_union_.arm64;
|
||||
InitializeARM64Context(process_reader_thread.context.native, context_.arm64);
|
||||
InitializeARM64Context(process_reader_thread.context.context<CONTEXT>(),
|
||||
context_.arm64);
|
||||
#else
|
||||
#error Unsupported Windows Arch
|
||||
#endif // ARCH_CPU_X86
|
||||
|
Loading…
x
Reference in New Issue
Block a user