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:
Alex Gough 2022-05-14 22:40:02 -07:00 committed by Crashpad LUCI CQ
parent 4581a355b1
commit a5b7e504c6
9 changed files with 165 additions and 113 deletions

View File

@ -36,12 +36,12 @@ static_assert(sizeof(CPUContextX86::Fsave) ==
#endif // ARCH_CPU_X86 #endif // ARCH_CPU_X86
template <typename T> template <typename T>
bool HasContextPart(const T& context, uint32_t bits) { bool HasContextPart(const T* context, uint32_t bits) {
return (context.ContextFlags & bits) == bits; return (context->ContextFlags & bits) == bits;
} }
template <class T> 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 // This function assumes that the WOW64_CONTEXT_* and x86 CONTEXT_* values
// for ContextFlags are identical. This can be tested when targeting 32-bit // for ContextFlags are identical. This can be tested when targeting 32-bit
// x86. // x86.
@ -72,54 +72,54 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
<< "non-x86 context"; << "non-x86 context";
if (HasContextPart(context, WOW64_CONTEXT_CONTROL)) { if (HasContextPart(context, WOW64_CONTEXT_CONTROL)) {
out->ebp = context.Ebp; out->ebp = context->Ebp;
out->eip = context.Eip; out->eip = context->Eip;
out->cs = static_cast<uint16_t>(context.SegCs); out->cs = static_cast<uint16_t>(context->SegCs);
out->eflags = context.EFlags; out->eflags = context->EFlags;
out->esp = context.Esp; out->esp = context->Esp;
out->ss = static_cast<uint16_t>(context.SegSs); out->ss = static_cast<uint16_t>(context->SegSs);
} }
if (HasContextPart(context, WOW64_CONTEXT_INTEGER)) { if (HasContextPart(context, WOW64_CONTEXT_INTEGER)) {
out->eax = context.Eax; out->eax = context->Eax;
out->ebx = context.Ebx; out->ebx = context->Ebx;
out->ecx = context.Ecx; out->ecx = context->Ecx;
out->edx = context.Edx; out->edx = context->Edx;
out->edi = context.Edi; out->edi = context->Edi;
out->esi = context.Esi; out->esi = context->Esi;
} }
if (HasContextPart(context, WOW64_CONTEXT_SEGMENTS)) { if (HasContextPart(context, WOW64_CONTEXT_SEGMENTS)) {
out->ds = static_cast<uint16_t>(context.SegDs); out->ds = static_cast<uint16_t>(context->SegDs);
out->es = static_cast<uint16_t>(context.SegEs); out->es = static_cast<uint16_t>(context->SegEs);
out->fs = static_cast<uint16_t>(context.SegFs); out->fs = static_cast<uint16_t>(context->SegFs);
out->gs = static_cast<uint16_t>(context.SegGs); out->gs = static_cast<uint16_t>(context->SegGs);
} }
if (HasContextPart(context, WOW64_CONTEXT_DEBUG_REGISTERS)) { if (HasContextPart(context, WOW64_CONTEXT_DEBUG_REGISTERS)) {
out->dr0 = context.Dr0; out->dr0 = context->Dr0;
out->dr1 = context.Dr1; out->dr1 = context->Dr1;
out->dr2 = context.Dr2; out->dr2 = context->Dr2;
out->dr3 = context.Dr3; out->dr3 = context->Dr3;
// DR4 and DR5 are obsolete synonyms for DR6 and DR7, see // DR4 and DR5 are obsolete synonyms for DR6 and DR7, see
// https://en.wikipedia.org/wiki/X86_debug_register. // https://en.wikipedia.org/wiki/X86_debug_register.
out->dr4 = context.Dr6; out->dr4 = context->Dr6;
out->dr5 = context.Dr7; out->dr5 = context->Dr7;
out->dr6 = context.Dr6; out->dr6 = context->Dr6;
out->dr7 = context.Dr7; out->dr7 = context->Dr7;
} }
if (HasContextPart(context, WOW64_CONTEXT_EXTENDED_REGISTERS)) { 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"); "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)) { } else if (HasContextPart(context, WOW64_CONTEXT_FLOATING_POINT)) {
// The static_assert that validates this cast cant be here because it // The static_assert that validates this cast cant be here because it
// relies on field names that vary based on the template parameter. // relies on field names that vary based on the template parameter.
CPUContextX86::FsaveToFxsave( CPUContextX86::FsaveToFxsave(
*reinterpret_cast<const CPUContextX86::Fsave*>(&context.FloatSave), *reinterpret_cast<const CPUContextX86::Fsave*>(&context->FloatSave),
&out->fxsave); &out->fxsave);
} }
} }
@ -128,101 +128,101 @@ void CommonInitializeX86Context(const T& context, CPUContextX86* out) {
#if defined(ARCH_CPU_X86) #if defined(ARCH_CPU_X86)
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out) { void InitializeX86Context(const CONTEXT* context, CPUContextX86* out) {
CommonInitializeX86Context(context, out); CommonInitializeX86Context(context, out);
} }
#elif defined(ARCH_CPU_X86_64) #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); CommonInitializeX86Context(context, out);
} }
void InitializeX64Context(const CONTEXT& context, CPUContextX86_64* out) { void InitializeX64Context(const CONTEXT* context, CPUContextX86_64* out) {
memset(out, 0, sizeof(*out)); memset(out, 0, sizeof(*out));
LOG_IF(ERROR, !HasContextPart(context, CONTEXT_AMD64)) << "non-x64 context"; LOG_IF(ERROR, !HasContextPart(context, CONTEXT_AMD64)) << "non-x64 context";
if (HasContextPart(context, CONTEXT_CONTROL)) { if (HasContextPart(context, CONTEXT_CONTROL)) {
out->cs = context.SegCs; out->cs = context->SegCs;
out->rflags = context.EFlags; out->rflags = context->EFlags;
out->rip = context.Rip; out->rip = context->Rip;
out->rsp = context.Rsp; out->rsp = context->Rsp;
// SegSs ignored. // SegSs ignored.
} }
if (HasContextPart(context, CONTEXT_INTEGER)) { if (HasContextPart(context, CONTEXT_INTEGER)) {
out->rax = context.Rax; out->rax = context->Rax;
out->rbx = context.Rbx; out->rbx = context->Rbx;
out->rcx = context.Rcx; out->rcx = context->Rcx;
out->rdx = context.Rdx; out->rdx = context->Rdx;
out->rdi = context.Rdi; out->rdi = context->Rdi;
out->rsi = context.Rsi; out->rsi = context->Rsi;
out->rbp = context.Rbp; out->rbp = context->Rbp;
out->r8 = context.R8; out->r8 = context->R8;
out->r9 = context.R9; out->r9 = context->R9;
out->r10 = context.R10; out->r10 = context->R10;
out->r11 = context.R11; out->r11 = context->R11;
out->r12 = context.R12; out->r12 = context->R12;
out->r13 = context.R13; out->r13 = context->R13;
out->r14 = context.R14; out->r14 = context->R14;
out->r15 = context.R15; out->r15 = context->R15;
} }
if (HasContextPart(context, CONTEXT_SEGMENTS)) { if (HasContextPart(context, CONTEXT_SEGMENTS)) {
out->fs = context.SegFs; out->fs = context->SegFs;
out->gs = context.SegGs; out->gs = context->SegGs;
// SegDs ignored. // SegDs ignored.
// SegEs ignored. // SegEs ignored.
} }
if (HasContextPart(context, CONTEXT_DEBUG_REGISTERS)) { if (HasContextPart(context, CONTEXT_DEBUG_REGISTERS)) {
out->dr0 = context.Dr0; out->dr0 = context->Dr0;
out->dr1 = context.Dr1; out->dr1 = context->Dr1;
out->dr2 = context.Dr2; out->dr2 = context->Dr2;
out->dr3 = context.Dr3; out->dr3 = context->Dr3;
// DR4 and DR5 are obsolete synonyms for DR6 and DR7, see // DR4 and DR5 are obsolete synonyms for DR6 and DR7, see
// https://en.wikipedia.org/wiki/X86_debug_register. // https://en.wikipedia.org/wiki/X86_debug_register.
out->dr4 = context.Dr6; out->dr4 = context->Dr6;
out->dr5 = context.Dr7; out->dr5 = context->Dr7;
out->dr6 = context.Dr6; out->dr6 = context->Dr6;
out->dr7 = context.Dr7; out->dr7 = context->Dr7;
} }
if (HasContextPart(context, CONTEXT_FLOATING_POINT)) { 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"); "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) #elif defined(ARCH_CPU_ARM64)
void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out) { void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out) {
memset(out, 0, sizeof(*out)); memset(out, 0, sizeof(*out));
LOG_IF(ERROR, !HasContextPart(context, CONTEXT_ARM64)) << "non-arm64 context"; LOG_IF(ERROR, !HasContextPart(context, CONTEXT_ARM64)) << "non-arm64 context";
if (HasContextPart(context, CONTEXT_CONTROL)) { if (HasContextPart(context, CONTEXT_CONTROL)) {
out->spsr = context.Cpsr; out->spsr = context->Cpsr;
out->pc = context.Pc; out->pc = context->Pc;
out->regs[30] = context.Lr; out->regs[30] = context->Lr;
out->sp = context.Sp; out->sp = context->Sp;
out->regs[29] = context.Fp; out->regs[29] = context->Fp;
} }
if (HasContextPart(context, CONTEXT_INTEGER)) { 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. // 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)) { 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"); "types must be equivalent");
memcpy(&out->fpsimd, &context.V, sizeof(out->fpsimd)); memcpy(&out->fpsimd, &context->V, sizeof(out->fpsimd));
} }
} }

