dbg_engine: shift thread register reads / process memory reads -> abstraction layer, rather than directly calling into demon; cache crash dump info, like thread info & memory ranges; implement thread reg reads & memory reads for dumps by using this acceleration structure when we have a dump handle, instead of regular demon reads.

This commit is contained in:
Ryan Fleury
2026-05-18 14:51:17 -07:00
parent 463a4f8565
commit 4840b46b84
23 changed files with 1035 additions and 401 deletions
+1 -1
View File
@@ -607,7 +607,7 @@ w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block)
}
//- rjf: unpack features available on this context
if (xstate_enabled)
if(xstate_enabled)
{
SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX | XSTATE_MASK_AVX512 | XSTATE_MASK_CET_U);
}
+6
View File
@@ -0,0 +1,6 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#if defined(X64_H)
# include "win32/x64/win32_x64.c"
#endif
+11
View File
@@ -0,0 +1,11 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_INC_H
#define WIN32_INC_H
#if defined(X64_H)
# include "win32/x64/win32_x64.h"
#endif
#endif // WIN32_INC_H
+139
View File
@@ -0,0 +1,139 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal B32
w32_x64_write_reg_block_from_thread_ctx(void *reg_block, void *thread_ctx)
{
X64_RegBlock *dst = (X64_RegBlock *)reg_block;
W32_X64_ThreadContext *src = (W32_X64_ThreadContext *)thread_ctx;
//- rjf: convert context -> X64_RegBlock
W32_X64_XSaveFormat *xsave = &src->FltSave;
dst->rax = src->Rax;
dst->rcx = src->Rcx;
dst->rdx = src->Rdx;
dst->rbx = src->Rbx;
dst->rsp = src->Rsp;
dst->rbp = src->Rbp;
dst->rsi = src->Rsi;
dst->rdi = src->Rdi;
dst->r8 = src->R8;
dst->r9 = src->R9;
dst->r10 = src->R10;
dst->r11 = src->R11;
dst->r12 = src->R12;
dst->r13 = src->R13;
dst->r14 = src->R14;
dst->r15 = src->R15;
dst->rip = src->Rip;
dst->cs = src->SegCs;
dst->ds = src->SegDs;
dst->es = src->SegEs;
dst->fs = src->SegFs;
dst->gs = src->SegGs;
dst->ss = src->SegSs;
dst->dr0 = src->Dr0;
dst->dr1 = src->Dr1;
dst->dr2 = src->Dr2;
dst->dr3 = src->Dr3;
dst->dr6 = src->Dr6;
dst->dr7 = src->Dr7;
// NOTE(rjf): this bit is "supposed to always be 1", according to old info.
// may need to be investigated.
dst->rflags = src->EFlags | 0x2;
dst->fcw = xsave->ControlWord;
dst->fsw = xsave->StatusWord;
dst->ftw = xsave->TagWord;
dst->fop = xsave->ErrorOpcode;
MemoryCopy(&dst->fip, &xsave->ErrorOffset, sizeof(U64));
MemoryCopy(&dst->fdp, &xsave->DataOffset, sizeof(U64));
dst->mxcsr = xsave->MxCsr;
dst->mxcsr_mask = xsave->MxCsr_Mask;
{
U128 *float_s = xsave->FloatRegisters;
U80 *float_d = &dst->st0;
for(U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1)
{
MemoryCopy(float_d, float_s, sizeof(*float_d));
}
}
{
U128 *xmm_s = xsave->XmmRegisters;
U512 *zmm_d = &dst->zmm0;
for(U32 n = 0; n < 16; n += 1, xmm_s += 1, zmm_d += 1)
{
MemoryCopy(zmm_d, xmm_s, sizeof(*xmm_s));
}
}
// TODO(rjf): we need to determine how to do LocateXStateFeature without
// actually running on Windows - what is that function actually looking at
// & doing?
#if 0
// AVX
{
DWORD avx_length = 0;
U8 *avx_s = (U8 *)LocateXStateFeature(ctx, XSTATE_AVX, &avx_length);
if(avx_length == 16 * sizeof(U128))
{
U512 *zmm_d = &dst->zmm0;
for(U32 n = 0; n < 16; n += 1, avx_s += sizeof(U128), zmm_d += 1)
{
MemoryCopy(&zmm_d->u8[16], avx_s, sizeof(U128));
}
}
}
// AVX-512
{
// rjf: kmask
DWORD kmask_length = 0;
U64 *kmask_s = (U64*)LocateXStateFeature(ctx, XSTATE_AVX512_KMASK, &kmask_length);
if(kmask_length == 8 * sizeof(U64))
{
U64 *kmask_d = &dst->k0;
for(U32 n = 0; n < 8; n += 1, kmask_s += 1, kmask_d += 1)
{
MemoryCopy(kmask_d, kmask_s, sizeof(*kmask_s));
}
}
// rjf: zmmh
DWORD avx512h_length = 0;
U8 *avx512h_s = (U8*)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM_H, &avx512h_length);
if(avx512h_length == 16 * sizeof(U256))
{
U512 *zmmh_d = &dst->zmm0;
for(U32 n = 0; n < 16; n += 1, avx512h_s += sizeof(U256), zmmh_d += 1)
{
MemoryCopy(&zmmh_d->u8[32], avx512h_s, sizeof(U256));
}
}
// rjf: zmm
DWORD avx512_length = 0;
U8 *avx512_s = (U8 *)LocateXStateFeature(ctx, XSTATE_AVX512_ZMM, &avx512_length);
if(avx512_length == 16 * sizeof(U512))
{
U512 *zmm_d = &dst->zmm16;
for(U32 n = 0; n < 16; n += 1, avx512_s += sizeof(U512), zmm_d += 1)
{
MemoryCopy(zmm_d, avx512_s, sizeof(U512));
}
}
}
// CET / Shadow Stack
if(xstate_mask & XSTATE_MASK_CET_U)
{
DWORD cet_length = 0;
XSAVE_CET_U_FORMAT *cet = LocateXStateFeature(ctx, XSTATE_CET_U, &cet_length);
if (cet_length == sizeof(*cet))
{
dst->cetmsr = cet->Ia32CetUMsr;
dst->cetssp = cet->Ia32Pl3SspMsr;
}
}
#endif
return 1;
}
+110
View File
@@ -0,0 +1,110 @@
// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
#ifndef WIN32_X64_H
#define WIN32_X64_H
#pragma pack(push, 1)
typedef struct W32_X64_XSaveFormat W32_X64_XSaveFormat;
struct W32_X64_XSaveFormat
{
U16 ControlWord;
U16 StatusWord;
U8 TagWord;
U8 Reserved1;
U16 ErrorOpcode;
U32 ErrorOffset;
U16 ErrorSelector;
U16 Reserved2;
U32 DataOffset;
U16 DataSelector;
U16 Reserved3;
U32 MxCsr;
U32 MxCsr_Mask;
U128 FloatRegisters[8];
U128 XmmRegisters[16];
U8 Reserved4[96];
};
typedef struct W32_X64_ThreadContext W32_X64_ThreadContext;
struct W32_X64_ThreadContext
{
U64 P1Home;
U64 P2Home;
U64 P3Home;
U64 P4Home;
U64 P5Home;
U64 P6Home;
U32 ContextFlags;
U32 MxCsr;
U16 SegCs;
U16 SegDs;
U16 SegEs;
U16 SegFs;
U16 SegGs;
U16 SegSs;
U32 EFlags;
U64 Dr0;
U64 Dr1;
U64 Dr2;
U64 Dr3;
U64 Dr6;
U64 Dr7;
U64 Rax;
U64 Rcx;
U64 Rdx;
U64 Rbx;
U64 Rsp;
U64 Rbp;
U64 Rsi;
U64 Rdi;
U64 R8;
U64 R9;
U64 R10;
U64 R11;
U64 R12;
U64 R13;
U64 R14;
U64 R15;
U64 Rip;
union
{
W32_X64_XSaveFormat FltSave;
struct
{
U128 Header[2];
U128 Legacy[8];
U128 Xmm0;
U128 Xmm1;
U128 Xmm2;
U128 Xmm3;
U128 Xmm4;
U128 Xmm5;
U128 Xmm6;
U128 Xmm7;
U128 Xmm8;
U128 Xmm9;
U128 Xmm10;
U128 Xmm11;
U128 Xmm12;
U128 Xmm13;
U128 Xmm14;
U128 Xmm15;
U8 padding_0[96];
};
};
U128 VectorRegister[26];
U64 VectorControl;
U64 DebugControl;
U64 LastBranchToRip;
U64 LastBranchFromRip;
U64 LastExceptionToRip;
U64 LastExceptionFromRip;
};
#pragma pack(pop)
internal B32 w32_x64_write_reg_block_from_thread_ctx(void *reg_block, void *thread_ctx);
#endif // WIN32_X64_H