Files
raddebugger/src/x64/x64.c
T

185 lines
6.3 KiB
C

// Copyright (c) Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
internal void
x64_cpuid(U32 leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx)
{
U32 info[4] = {0};
#if COMPILER_MSVC
__cpuid(info, leaf);
if (eax) { *eax = info[0]; }
if (ebx) { *ebx = info[1]; }
if (ecx) { *ecx = info[2]; }
if (edx) { *edx = info[3]; }
#elif COMPILER_CLANG || COMPILER_GCC
if (!eax) { eax = &info[0]; }
if (!ebx) { ebx = &info[1]; }
if (!ecx) { ecx = &info[2]; }
if (!edx) { edx = &info[3]; }
__get_cpuid(leaf, eax, ebx, ecx, edx);
#else
# error "cpuid is not defined for this compiler"
#endif
}
internal void
x64_cpuid_ex(U32 leaf, U32 sub_leaf, U32 *eax, U32 *ebx, U32 *ecx, U32 *edx)
{
U32 info[4];
#if COMPILER_MSVC
__cpuidex(info, leaf, sub_leaf);
if (eax) { *eax = info[0]; }
if (ebx) { *ebx = info[1]; }
if (ecx) { *ecx = info[2]; }
if (edx) { *edx = info[3]; }
#elif COMPILER_CLANG || COMPILER_GCC
if (!eax) { eax = &info[0]; }
if (!ebx) { ebx = &info[1]; }
if (!ecx) { ecx = &info[2]; }
if (!edx) { edx = &info[3]; }
__get_cpuid_count(leaf, sub_leaf, eax, ebx, ecx, edx);
#else
# error "cpuid_count is not defined for this compiler"
#endif
}
internal B32
x64_is_xsave_supported(void)
{
U32 ecx = 0;
x64_cpuid(1, 0, 0, &ecx, 0);
return !!(ecx & (1 << 26));
}
internal U32
x64_get_xsave_size(void)
{
U32 xsave_size = 0;
x64_cpuid_ex(0xd, 0, 0, &xsave_size, 0, 0);
return xsave_size;
}
internal U16
x64_xsave_tag_word_from_real_tag_word(U16 ftw)
{
U16 compact = 0;
for EachIndex(fpr, 8) {
U32 tag = (ftw >> (fpr * 2)) & 3;
if (tag != 3) {
compact |= (1 << fpr);
}
}
return compact;
}
internal U32
x64_xsave_offset_from_feature_flag(U64 xcr0, X64_XStateComponentIdx comp_idx)
{
U32 offset = 0;
if (xcr0 & (1 << comp_idx)) {
if(comp_idx == X64_XStateComponentIdx_FP) {
offset = 0;
} else if(comp_idx == X64_XStateComponentIdx_SSE) {
offset = 160;
} else {
x64_cpuid_ex(0xd, comp_idx, 0, &offset, 0, 0);
}
}
return offset;
}
internal X64_XSaveLayout
x64_get_xsave_layout(U64 xcr0)
{
X64_XSaveLayout xsave_layout = {0};
xsave_layout.x87_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_FP);
xsave_layout.sse_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_SSE);
xsave_layout.avx_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_AVX);
xsave_layout.bndregs_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_BNDREGS);
xsave_layout.bndcfg_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_BNDCSR);
xsave_layout.opmask_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_OPMASK);
xsave_layout.zmm_h_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_ZMM_H);
xsave_layout.zmm_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_ZMM);
xsave_layout.pt_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PT);
xsave_layout.pkru_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PKRU);
xsave_layout.pasid_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_PASID);
xsave_layout.cet_u_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_CETU);
xsave_layout.cet_s_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_CETS);
xsave_layout.hdc_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_HDC);
xsave_layout.uintr_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_UINTR);
xsave_layout.lbr_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_LBR);
xsave_layout.hwp_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_HWP);
xsave_layout.tile_cfg_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_TILECFG);
xsave_layout.tile_data_offset = x64_xsave_offset_from_feature_flag(xcr0, X64_XStateComponentIdx_TILEDATA);
return xsave_layout;
}
internal void
x64_set_debug_break(U64 *drs, U64 trap_idx, U64 addr, U64 size, X64_BreakpointType bp_type, X64_DebugBreakType break_type)
{
// set breakpoint address
switch (trap_idx) {
case 0: { drs[0] = addr; } break;
case 1: { drs[1] = addr; } break;
case 2: { drs[2] = addr; } break;
case 3: { drs[3] = addr; } break;
default: { InvalidPath; } break;
}
// enable breakpoint
drs[7] &= ~(3 << (trap_idx * 2));
switch (bp_type)
{
case X64_BreakpointType_Null: break;
case X64_BreakpointType_Local: { drs[7] |= 1 << (trap_idx * 2); } break;
case X64_BreakpointType_Global: { drs[7] |= 2 << (trap_idx * 2); } break;
default: { InvalidPath; } break;
}
// set break access type
switch (break_type) {
case X64_DebugBreakType_Exec:
Assert(size == 0);
case X64_DebugBreakType_Null: {
drs[7] &= ~((1ull << 16) << (trap_idx * 4));
drs[7] &= ~((1ull << 17) << (trap_idx * 4));
} break;
case X64_DebugBreakType_Write: {
drs[7] |= (1ull << 16) << (trap_idx * 4);
drs[7] &= ~((1ull << 17) << (trap_idx * 4));
} break;
case X64_DebugBreakType_ReadWriteIO: {
drs[7] &= ~((1ull << 16) << (trap_idx * 4));
drs[7] |= (1ull << 17) << (trap_idx * 4);
} break;
case X64_DebugBreakType_ReadWriteNoFetch: {
drs[7] |= (1u << 16) << (trap_idx * 4);
drs[7] |= (1u << 17) << (trap_idx * 4);
} break;
default: { InvalidPath; } break;
}
// set breakpoint size
switch (size) {
case 0:
case 1: {
drs[7] &= ~((1ull << 18) << (trap_idx * 4));
drs[7] &= ~((1ull << 19) << (trap_idx * 4));
} break;
case 2: {
drs[7] |= (1 << 18) << (trap_idx * 4);
drs[7] &= ~((1 << 19) << (trap_idx * 4));
} break;
case 4: {
drs[7] |= (1 << 18) << (trap_idx * 4);
drs[7] |= (1 << 19) << (trap_idx * 4);
} break;
case 8: {
drs[7] &= ~((1 << 18) << (trap_idx * 4));
drs[7] |= (1 << 19) << (trap_idx * 4);
} break;
default: { InvalidPath; }
}
}