View File

@ -29,7 +29,7 @@ struct CPUContextARM64;
//! \brief Initializes a CPUContextX86 structure from a native context structure //! \brief Initializes a CPUContextX86 structure from a native context structure
//! on Windows. //! on Windows.
void InitializeX86Context(const CONTEXT& context, CPUContextX86* out); void InitializeX86Context(const CONTEXT* context, CPUContextX86* out);
#endif // ARCH_CPU_X86 #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 //! \brief Initializes a CPUContextX86 structure from a native context structure
//! on Windows. //! 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 //! \brief Initializes a CPUContextX86_64 structure from a native context
//! structure on Windows. //! 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 #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 //! \brief Initializes a CPUContextARM64 structure from a native context
//! structure on Windows. //! structure on Windows.
void InitializeARM64Context(const CONTEXT& context, CPUContextARM64* out); void InitializeARM64Context(const CONTEXT* context, CPUContextARM64* out);
#endif // ARCH_CPU_ARM64 #endif // ARCH_CPU_ARM64

View File

@ -41,7 +41,7 @@ void TestInitializeX86Context() {
// directly from the supplied thread, float, and debug state parameters. // directly from the supplied thread, float, and debug state parameters.
{ {
CPUContextX86 cpu_context_x86 = {}; 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.eax, 1u);
EXPECT_EQ(cpu_context_x86.fxsave.ftw, 2u); EXPECT_EQ(cpu_context_x86.fxsave.ftw, 2u);
EXPECT_EQ(cpu_context_x86.dr0, 3u); EXPECT_EQ(cpu_context_x86.dr0, 3u);
@ -73,7 +73,7 @@ void TestInitializeX86Context_FsaveWithoutFxsave() {
{ {
CPUContextX86 cpu_context_x86 = {}; 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.eax, 1u);
@ -117,7 +117,7 @@ TEST(CPUContextWin, InitializeX64Context) {
// set directly from the supplied thread, float, and debug state parameters. // set directly from the supplied thread, float, and debug state parameters.
{ {
CPUContextX86_64 cpu_context_x86_64 = {}; 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.rax, 10u);
EXPECT_EQ(cpu_context_x86_64.fxsave.ftw, 11u); EXPECT_EQ(cpu_context_x86_64.fxsave.ftw, 11u);
EXPECT_EQ(cpu_context_x86_64.dr0, 12u); EXPECT_EQ(cpu_context_x86_64.dr0, 12u);

View File

@ -36,7 +36,7 @@ using Context32 = CONTEXT;
using Context32 = WOW64_CONTEXT; using Context32 = WOW64_CONTEXT;
#endif #endif
void NativeContextToCPUContext32(const Context32& context_record, void NativeContextToCPUContext32(const Context32* context_record,
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union) { CPUContextUnion* context_union) {
context->architecture = kCPUArchitectureX86; context->architecture = kCPUArchitectureX86;
@ -46,7 +46,7 @@ void NativeContextToCPUContext32(const Context32& context_record,
#endif // ARCH_CPU_X86_FAMILY #endif // ARCH_CPU_X86_FAMILY
#if defined(ARCH_CPU_64_BITS) #if defined(ARCH_CPU_64_BITS)
void NativeContextToCPUContext64(const CONTEXT& context_record, void NativeContextToCPUContext64(const CONTEXT* context_record,
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union) { CPUContextUnion* context_union) {
#if defined(ARCH_CPU_X86_64) #if defined(ARCH_CPU_X86_64)
@ -190,7 +190,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
ProcessReaderWin* process_reader, ProcessReaderWin* process_reader,
WinVMAddress exception_pointers_address, WinVMAddress exception_pointers_address,
DWORD exception_thread_id, DWORD exception_thread_id,
void (*native_to_cpu_context)(const ContextType& context_record, void (*native_to_cpu_context)(const ContextType* context_record,
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union)) { CPUContextUnion* context_union)) {
ExceptionPointersType exception_pointers; ExceptionPointersType exception_pointers;
@ -232,10 +232,9 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
for (const auto& thread : process_reader->Threads()) { for (const auto& thread : process_reader->Threads()) {
if (thread.id == blame_thread_id) { if (thread.id == blame_thread_id) {
thread_id_ = blame_thread_id; thread_id_ = blame_thread_id;
native_to_cpu_context( native_to_cpu_context(thread.context.context<const ContextType>(),
*reinterpret_cast<const ContextType*>(&thread.context), &context_,
&context_, &context_union_);
&context_union_);
exception_address_ = context_.InstructionPointer(); exception_address_ = context_.InstructionPointer();
break; break;
} }
@ -266,7 +265,7 @@ bool ExceptionSnapshotWin::InitializeFromExceptionPointers(
return false; return false;
} }
native_to_cpu_context(context_record, &context_, &context_union_); native_to_cpu_context(&context_record, &context_, &context_union_);
} }
return true; return true;

View File

@ -93,7 +93,7 @@ class ExceptionSnapshotWin final : public ExceptionSnapshot {
ProcessReaderWin* process_reader, ProcessReaderWin* process_reader,
WinVMAddress exception_pointers_address, WinVMAddress exception_pointers_address,
DWORD exception_thread_id, DWORD exception_thread_id,
void (*native_to_cpu_context)(const ContextType& context_record, void (*native_to_cpu_context)(const ContextType* context_record,
CPUContext* context, CPUContext* context,
CPUContextUnion* context_union)); CPUContextUnion* context_union));

View File

@ -143,7 +143,7 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
DCHECK(suspension_state == ProcessSuspensionState::kRunning); DCHECK(suspension_state == ProcessSuspensionState::kRunning);
thread->suspend_count = 0; thread->suspend_count = 0;
DCHECK(!is_64_reading_32); DCHECK(!is_64_reading_32);
CaptureContext(&thread->context.native); thread->context.InitializeFromCurrentThread();
} else { } else {
DWORD previous_suspend_count = SuspendThread(thread_handle); DWORD previous_suspend_count = SuspendThread(thread_handle);
if (previous_suspend_count == static_cast<DWORD>(-1)) { if (previous_suspend_count == static_cast<DWORD>(-1)) {
@ -162,25 +162,18 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
(suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0); (suspension_state == ProcessSuspensionState::kSuspended ? 1 : 0);
} }
memset(&thread->context, 0, sizeof(thread->context));
#if defined(ARCH_CPU_32_BITS) #if defined(ARCH_CPU_32_BITS)
const bool is_native = true; const bool is_native = true;
#elif defined(ARCH_CPU_64_BITS) #elif defined(ARCH_CPU_64_BITS)
const bool is_native = !is_64_reading_32; const bool is_native = !is_64_reading_32;
if (is_64_reading_32) { if (is_64_reading_32) {
thread->context.wow64.ContextFlags = CONTEXT_ALL; if (!thread->context.InitializeWow64(thread_handle))
if (!Wow64GetThreadContext(thread_handle, &thread->context.wow64)) {
PLOG(ERROR) << "Wow64GetThreadContext";
return false; return false;
}
} }
#endif #endif
if (is_native) { if (is_native) {
thread->context.native.ContextFlags = CONTEXT_ALL; if (!thread->context.InitializeNative(thread_handle))
if (!GetThreadContext(thread_handle, &thread->context.native)) {
PLOG(ERROR) << "GetThreadContext";
return false; return false;
}
} }
if (!ResumeThread(thread_handle)) { if (!ResumeThread(thread_handle)) {
@ -194,6 +187,39 @@ bool FillThreadContextAndSuspendCount(HANDLE thread_handle,
} // namespace } // 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() ProcessReaderWin::Thread::Thread()
: context(), : context(),
id(0), id(0),
@ -203,8 +229,7 @@ ProcessReaderWin::Thread::Thread()
stack_region_size(0), stack_region_size(0),
suspend_count(0), suspend_count(0),
priority_class(0), priority_class(0),
priority(0) { priority(0) {}
}
ProcessReaderWin::ProcessReaderWin() ProcessReaderWin::ProcessReaderWin()
: process_(INVALID_HANDLE_VALUE), : process_(INVALID_HANDLE_VALUE),

View File

@ -40,17 +40,39 @@ enum class ProcessSuspensionState : bool {
//! \brief Accesses information about another process, identified by a `HANDLE`. //! \brief Accesses information about another process, identified by a `HANDLE`.
class ProcessReaderWin { class ProcessReaderWin {
public: 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. //! \brief Contains information about a thread that belongs to a process.
struct Thread { struct Thread {
Thread(); Thread();
~Thread() {} ~Thread() {}
union { ThreadContext context;
CONTEXT native;
#if defined(ARCH_CPU_64_BITS)
WOW64_CONTEXT wow64;
#endif
} context;
uint64_t id; uint64_t id;
WinVMAddress teb_address; WinVMAddress teb_address;
WinVMSize teb_size; WinVMSize teb_size;

View File

@ -111,7 +111,8 @@ TEST(ProcessReaderWin, SelfOneThread) {
ASSERT_GE(threads.size(), 1u); ASSERT_GE(threads.size(), 1u);
EXPECT_EQ(threads[0].id, GetCurrentThreadId()); 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); EXPECT_EQ(threads[0].suspend_count, 0u);
} }

View File

@ -67,21 +67,25 @@ bool ThreadSnapshotWin::Initialize(
#if defined(ARCH_CPU_X86) #if defined(ARCH_CPU_X86)
context_.architecture = kCPUArchitectureX86; context_.architecture = kCPUArchitectureX86;
context_.x86 = &context_union_.x86; 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) #elif defined(ARCH_CPU_X86_64)
if (process_reader->Is64Bit()) { if (process_reader->Is64Bit()) {
context_.architecture = kCPUArchitectureX86_64; context_.architecture = kCPUArchitectureX86_64;
context_.x86_64 = &context_union_.x86_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 { } else {
context_.architecture = kCPUArchitectureX86; context_.architecture = kCPUArchitectureX86;
context_.x86 = &context_union_.x86; 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) #elif defined(ARCH_CPU_ARM64)
context_.architecture = kCPUArchitectureARM64; context_.architecture = kCPUArchitectureARM64;
context_.arm64 = &context_union_.arm64; context_.arm64 = &context_union_.arm64;
InitializeARM64Context(process_reader_thread.context.native, context_.arm64); InitializeARM64Context(process_reader_thread.context.context<CONTEXT>(),
context_.arm64);
#else #else
#error Unsupported Windows Arch #error Unsupported Windows Arch
#endif // ARCH_CPU_X86 #endif // ARCH_CPU_X86