From f60b349853f166d0ce23f4e79055af53494157e4 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 10:42:56 -0700 Subject: [PATCH 01/26] remove dt context --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 631 +++++++++- src/coreclr/debug/daccess/dacdbiimpl.h | 35 +- .../debug/daccess/dacdbiimplstackwalk.cpp | 27 +- src/coreclr/debug/di/CMakeLists.txt | 21 +- .../debug/di/amd64/FloatConversion.asm | 19 - .../debug/di/amd64/cordbregisterset.cpp | 217 ---- src/coreclr/debug/di/amd64/floatconversion.S | 10 - src/coreclr/debug/di/arm/cordbregisterset.cpp | 117 -- src/coreclr/debug/di/arm/floatconversion.S | 14 - .../debug/di/arm64/cordbregisterset.cpp | 241 ---- src/coreclr/debug/di/arm64/floatconversion.S | 13 - .../debug/di/arm64/floatconversion.asm | 16 - src/coreclr/debug/di/cordb.cpp | 16 +- .../debug/di/i386/cordbregisterset.cpp | 191 --- .../debug/di/loongarch64/cordbregisterset.cpp | 269 ---- .../debug/di/loongarch64/floatconversion.S | 12 - src/coreclr/debug/di/module.cpp | 9 +- src/coreclr/debug/di/platformspecific.cpp | 6 - src/coreclr/debug/di/process.cpp | 182 ++- .../debug/di/riscv64/cordbregisterset.cpp | 107 -- .../debug/di/riscv64/floatconversion.S | 12 - src/coreclr/debug/di/rspriv.h | 129 +- src/coreclr/debug/di/rsregsetcommon.cpp | 142 +-- src/coreclr/debug/di/rsstackwalk.cpp | 98 +- src/coreclr/debug/di/rsthread.cpp | 1115 +++-------------- src/coreclr/debug/di/shimlocaldatatarget.cpp | 4 +- src/coreclr/debug/di/shimpriv.h | 35 +- src/coreclr/debug/di/shimstackwalk.cpp | 89 +- src/coreclr/debug/di/stdafx.h | 9 +- src/coreclr/debug/di/valuehome.cpp | 338 +---- src/coreclr/debug/ee/controller.cpp | 10 +- src/coreclr/debug/ee/debugger.cpp | 4 +- src/coreclr/debug/inc/amd64/primitives.h | 16 +- src/coreclr/debug/inc/arm/primitives.h | 5 +- src/coreclr/debug/inc/arm64/primitives.h | 11 +- src/coreclr/debug/inc/arm_primitives.h | 4 +- src/coreclr/debug/inc/common.h | 2 +- src/coreclr/debug/inc/dacdbiinterface.h | 103 +- src/coreclr/debug/inc/dacdbistructures.h | 2 +- src/coreclr/debug/inc/dbgipcevents.h | 45 +- src/coreclr/debug/inc/i386/primitives.h | 12 +- .../debug/inc/loongarch64/primitives.h | 6 +- src/coreclr/debug/inc/riscv64/primitives.h | 6 +- src/coreclr/debug/shared/amd64/primitives.cpp | 2 +- src/coreclr/debug/shared/arm/primitives.cpp | 20 +- src/coreclr/debug/shared/arm64/primitives.cpp | 22 +- src/coreclr/debug/shared/i386/primitives.cpp | 30 +- .../debug/shared/loongarch64/primitives.cpp | 22 +- .../debug/shared/riscv64/primitives.cpp | 24 +- src/coreclr/inc/dacdbi.idl | 64 +- .../StackWalk/Context/AMD64Context.cs | 68 +- .../StackWalk/Context/ARM64Context.cs | 51 +- .../Contracts/StackWalk/Context/ARMContext.cs | 34 +- .../StackWalk/Context/ContextHolder.cs | 5 + .../Context/IPlatformAgnosticContext.cs | 9 + .../StackWalk/Context/IPlatformContext.cs | 7 + .../StackWalk/Context/LoongArch64Context.cs | 64 +- .../StackWalk/Context/RISCV64Context.cs | 51 +- .../StackWalk/Context/RegisterAttribute.cs | 1 + .../Contracts/StackWalk/Context/X86Context.cs | 44 +- .../Dbi/DacDbiImpl.cs | 787 ++++++++++++ .../Dbi/IDacDbiInterface.cs | 211 +++- 62 files changed, 2851 insertions(+), 3015 deletions(-) delete mode 100644 src/coreclr/debug/di/amd64/FloatConversion.asm delete mode 100644 src/coreclr/debug/di/amd64/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/amd64/floatconversion.S delete mode 100644 src/coreclr/debug/di/arm/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/arm/floatconversion.S delete mode 100644 src/coreclr/debug/di/arm64/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/arm64/floatconversion.S delete mode 100644 src/coreclr/debug/di/arm64/floatconversion.asm delete mode 100644 src/coreclr/debug/di/i386/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/loongarch64/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/loongarch64/floatconversion.S delete mode 100644 src/coreclr/debug/di/riscv64/cordbregisterset.cpp delete mode 100644 src/coreclr/debug/di/riscv64/floatconversion.S diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 6fc569b45554c2..29d3e8658c1e4c 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -4955,7 +4955,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::Hijack(VMPTR_Thread vmThread, ULO // // The debugger could always re-enable the single-step flag if it wants to. #ifndef FEATURE_EMULATE_SINGLESTEP - UnsetSSFlag(reinterpret_cast(&ctx)); + UnsetSSFlag(&ctx); #endif // Push pointers @@ -5489,7 +5489,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetDebuggerControlBlockAddress(OU } // DacDbi API: Get the context for a particular thread of the target process -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, BYTE * pContextBufferRaw) { DD_ENTER_MAY_THROW @@ -5497,7 +5497,9 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, EX_TRY { - _ASSERTE(pContextBuffer != NULL); + _ASSERTE(pContextBufferRaw != NULL); + + DT_CONTEXT * pContextBuffer = reinterpret_cast(pContextBufferRaw); Thread * pThread = vmThread.GetDacPtr(); @@ -5571,6 +5573,629 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, return hr; } +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize) +{ + DD_ENTER_MAY_THROW; + + if (pSize == NULL) + return E_INVALIDARG; + + switch (flags) + { + case kContextSizeBase: +#if defined(DT_CONTEXT_EXTENDED_REGISTERS) + *pSize = offsetof(DT_CONTEXT, ExtendedRegisters); +#else + *pSize = sizeof(DT_CONTEXT); +#endif + break; + + case kContextSizeExtendedRegisters: + *pSize = sizeof(DT_CONTEXT); + break; + + default: + return E_INVALIDARG; + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetInfo(OUT TargetInfo * pTargetInfo) +{ + DD_ENTER_MAY_THROW; + + if (pTargetInfo == NULL) + return E_INVALIDARG; + +#if defined(TARGET_X86) + pTargetInfo->arch = kArchX86; +#elif defined(TARGET_AMD64) + pTargetInfo->arch = kArchAMD64; +#elif defined(TARGET_ARM) + pTargetInfo->arch = kArchArm; +#elif defined(TARGET_ARM64) + pTargetInfo->arch = kArchArm64; +#elif defined(TARGET_LOONGARCH64) + pTargetInfo->arch = kArchLoongArch64; +#elif defined(TARGET_RISCV64) + pTargetInfo->arch = kArchRiscV64; +#elif defined(TARGET_WASM) + pTargetInfo->arch = kArchWasm; +#else + pTargetInfo->arch = kArchUnknown; +#endif + +#if defined(TARGET_UNIX) + pTargetInfo->os = kOSUnix; +#elif defined(TARGET_WINDOWS) + pTargetInfo->os = kOSWindows; +#else + pTargetInfo->os = kOSUnknown; +#endif + + return S_OK; +} + +static UINT_PTR * GetRegisterSlotFromContext(BYTE * ctxBuf, CorDebugRegister reg) +{ + DT_CONTEXT * pCtx = (DT_CONTEXT *)ctxBuf; + +#if defined(TARGET_X86) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Eip; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Esp; + case REGISTER_FRAME_POINTER: return (UINT_PTR *)&pCtx->Ebp; + case REGISTER_X86_EAX: return (UINT_PTR *)&pCtx->Eax; + case REGISTER_X86_ECX: return (UINT_PTR *)&pCtx->Ecx; + case REGISTER_X86_EDX: return (UINT_PTR *)&pCtx->Edx; + case REGISTER_X86_EBX: return (UINT_PTR *)&pCtx->Ebx; + case REGISTER_X86_ESI: return (UINT_PTR *)&pCtx->Esi; + case REGISTER_X86_EDI: return (UINT_PTR *)&pCtx->Edi; + default: return NULL; + } +#elif defined(TARGET_AMD64) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Rip; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Rsp; + case REGISTER_AMD64_RBP: return (UINT_PTR *)&pCtx->Rbp; + case REGISTER_AMD64_RAX: return (UINT_PTR *)&pCtx->Rax; + case REGISTER_AMD64_RCX: return (UINT_PTR *)&pCtx->Rcx; + case REGISTER_AMD64_RDX: return (UINT_PTR *)&pCtx->Rdx; + case REGISTER_AMD64_RBX: return (UINT_PTR *)&pCtx->Rbx; + case REGISTER_AMD64_RSI: return (UINT_PTR *)&pCtx->Rsi; + case REGISTER_AMD64_RDI: return (UINT_PTR *)&pCtx->Rdi; + case REGISTER_AMD64_R8: return (UINT_PTR *)&pCtx->R8; + case REGISTER_AMD64_R9: return (UINT_PTR *)&pCtx->R9; + case REGISTER_AMD64_R10: return (UINT_PTR *)&pCtx->R10; + case REGISTER_AMD64_R11: return (UINT_PTR *)&pCtx->R11; + case REGISTER_AMD64_R12: return (UINT_PTR *)&pCtx->R12; + case REGISTER_AMD64_R13: return (UINT_PTR *)&pCtx->R13; + case REGISTER_AMD64_R14: return (UINT_PTR *)&pCtx->R14; + case REGISTER_AMD64_R15: return (UINT_PTR *)&pCtx->R15; + default: return NULL; + } +#elif defined(TARGET_ARM) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Pc; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Sp; + case REGISTER_ARM_R0: return (UINT_PTR *)&pCtx->R0; + case REGISTER_ARM_R1: return (UINT_PTR *)&pCtx->R1; + case REGISTER_ARM_R2: return (UINT_PTR *)&pCtx->R2; + case REGISTER_ARM_R3: return (UINT_PTR *)&pCtx->R3; + case REGISTER_ARM_R4: return (UINT_PTR *)&pCtx->R4; + case REGISTER_ARM_R5: return (UINT_PTR *)&pCtx->R5; + case REGISTER_ARM_R6: return (UINT_PTR *)&pCtx->R6; + case REGISTER_ARM_R7: return (UINT_PTR *)&pCtx->R7; + case REGISTER_ARM_R8: return (UINT_PTR *)&pCtx->R8; + case REGISTER_ARM_R9: return (UINT_PTR *)&pCtx->R9; + case REGISTER_ARM_R10: return (UINT_PTR *)&pCtx->R10; + case REGISTER_ARM_R11: return (UINT_PTR *)&pCtx->R11; + case REGISTER_ARM_R12: return (UINT_PTR *)&pCtx->R12; + case REGISTER_ARM_LR: return (UINT_PTR *)&pCtx->Lr; + default: return NULL; + } +#elif defined(TARGET_ARM64) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Pc; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Sp; + case REGISTER_ARM64_FP: return (UINT_PTR *)&pCtx->Fp; + case REGISTER_ARM64_LR: return (UINT_PTR *)&pCtx->Lr; + default: + if (reg >= REGISTER_ARM64_X0 && reg <= REGISTER_ARM64_X28) + return (UINT_PTR *)&pCtx->X[reg - REGISTER_ARM64_X0]; + return NULL; + } +#elif defined(TARGET_LOONGARCH64) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Pc; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Sp; + case REGISTER_LOONGARCH64_FP: return (UINT_PTR *)&pCtx->Fp; + case REGISTER_LOONGARCH64_RA: return (UINT_PTR *)&pCtx->Ra; + case REGISTER_LOONGARCH64_TP: return (UINT_PTR *)&pCtx->Tp; + case REGISTER_LOONGARCH64_X0: return (UINT_PTR *)&pCtx->X0; + default: + if (reg >= REGISTER_LOONGARCH64_A0 && reg <= REGISTER_LOONGARCH64_A7) + return (UINT_PTR *)&pCtx->A0 + (reg - REGISTER_LOONGARCH64_A0); + if (reg >= REGISTER_LOONGARCH64_T0 && reg <= REGISTER_LOONGARCH64_T8) + return (UINT_PTR *)&pCtx->T0 + (reg - REGISTER_LOONGARCH64_T0); + if (reg >= REGISTER_LOONGARCH64_S0 && reg <= REGISTER_LOONGARCH64_S8) + return (UINT_PTR *)&pCtx->S0 + (reg - REGISTER_LOONGARCH64_S0); + return NULL; + } +#elif defined(TARGET_RISCV64) + switch (reg) + { + case REGISTER_INSTRUCTION_POINTER: return (UINT_PTR *)&pCtx->Pc; + case REGISTER_STACK_POINTER: return (UINT_PTR *)&pCtx->Sp; + case REGISTER_RISCV64_FP: return (UINT_PTR *)&pCtx->Fp; + case REGISTER_RISCV64_RA: return (UINT_PTR *)&pCtx->Ra; + case REGISTER_RISCV64_GP: return (UINT_PTR *)&pCtx->Gp; + case REGISTER_RISCV64_TP: return (UINT_PTR *)&pCtx->Tp; + case REGISTER_RISCV64_S1: return (UINT_PTR *)&pCtx->S1; + default: + if (reg >= REGISTER_RISCV64_T0 && reg <= REGISTER_RISCV64_T2) + return (UINT_PTR *)&pCtx->T0 + (reg - REGISTER_RISCV64_T0); + if (reg >= REGISTER_RISCV64_A0 && reg <= REGISTER_RISCV64_A7) + return (UINT_PTR *)&pCtx->A0 + (reg - REGISTER_RISCV64_A0); + if (reg >= REGISTER_RISCV64_S2 && reg <= REGISTER_RISCV64_S11) + return (UINT_PTR *)&pCtx->S2 + (reg - REGISTER_RISCV64_S2); + if (reg >= REGISTER_RISCV64_T3 && reg <= REGISTER_RISCV64_T6) + return (UINT_PTR *)&pCtx->T3 + (reg - REGISTER_RISCV64_T3); + return NULL; + } +#else + return NULL; +#endif +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::WriteRegistersToContext( + IN OUT BYTE * ctxBuf, + IN ULONG32 cb, + IN const CorDebugRegister * regs, + IN ULONG32 nRegs, + IN const TADDR * values) +{ + DD_ENTER_MAY_THROW; + + if (ctxBuf == NULL || (nRegs > 0 && (regs == NULL || values == NULL))) + return E_INVALIDARG; + if (cb < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + for (ULONG32 i = 0; i < nRegs; i++) + { + // Registers with no CONTEXT slot (e.g. float / SIMD registers) are skipped. + UINT_PTR * pSlot = GetRegisterSlotFromContext(ctxBuf, regs[i]); + if (pSlot != NULL) + *pSlot = (UINT_PTR)values[i]; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadRegistersFromContext( + IN BYTE * ctxBuf, + IN ULONG32 cb, + IN const CorDebugRegister * regs, + IN ULONG32 nRegs, + OUT TADDR * pValues) +{ + DD_ENTER_MAY_THROW; + + if (ctxBuf == NULL || (nRegs > 0 && (regs == NULL || pValues == NULL))) + return E_INVALIDARG; + if (cb < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + for (ULONG32 i = 0; i < nRegs; i++) + { + // Registers with no CONTEXT slot (e.g. float / SIMD registers) read as zero. + UINT_PTR * pSlot = GetRegisterSlotFromContext(ctxBuf, regs[i]); + pValues[i] = (pSlot != NULL) ? (TADDR)*pSlot : (TADDR)0; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetAvailableRegistersMask( + IN BOOL fActive, + IN BOOL fQuickUnwind, + IN ULONG32 regCount, + OUT BYTE pAvailable[]) +{ + DD_ENTER_MAY_THROW; + + if (pAvailable == NULL || regCount == 0) + return E_INVALIDARG; + + ZeroMemory(pAvailable, regCount); + + auto setBit = [pAvailable, regCount](int reg) + { + ULONG32 byteIdx = (ULONG32)reg / 8; + if (byteIdx < regCount) + pAvailable[byteIdx] |= (BYTE)(1 << (reg % 8)); + }; + +#if defined(TARGET_X86) + setBit(REGISTER_INSTRUCTION_POINTER); + setBit(REGISTER_STACK_POINTER); + setBit(REGISTER_FRAME_POINTER); + if (!fQuickUnwind || fActive) + { + setBit(REGISTER_X86_EAX); + setBit(REGISTER_X86_ECX); + setBit(REGISTER_X86_EDX); + setBit(REGISTER_X86_EBX); + setBit(REGISTER_X86_ESI); + setBit(REGISTER_X86_EDI); + } + if (fActive) + { + for (int r = REGISTER_X86_FPSTACK_0; r <= REGISTER_X86_FPSTACK_7; r++) + setBit(r); + } +#elif defined(TARGET_AMD64) + setBit(REGISTER_INSTRUCTION_POINTER); + setBit(REGISTER_STACK_POINTER); + if (!fQuickUnwind || fActive) + { + setBit(REGISTER_AMD64_RBP); + setBit(REGISTER_AMD64_RAX); + setBit(REGISTER_AMD64_RCX); + setBit(REGISTER_AMD64_RDX); + setBit(REGISTER_AMD64_RBX); + setBit(REGISTER_AMD64_RSI); + setBit(REGISTER_AMD64_RDI); + for (int r = REGISTER_AMD64_R8; r <= REGISTER_AMD64_R15; r++) + setBit(r); + } + if (fActive) + { + for (int r = REGISTER_AMD64_XMM0; r <= REGISTER_AMD64_XMM15; r++) + setBit(r); + } +#elif defined(TARGET_ARM) + UNREFERENCED_PARAMETER(fActive); + UNREFERENCED_PARAMETER(fQuickUnwind); + setBit(REGISTER_INSTRUCTION_POINTER); + setBit(REGISTER_STACK_POINTER); + for (int r = REGISTER_ARM_R0; r <= REGISTER_ARM_R12; r++) + setBit(r); + setBit(REGISTER_ARM_LR); +#elif defined(TARGET_ARM64) + UNREFERENCED_PARAMETER(fActive); + UNREFERENCED_PARAMETER(fQuickUnwind); + setBit(REGISTER_ARM64_PC); + setBit(REGISTER_ARM64_SP); + setBit(REGISTER_ARM64_FP); + setBit(REGISTER_ARM64_LR); + for (int r = REGISTER_ARM64_X0; r <= REGISTER_ARM64_X28; r++) + setBit(r); + for (int r = REGISTER_ARM64_V0; r <= REGISTER_ARM64_V31; r++) + setBit(r); +#elif defined(TARGET_LOONGARCH64) + UNREFERENCED_PARAMETER(fActive); + UNREFERENCED_PARAMETER(fQuickUnwind); + setBit(REGISTER_LOONGARCH64_PC); + setBit(REGISTER_LOONGARCH64_SP); + setBit(REGISTER_LOONGARCH64_FP); + setBit(REGISTER_LOONGARCH64_RA); + setBit(REGISTER_LOONGARCH64_TP); + setBit(REGISTER_LOONGARCH64_X0); + for (int r = REGISTER_LOONGARCH64_A0; r <= REGISTER_LOONGARCH64_A7; r++) + setBit(r); + for (int r = REGISTER_LOONGARCH64_T0; r <= REGISTER_LOONGARCH64_T8; r++) + setBit(r); + for (int r = REGISTER_LOONGARCH64_S0; r <= REGISTER_LOONGARCH64_S8; r++) + setBit(r); + for (int r = REGISTER_LOONGARCH64_F0; r <= REGISTER_LOONGARCH64_F31; r++) + setBit(r); +#elif defined(TARGET_RISCV64) + UNREFERENCED_PARAMETER(fActive); + UNREFERENCED_PARAMETER(fQuickUnwind); + setBit(REGISTER_RISCV64_PC); + setBit(REGISTER_RISCV64_RA); + setBit(REGISTER_RISCV64_SP); + setBit(REGISTER_RISCV64_GP); + setBit(REGISTER_RISCV64_TP); + setBit(REGISTER_RISCV64_FP); + setBit(REGISTER_RISCV64_S1); + for (int r = REGISTER_RISCV64_T0; r <= REGISTER_RISCV64_T2; r++) + setBit(r); + for (int r = REGISTER_RISCV64_A0; r <= REGISTER_RISCV64_A7; r++) + setBit(r); + for (int r = REGISTER_RISCV64_S2; r <= REGISTER_RISCV64_S11; r++) + setBit(r); + for (int r = REGISTER_RISCV64_T3; r <= REGISTER_RISCV64_T6; r++) + setBit(r); + for (int r = REGISTER_RISCV64_F0; r <= REGISTER_RISCV64_F31; r++) + setBit(r); +#else + UNREFERENCED_PARAMETER(fActive); + UNREFERENCED_PARAMETER(fQuickUnwind); + return E_NOTIMPL; +#endif + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ContextHasExtendedRegisters( + IN BYTE * ctxBuf, + IN ULONG32 cb, + OUT BOOL * pResult) +{ + DD_ENTER_MAY_THROW; + + if (ctxBuf == NULL || pResult == NULL) + return E_INVALIDARG; + if (cb < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + *pResult = FALSE; +#if defined(DT_CONTEXT_EXTENDED_REGISTERS) + DT_CONTEXT * pCtx = (DT_CONTEXT *)ctxBuf; + *pResult = (pCtx->ContextFlags & DT_CONTEXT_EXTENDED_REGISTERS) == DT_CONTEXT_EXTENDED_REGISTERS; +#endif + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CompareControlRegisters( + IN const BYTE * ctxBuf1, + IN ULONG32 cb1, + IN const BYTE * ctxBuf2, + IN ULONG32 cb2, + OUT BOOL * pResult) +{ + DD_ENTER_MAY_THROW; + + if (ctxBuf1 == NULL || ctxBuf2 == NULL || pResult == NULL) + return E_INVALIDARG; + if (cb1 < sizeof(DT_CONTEXT) || cb2 < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + *pResult = ::CompareControlRegisters( + reinterpret_cast(ctxBuf1), + reinterpret_cast(ctxBuf2)); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CopyContext( + IN OUT BYTE * dstCtxBuf, + IN ULONG32 cbDst, + IN const BYTE * srcCtxBuf, + IN ULONG32 cbSrc, + IN ULONG32 flags) +{ + DD_ENTER_MAY_THROW; + + if (dstCtxBuf == NULL || srcCtxBuf == NULL) + return E_INVALIDARG; + if (cbDst < sizeof(DT_CONTEXT) || cbSrc < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + // flags != 0 stamps the destination's ContextFlags before the copy, so the + // chunk-wise copy below pulls exactly the requested pieces from the source. + // flags == 0 preserves the destination's existing ContextFlags. + if (flags != 0) + reinterpret_cast(dstCtxBuf)->ContextFlags = flags; + + CORDbgCopyThreadContext( + reinterpret_cast(dstCtxBuf), + reinterpret_cast(srcCtxBuf)); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ConvertJitRegNumToCorDebugRegister( + IN ULONG32 jitRegNum, + OUT CorDebugRegister * pReg) +{ + DD_ENTER_MAY_THROW; + + if (pReg == NULL) + return E_INVALIDARG; + if (jitRegNum >= ARRAY_SIZE(g_JITToCorDbgReg)) + return E_INVALIDARG; + + *pReg = ConvertRegNumToCorDebugRegister(static_cast(jitRegNum)); + return S_OK; +} + +namespace +{ + double BitsToDouble(UINT64 bits) + { + double d; + memcpy(&d, &bits, sizeof(double)); + return d; + } + + // Convert an x87 80-bit double-extended value to IEEE-754 binary64 with + // round-to-nearest-even, matching the hardware FSTP conversion the legacy + // x86 path used (gradual underflow to subnormals, overflow to infinity). + // Layout (Intel SDM Vol 1 sec 8.2.2): bytes 0-7 = 64-bit significand with an + // explicit integer bit at 63; bytes 8-9 = 15-bit biased exponent (bias + // 16383) in bits 0-14 and the sign in bit 15. + double X87ExtendedToDouble(const BYTE * slot10) + { + UINT64 significand = 0; + memcpy(&significand, slot10, sizeof(UINT64)); + UINT16 signExp = 0; + memcpy(&signExp, slot10 + 8, sizeof(UINT16)); + + UINT64 sign = (UINT64)((signExp >> 15) & 1) << 63; + UINT32 exp80 = (UINT32)(signExp & 0x7FFF); + + if (exp80 == 0x7FFF) + { + UINT64 frac = significand & ~(1ULL << 63); + if (frac == 0) + return BitsToDouble(sign | ((UINT64)0x7FF << 52)); + // Force a quiet NaN (keeping the high payload bits) so a signaling + // NaN is never misencoded as an infinity. + UINT64 payload = (frac >> 12) & ((1ULL << 51) - 1); + return BitsToDouble(sign | ((UINT64)0x7FF << 52) | (1ULL << 51) | payload); + } + + // Zero, extended denormals and unnormals all fall below the binary64 + // subnormal floor (2^-1074) and map to signed zero. + if (exp80 == 0 || (significand & (1ULL << 63)) == 0) + return BitsToDouble(sign); + + int expD = (int)exp80 - 16383 + 1023; // pre-rounding binary64 biased exponent + + if (expD >= 0x7FF) + return BitsToDouble(sign | ((UINT64)0x7FF << 52)); // overflow -> infinity + + if (expD > 0) + { + // Normal: keep the top 52 fraction bits and round the low 11 to even. + UINT64 frac = significand & ~(1ULL << 63); // 63 fraction bits + UINT64 result = frac >> 11; // top 52 bits + UINT64 discarded = frac & 0x7FF; // low 11 bits + if (discarded > 0x400 || (discarded == 0x400 && (result & 1))) + { + result++; + if (result >> 52) // carry out of the fraction + { + result = 0; + expD++; + if (expD >= 0x7FF) + return BitsToDouble(sign | ((UINT64)0x7FF << 52)); + } + } + return BitsToDouble(sign | ((UINT64)expD << 52) | (result & ((1ULL << 52) - 1))); + } + + // Subnormal / underflow (expD <= 0): right-shift the significand by + // (12 - expD) and round to nearest-even. A carry into bit 52 promotes the + // value to the smallest normal, which the encoding produces for free. + int shift = 12 - expD; // >= 12 + if (shift > 64) // below half the smallest subnormal + return BitsToDouble(sign); + + UINT64 result; + UINT64 discarded; + UINT64 half; + if (shift == 64) + { + result = 0; + discarded = significand; + half = 1ULL << 63; + } + else + { + result = significand >> shift; + discarded = significand & ((1ULL << shift) - 1); + half = 1ULL << (shift - 1); + } + if (discarded > half || (discarded == half && (result & 1))) + result++; + return BitsToDouble(sign | result); + } + + double Reinterpret64ToDouble(const BYTE * slot) + { + double d; + memcpy(&d, slot, sizeof(double)); + return d; + } +} + +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( + IN BYTE * ctxBuf, + IN ULONG32 cb, + IN ULONG32 maxValues, + OUT DOUBLE values[], + OUT ULONG32 * pValuesCount, + OUT int * pFirstFloatReg, + OUT ULONG32 * pFloatStackTop) +{ + DD_ENTER_MAY_THROW; + + if (ctxBuf == NULL || values == NULL || pValuesCount == NULL || + pFirstFloatReg == NULL || pFloatStackTop == NULL || maxValues == 0) + { + return E_INVALIDARG; + } + if (cb < sizeof(DT_CONTEXT)) + return E_INVALIDARG; + + DT_CONTEXT * pCtx = reinterpret_cast(ctxBuf); + + *pValuesCount = 0; + *pFirstFloatReg = -1; + *pFloatStackTop = 0; + memset(values, 0, sizeof(DOUBLE) * maxValues); + +#if defined(TARGET_X86) + const DT_FLOATING_SAVE_AREA * pFp = &pCtx->FloatSave; + ULONG32 rawTop = (pFp->StatusWord >> 11) & 0x7; + ULONG32 floatStackTop = 7 - rawTop; + *pFloatStackTop = floatStackTop; + *pFirstFloatReg = REGISTER_X86_FPSTACK_0; + + ULONG32 count = floatStackTop + 1; + if (count > maxValues) + count = maxValues; + *pValuesCount = count; + + const BYTE * regArea = (const BYTE *)pFp->RegisterArea; + for (ULONG32 i = 0; i < count; i++) + { + ULONG32 physIdx = (rawTop + i) & 0x7; + values[i] = X87ExtendedToDouble(regArea + physIdx * 10); + } +#elif defined(TARGET_AMD64) + const BYTE * base = (const BYTE *)&pCtx->Xmm0; + ULONG32 count = 16; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = REGISTER_AMD64_XMM0; + for (ULONG32 i = 0; i < count; i++) + values[i] = Reinterpret64ToDouble(base + i * 16); +#elif defined(TARGET_ARM64) + const BYTE * base = (const BYTE *)&pCtx->V; + ULONG32 count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = REGISTER_ARM64_V0; + for (ULONG32 i = 0; i < count; i++) + values[i] = Reinterpret64ToDouble(base + i * 16); +#elif defined(TARGET_ARM) + const BYTE * base = (const BYTE *)&pCtx->D; + ULONG32 count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + for (ULONG32 i = 0; i < count; i++) + values[i] = Reinterpret64ToDouble(base + i * 8); +#elif defined(TARGET_LOONGARCH64) + const BYTE * base = (const BYTE *)&pCtx->F; + ULONG32 count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = REGISTER_LOONGARCH64_F0; + for (ULONG32 i = 0; i < count; i++) + values[i] = Reinterpret64ToDouble(base + i * 32); +#elif defined(TARGET_RISCV64) + const BYTE * base = (const BYTE *)&pCtx->F; + ULONG32 count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = REGISTER_RISCV64_F0; + for (ULONG32 i = 0; i < count; i++) + values[i] = Reinterpret64ToDouble(base + i * 8); +#else + return E_NOTIMPL; +#endif + + return S_OK; +} + // Create a VMPTR_Object from a target object address // @dbgtodo validate the VMPTR_Object is in fact a object, possibly by DACizing // Object::Validate diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 24c0c6865b13c7..212269e7c5676c 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -151,6 +151,29 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE EnumerateAsyncLocals(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeAddr, UINT32 state, FP_ASYNC_LOCAL_CALLBACK fpCallback, CALLBACK_DATA pUserData); HRESULT STDMETHODCALLTYPE GetGenericArgTokenIndex(VMPTR_MethodDesc vmMethod, OUT UINT32* pIndex); + HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize); + + HRESULT STDMETHODCALLTYPE WriteRegistersToContext(IN OUT BYTE * ctxBuf, IN ULONG32 cb, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values); + HRESULT STDMETHODCALLTYPE ReadRegistersFromContext(IN BYTE * ctxBuf, IN ULONG32 cb, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues); + HRESULT STDMETHODCALLTYPE GetAvailableRegistersMask(IN BOOL fActive, IN BOOL fQuickUnwind, IN ULONG32 regCount, OUT BYTE pAvailable[]); + HRESULT STDMETHODCALLTYPE ConvertJitRegNumToCorDebugRegister(IN ULONG32 jitRegNum, OUT CorDebugRegister * pReg); + HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( + IN BYTE * ctxBuf, + IN ULONG32 cb, + IN ULONG32 regCount, + OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], + OUT ULONG32 * pValuesCount, + OUT int * pFirstFloatReg, + OUT ULONG32 * pFloatStackTop); + + HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); + + HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters(IN BYTE * ctxBuf, IN ULONG32 cb, OUT BOOL * pResult); + + HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN const BYTE * ctxBuf1, IN ULONG32 cb1, IN const BYTE * ctxBuf2, IN ULONG32 cb2, OUT BOOL * pResult); + + HRESULT STDMETHODCALLTYPE CopyContext(IN OUT BYTE * dstCtxBuf, IN ULONG32 cbDst, IN const BYTE * srcCtxBuf, IN ULONG32 cbSrc, IN ULONG32 flags); + private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, TypeHandle typeHandle, @@ -681,24 +704,24 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT VMPTR_CONTEXT * pRetVal); // Create and return a stackwalker on the specified thread. - HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, DT_CONTEXT * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle); + HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle); // Delete the stackwalk object HRESULT STDMETHODCALLTYPE DeleteStackWalk(StackWalkHandle ppSFIHandle); // Get the CONTEXT of the current frame at which the stackwalker is stopped. - HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, DT_CONTEXT * pContext); + HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext); void GetStackWalkCurrentContext(StackFrameIterator * pIter, DT_CONTEXT * pContext); // Set the stackwalker to the specified CONTEXT. - HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, DT_CONTEXT * pContext); + HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContext); // Unwind the stackwalker to the next frame. HRESULT STDMETHODCALLTYPE UnwindStackWalkFrame(StackWalkHandle pSFIHandle, OUT BOOL * pResult); HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, - const DT_CONTEXT * pContext); + const BYTE * pContext); // Retrieve information about the current frame from the stackwalker. HRESULT STDMETHODCALLTYPE GetStackWalkCurrentFrameInfo(StackWalkHandle pSFIHandle, OPTIONAL Debugger_STRData * pFrameData, OUT FrameType * pRetVal); @@ -722,10 +745,10 @@ class DacDbiInterfaceImpl : // Return TRUE if the specified CONTEXT is the CONTEXT of the leaf frame. // @dbgtodo filter CONTEXT - Currently we check for the filter CONTEXT first. - HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const DT_CONTEXT * pContext, OUT BOOL * pResult); + HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContext, OUT BOOL * pResult); // DacDbi API: Get the context for a particular thread of the target process - HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer); + HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, BYTE * pContextBuffer); // Check if the given method is a DiagnosticHidden or an LCG method. HRESULT STDMETHODCALLTYPE IsDiagnosticsHiddenOrLCGMethod(VMPTR_MethodDesc vmMethodDesc, OUT DynamicMethodType * pRetVal); diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index 3ef32a23964011..6f06742ca69b72 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -109,7 +109,7 @@ T_CONTEXT * GetContextBufferFromHandle(StackWalkHandle pSFIHandle) // Create and return a stackwalker on the specified thread. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateStackWalk(VMPTR_Thread vmThread, DT_CONTEXT * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) { DD_ENTER_MAY_THROW; @@ -156,7 +156,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::DeleteStackWalk(StackWalkHandle p } // Get the CONTEXT of the current frame at which the stackwalker is stopped. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, DT_CONTEXT * pContext) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext) { DD_ENTER_MAY_THROW; @@ -166,7 +166,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackW StackFrameIterator * pIter = GetIteratorFromHandle(pSFIHandle); - GetStackWalkCurrentContext(pIter, pContext); + GetStackWalkCurrentContext(pIter, reinterpret_cast(pContext)); } EX_CATCH_HRESULT(hr); return hr; @@ -189,7 +189,7 @@ void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackFrameIterator * pIter, // Set the stackwalker to the specified CONTEXT. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, DT_CONTEXT * pContext) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContextBuffer) { DD_ENTER_MAY_THROW; @@ -197,12 +197,14 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_ EX_TRY { + DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); + StackFrameIterator * pIter = GetIteratorFromHandle(pSFIHandle); REGDISPLAY * pRD = GetRegDisplayFromHandle(pSFIHandle); #if defined(_DEBUG) // The caller should have checked this already. - _ASSERTE(CheckContext(vmThread, pContext) == S_OK); + _ASSERTE(CheckContext(vmThread, pContextBuffer) == S_OK); #endif // _DEBUG // DD can't keep pointers back into the RS address space. @@ -342,9 +344,12 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHan // Check whether the specified CONTEXT is valid. The only check we perform right now is whether the // SP in the specified CONTEXT is in the stack range of the thread. HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CheckContext(VMPTR_Thread vmThread, - const DT_CONTEXT * pContext) + const BYTE * pContextBuffer) { DD_ENTER_MAY_THROW; + _ASSERTE(pContextBuffer != NULL); + + const DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); // If the SP in the CONTEXT isn't valid, then there's no point in checking. if ((pContext->ContextFlags & CONTEXT_CONTROL) == 0) @@ -704,7 +709,7 @@ FramePointer DacDbiInterfaceImpl::GetFramePointerWorker(StackFrameIterator * pIt } // Return TRUE if the specified CONTEXT is the CONTEXT of the leaf frame. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread, const DT_CONTEXT * pContext, OUT BOOL * pResult) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContextBuffer, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; @@ -712,6 +717,8 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread EX_TRY { + const DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); + DT_CONTEXT ctxLeaf; Thread * pThread = vmThread.GetDacPtr(); ctxLeaf.ContextFlags = DT_CONTEXT_ALL; @@ -721,7 +728,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread reinterpret_cast(&ctxLeaf))); // Call a platform-specific helper to compare the two contexts. - *pResult = CompareControlRegisters(pContext, &ctxLeaf); + *pResult = ::CompareControlRegisters(pContext, &ctxLeaf); } EX_CATCH_HRESULT(hr); return hr; @@ -755,7 +762,7 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, pFrameData->eType = Debugger_STRData::cRuntimeNativeFrame; _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, pFrameData->ctx); + GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx)); } else if (ft == kManagedStackFrame) { @@ -786,7 +793,7 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, pFrameData->eType = Debugger_STRData::cMethodFrame; _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, pFrameData->ctx); + GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx)); // // initialize the fields in Debugger_STRData::v diff --git a/src/coreclr/debug/di/CMakeLists.txt b/src/coreclr/debug/di/CMakeLists.txt index e9c6b14af9300c..690d8f0a446c32 100644 --- a/src/coreclr/debug/di/CMakeLists.txt +++ b/src/coreclr/debug/di/CMakeLists.txt @@ -13,6 +13,7 @@ set(CORDBDI_SOURCES shimstackwalk.cpp breakpoint.cpp cordb.cpp + cordbregisterset.cpp divalue.cpp dbgtransportmanager.cpp hash.cpp @@ -50,24 +51,6 @@ set(CORDBDI_HEADERS if(CLR_CMAKE_HOST_WIN32) #use static crt set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) - - if (CLR_CMAKE_TARGET_ARCH_AMD64 OR ((CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_ARM) - AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)) - set(CORDBDI_SOURCES_ASM_FILE ${ARCH_SOURCES_DIR}/floatconversion.asm) - endif() - - if ((CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_ARM64) AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD) - convert_to_absolute_path(CORDBDI_SOURCES_ASM_FILE ${CORDBDI_SOURCES_ASM_FILE}) - preprocess_files(CORDBDI_SOURCES_ASM_FILE ${CORDBDI_SOURCES_ASM_FILE}) - endif() -elseif(CLR_CMAKE_HOST_UNIX) - - if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_ARM OR CLR_CMAKE_TARGET_ARCH_LOONGARCH64 OR CLR_CMAKE_TARGET_ARCH_RISCV64) - set(CORDBDI_SOURCES_ASM_FILE - ${ARCH_SOURCES_DIR}/floatconversion.S - ) - endif() - endif(CLR_CMAKE_HOST_WIN32) if (CLR_CMAKE_TARGET_WIN32) @@ -75,8 +58,6 @@ if (CLR_CMAKE_TARGET_WIN32) list(APPEND CORDBDI_SOURCES ${CORDBDI_HEADERS}) endif (CLR_CMAKE_TARGET_WIN32) -list(APPEND CORDBDI_SOURCES ${CORDBDI_SOURCES_ASM_FILE}) - add_library_clr(cordbdi STATIC ${CORDBDI_SOURCES}) target_precompile_headers(cordbdi PRIVATE stdafx.h) add_dependencies(cordbdi eventing_headers) diff --git a/src/coreclr/debug/di/amd64/FloatConversion.asm b/src/coreclr/debug/di/amd64/FloatConversion.asm deleted file mode 100644 index a9f4fbc6f82aef..00000000000000 --- a/src/coreclr/debug/di/amd64/FloatConversion.asm +++ /dev/null @@ -1,19 +0,0 @@ -; Licensed to the .NET Foundation under one or more agreements. -; The .NET Foundation licenses this file to you under the MIT license. - -;// @dbgtodo Microsoft inspection: remove the implementation from vm\amd64\getstate.asm when we remove the -;// ipc event to load the float state. - -;// this is the same implementation as the function of the same name in vm\amd64\getstate.asm and they must -;// remain in sync. -;// Arguments -;// input: (in rcx) the M128 value to be converted to a double -;// output: the double corresponding to the M128 input value - -_TEXT segment para 'CODE' -FPFillR8 proc - movdqa xmm0, [rcx] - ret -FPFillR8 endp - -END diff --git a/src/coreclr/debug/di/amd64/cordbregisterset.cpp b/src/coreclr/debug/di/amd64/cordbregisterset.cpp deleted file mode 100644 index 22e4521dbc12c6..00000000000000 --- a/src/coreclr/debug/di/amd64/cordbregisterset.cpp +++ /dev/null @@ -1,217 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64* pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64*); - - (*pAvailable) = SETBITULONG64( REGISTER_INSTRUCTION_POINTER ) - | SETBITULONG64( REGISTER_STACK_POINTER ); - - if (!m_quickUnwind || m_active) - (*pAvailable) |= SETBITULONG64( REGISTER_AMD64_RBP ) - | SETBITULONG64( REGISTER_AMD64_RAX ) - | SETBITULONG64( REGISTER_AMD64_RCX ) - | SETBITULONG64( REGISTER_AMD64_RDX ) - | SETBITULONG64( REGISTER_AMD64_RBX ) - | SETBITULONG64( REGISTER_AMD64_RSI ) - | SETBITULONG64( REGISTER_AMD64_RDI ) - | SETBITULONG64( REGISTER_AMD64_R8 ) - | SETBITULONG64( REGISTER_AMD64_R9 ) - | SETBITULONG64( REGISTER_AMD64_R10 ) - | SETBITULONG64( REGISTER_AMD64_R11 ) - | SETBITULONG64( REGISTER_AMD64_R12 ) - | SETBITULONG64( REGISTER_AMD64_R13 ) - | SETBITULONG64( REGISTER_AMD64_R14 ) - | SETBITULONG64( REGISTER_AMD64_R15 ); - - if (m_active) - (*pAvailable) |= SETBITULONG64( REGISTER_AMD64_XMM0 ) - | SETBITULONG64( REGISTER_AMD64_XMM1 ) - | SETBITULONG64( REGISTER_AMD64_XMM2 ) - | SETBITULONG64( REGISTER_AMD64_XMM3 ) - | SETBITULONG64( REGISTER_AMD64_XMM4 ) - | SETBITULONG64( REGISTER_AMD64_XMM5 ) - | SETBITULONG64( REGISTER_AMD64_XMM6 ) - | SETBITULONG64( REGISTER_AMD64_XMM7 ) - | SETBITULONG64( REGISTER_AMD64_XMM8 ) - | SETBITULONG64( REGISTER_AMD64_XMM9 ) - | SETBITULONG64( REGISTER_AMD64_XMM10 ) - | SETBITULONG64( REGISTER_AMD64_XMM11 ) - | SETBITULONG64( REGISTER_AMD64_XMM12 ) - | SETBITULONG64( REGISTER_AMD64_XMM13 ) - | SETBITULONG64( REGISTER_AMD64_XMM14 ) - | SETBITULONG64( REGISTER_AMD64_XMM15 ); - - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, - CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - UINT iRegister = 0; - - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - if ( mask & ( SETBITULONG64( REGISTER_AMD64_XMM0 ) - | SETBITULONG64( REGISTER_AMD64_XMM1 ) - | SETBITULONG64( REGISTER_AMD64_XMM2 ) - | SETBITULONG64( REGISTER_AMD64_XMM3 ) - | SETBITULONG64( REGISTER_AMD64_XMM4 ) - | SETBITULONG64( REGISTER_AMD64_XMM5 ) - | SETBITULONG64( REGISTER_AMD64_XMM6 ) - | SETBITULONG64( REGISTER_AMD64_XMM7 ) - | SETBITULONG64( REGISTER_AMD64_XMM8 ) - | SETBITULONG64( REGISTER_AMD64_XMM9 ) - | SETBITULONG64( REGISTER_AMD64_XMM10 ) - | SETBITULONG64( REGISTER_AMD64_XMM11 ) - | SETBITULONG64( REGISTER_AMD64_XMM12 ) - | SETBITULONG64( REGISTER_AMD64_XMM13 ) - | SETBITULONG64( REGISTER_AMD64_XMM14 ) - | SETBITULONG64( REGISTER_AMD64_XMM15 ) ) ) - { - HRESULT hr = S_OK; - - if (!m_active) - return E_INVALIDARG; - - if (!m_thread->m_fFloatStateValid) - { - EX_TRY - { - m_thread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - - if ( !SUCCEEDED(hr) ) - { - return hr; - } - LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); - } - } - - // Make sure that the registers are really available - if ( mask & ( SETBITULONG64( REGISTER_AMD64_RBP ) - | SETBITULONG64( REGISTER_AMD64_RAX ) - | SETBITULONG64( REGISTER_AMD64_RCX ) - | SETBITULONG64( REGISTER_AMD64_RDX ) - | SETBITULONG64( REGISTER_AMD64_RBX ) - | SETBITULONG64( REGISTER_AMD64_RSI ) - | SETBITULONG64( REGISTER_AMD64_RDI ) - | SETBITULONG64( REGISTER_AMD64_R8 ) - | SETBITULONG64( REGISTER_AMD64_R9 ) - | SETBITULONG64( REGISTER_AMD64_R10 ) - | SETBITULONG64( REGISTER_AMD64_R11 ) - | SETBITULONG64( REGISTER_AMD64_R12 ) - | SETBITULONG64( REGISTER_AMD64_R13 ) - | SETBITULONG64( REGISTER_AMD64_R14 ) - | SETBITULONG64( REGISTER_AMD64_R15 ) ) ) - { - if (!m_active && m_quickUnwind) - return E_INVALIDARG; - } - - for ( int i = REGISTER_INSTRUCTION_POINTER - ; i<=REGISTER_AMD64_XMM15 && iRegister < regCount - ; i++) - { - if( mask & SETBITULONG64(i) ) - { - switch( i ) - { - case REGISTER_INSTRUCTION_POINTER: - regBuffer[iRegister++] = m_context.Rip; break; - case REGISTER_STACK_POINTER: - regBuffer[iRegister++] = m_context.Rsp; break; - case REGISTER_AMD64_RBP: - regBuffer[iRegister++] = m_context.Rbp; break; - case REGISTER_AMD64_RAX: - regBuffer[iRegister++] = m_context.Rax; break; - case REGISTER_AMD64_RBX: - regBuffer[iRegister++] = m_context.Rbx; break; - case REGISTER_AMD64_RCX: - regBuffer[iRegister++] = m_context.Rcx; break; - case REGISTER_AMD64_RDX: - regBuffer[iRegister++] = m_context.Rdx; break; - case REGISTER_AMD64_RSI: - regBuffer[iRegister++] = m_context.Rsi; break; - case REGISTER_AMD64_RDI: - regBuffer[iRegister++] = m_context.Rdi; break; - case REGISTER_AMD64_R8: - regBuffer[iRegister++] = m_context.R8; break; - case REGISTER_AMD64_R9: - regBuffer[iRegister++] = m_context.R9; break; - case REGISTER_AMD64_R10: - regBuffer[iRegister++] = m_context.R10; break; - case REGISTER_AMD64_R11: - regBuffer[iRegister++] = m_context.R11; break; - case REGISTER_AMD64_R12: - regBuffer[iRegister++] = m_context.R12; break; - case REGISTER_AMD64_R13: - regBuffer[iRegister++] = m_context.R13; break; - case REGISTER_AMD64_R14: - regBuffer[iRegister++] = m_context.R14; break; - case REGISTER_AMD64_R15: - regBuffer[iRegister++] = m_context.R15; break; - - case REGISTER_AMD64_XMM0: - case REGISTER_AMD64_XMM1: - case REGISTER_AMD64_XMM2: - case REGISTER_AMD64_XMM3: - case REGISTER_AMD64_XMM4: - case REGISTER_AMD64_XMM5: - case REGISTER_AMD64_XMM6: - case REGISTER_AMD64_XMM7: - case REGISTER_AMD64_XMM8: - case REGISTER_AMD64_XMM9: - case REGISTER_AMD64_XMM10: - case REGISTER_AMD64_XMM11: - case REGISTER_AMD64_XMM12: - case REGISTER_AMD64_XMM13: - case REGISTER_AMD64_XMM14: - case REGISTER_AMD64_XMM15: - regBuffer[iRegister++] = *(CORDB_REGISTER*) - &(m_thread->m_floatValues[(i - REGISTER_AMD64_XMM0)]); - break; - } - } - } - - _ASSERTE( iRegister <= regCount ); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAvailableAdapter(regCount, pAvailable); -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAdapter(maskCount, mask, regCount, regBuffer); -} diff --git a/src/coreclr/debug/di/amd64/floatconversion.S b/src/coreclr/debug/di/amd64/floatconversion.S deleted file mode 100644 index d43658175addaa..00000000000000 --- a/src/coreclr/debug/di/amd64/floatconversion.S +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -.intel_syntax noprefix -#include - -LEAF_ENTRY FPFillR8, _TEXT - movdqa xmm0, xmmword ptr [rdi] - ret -LEAF_END FPFillR8, _TEXT diff --git a/src/coreclr/debug/di/arm/cordbregisterset.cpp b/src/coreclr/debug/di/arm/cordbregisterset.cpp deleted file mode 100644 index 781947a6e45e82..00000000000000 --- a/src/coreclr/debug/di/arm/cordbregisterset.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64 *pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); - - *pAvailable = SETBITULONG64(REGISTER_INSTRUCTION_POINTER) - | SETBITULONG64(REGISTER_STACK_POINTER) - | SETBITULONG64(REGISTER_ARM_R0) - | SETBITULONG64(REGISTER_ARM_R1) - | SETBITULONG64(REGISTER_ARM_R2) - | SETBITULONG64(REGISTER_ARM_R3) - | SETBITULONG64(REGISTER_ARM_R4) - | SETBITULONG64(REGISTER_ARM_R5) - | SETBITULONG64(REGISTER_ARM_R6) - | SETBITULONG64(REGISTER_ARM_R7) - | SETBITULONG64(REGISTER_ARM_R8) - | SETBITULONG64(REGISTER_ARM_R9) - | SETBITULONG64(REGISTER_ARM_R10) - | SETBITULONG64(REGISTER_ARM_R11) - | SETBITULONG64(REGISTER_ARM_R12) - | SETBITULONG64(REGISTER_ARM_LR); - - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - - UINT iRegister = 0; - - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - // @ARMTODO: floating point support - - for (int i = REGISTER_INSTRUCTION_POINTER; - i <= REGISTER_ARM_LR && iRegister < regCount; - i++) - { - if (mask & SETBITULONG64(i)) - { - switch (i) - { - case REGISTER_INSTRUCTION_POINTER: - regBuffer[iRegister++] = m_context.Pc; break; - case REGISTER_STACK_POINTER: - regBuffer[iRegister++] = m_context.Sp; break; - case REGISTER_ARM_R0: - regBuffer[iRegister++] = m_context.R0; break; - case REGISTER_ARM_R1: - regBuffer[iRegister++] = m_context.R1; break; - case REGISTER_ARM_R2: - regBuffer[iRegister++] = m_context.R2; break; - case REGISTER_ARM_R3: - regBuffer[iRegister++] = m_context.R3; break; - case REGISTER_ARM_R4: - regBuffer[iRegister++] = m_context.R4; break; - case REGISTER_ARM_R5: - regBuffer[iRegister++] = m_context.R5; break; - case REGISTER_ARM_R6: - regBuffer[iRegister++] = m_context.R6; break; - case REGISTER_ARM_R7: - regBuffer[iRegister++] = m_context.R7; break; - case REGISTER_ARM_R8: - regBuffer[iRegister++] = m_context.R8; break; - case REGISTER_ARM_R9: - regBuffer[iRegister++] = m_context.R9; break; - case REGISTER_ARM_R10: - regBuffer[iRegister++] = m_context.R10; break; - case REGISTER_ARM_R11: - regBuffer[iRegister++] = m_context.R11; break; - case REGISTER_ARM_R12: - regBuffer[iRegister++] = m_context.R12; break; - case REGISTER_ARM_LR: - regBuffer[iRegister++] = m_context.Lr; break; - } - } - } - - _ASSERTE (iRegister <= regCount); - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAvailableAdapter(regCount, pAvailable); -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAdapter(maskCount, mask, regCount, regBuffer); -} diff --git a/src/coreclr/debug/di/arm/floatconversion.S b/src/coreclr/debug/di/arm/floatconversion.S deleted file mode 100644 index feea0db7abed7f..00000000000000 --- a/src/coreclr/debug/di/arm/floatconversion.S +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include - -// Arguments -// input: (in R0) the address of the ULONGLONG to be converted to a double -// output: the double corresponding to the ULONGLONG input value - -LEAF_ENTRY FPFillR8, .TEXT - .thumb - vldr D0, [R0] - bx lr -LEAF_END FPFillR8, .TEXT diff --git a/src/coreclr/debug/di/arm64/cordbregisterset.cpp b/src/coreclr/debug/di/arm64/cordbregisterset.cpp deleted file mode 100644 index ca11ec8020aabc..00000000000000 --- a/src/coreclr/debug/di/arm64/cordbregisterset.cpp +++ /dev/null @@ -1,241 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64* pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); - - *pAvailable = SETBITULONG64(REGISTER_ARM64_PC) - | SETBITULONG64(REGISTER_ARM64_SP) - | SETBITULONG64(REGISTER_ARM64_X0) - | SETBITULONG64(REGISTER_ARM64_X1) - | SETBITULONG64(REGISTER_ARM64_X2) - | SETBITULONG64(REGISTER_ARM64_X3) - | SETBITULONG64(REGISTER_ARM64_X4) - | SETBITULONG64(REGISTER_ARM64_X5) - | SETBITULONG64(REGISTER_ARM64_X6) - | SETBITULONG64(REGISTER_ARM64_X7) - | SETBITULONG64(REGISTER_ARM64_X8) - | SETBITULONG64(REGISTER_ARM64_X9) - | SETBITULONG64(REGISTER_ARM64_X10) - | SETBITULONG64(REGISTER_ARM64_X11) - | SETBITULONG64(REGISTER_ARM64_X12) - | SETBITULONG64(REGISTER_ARM64_X13) - | SETBITULONG64(REGISTER_ARM64_X14) - | SETBITULONG64(REGISTER_ARM64_X15) - | SETBITULONG64(REGISTER_ARM64_X16) - | SETBITULONG64(REGISTER_ARM64_X17) - | SETBITULONG64(REGISTER_ARM64_X18) - | SETBITULONG64(REGISTER_ARM64_X19) - | SETBITULONG64(REGISTER_ARM64_X20) - | SETBITULONG64(REGISTER_ARM64_X21) - | SETBITULONG64(REGISTER_ARM64_X22) - | SETBITULONG64(REGISTER_ARM64_X23) - | SETBITULONG64(REGISTER_ARM64_X24) - | SETBITULONG64(REGISTER_ARM64_X25) - | SETBITULONG64(REGISTER_ARM64_X26) - | SETBITULONG64(REGISTER_ARM64_X27) - | SETBITULONG64(REGISTER_ARM64_X28) - | SETBITULONG64(REGISTER_ARM64_FP) - | SETBITULONG64(REGISTER_ARM64_LR) - | SETBITULONG64(REGISTER_ARM64_V0) - | SETBITULONG64(REGISTER_ARM64_V1) - | SETBITULONG64(REGISTER_ARM64_V2) - | SETBITULONG64(REGISTER_ARM64_V3) - | SETBITULONG64(REGISTER_ARM64_V4) - | SETBITULONG64(REGISTER_ARM64_V5) - | SETBITULONG64(REGISTER_ARM64_V6) - | SETBITULONG64(REGISTER_ARM64_V7) - | SETBITULONG64(REGISTER_ARM64_V8) - | SETBITULONG64(REGISTER_ARM64_V9) - | SETBITULONG64(REGISTER_ARM64_V10) - | SETBITULONG64(REGISTER_ARM64_V11) - | SETBITULONG64(REGISTER_ARM64_V12) - | SETBITULONG64(REGISTER_ARM64_V13) - | SETBITULONG64(REGISTER_ARM64_V14) - | SETBITULONG64(REGISTER_ARM64_V15) - | SETBITULONG64(REGISTER_ARM64_V16) - | SETBITULONG64(REGISTER_ARM64_V17) - | SETBITULONG64(REGISTER_ARM64_V18) - | SETBITULONG64(REGISTER_ARM64_V19) - | SETBITULONG64(REGISTER_ARM64_V20) - | SETBITULONG64(REGISTER_ARM64_V21) - | SETBITULONG64(REGISTER_ARM64_V22) - | SETBITULONG64(REGISTER_ARM64_V23) - | SETBITULONG64(REGISTER_ARM64_V24) - | SETBITULONG64(REGISTER_ARM64_V25) - | SETBITULONG64(REGISTER_ARM64_V26) - | SETBITULONG64(REGISTER_ARM64_V27) - | SETBITULONG64(REGISTER_ARM64_V28) - | SETBITULONG64(REGISTER_ARM64_V29) - | SETBITULONG64(REGISTER_ARM64_V30); - - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, - CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - - UINT iRegister = 0; - - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - for (int i = REGISTER_ARM64_PC; - i <= REGISTER_ARM64_V30 && iRegister < regCount; - i++) - { - if (mask & SETBITULONG64(i)) - { - _ASSERTE (iRegister < regCount); - - if ((i >= REGISTER_ARM64_X0) && (i <= REGISTER_ARM64_X28)) - { - regBuffer[iRegister++] = m_context.X[i - REGISTER_ARM64_X0]; - continue; - } - - if ((i >= REGISTER_ARM64_V0) && (i <= REGISTER_ARM64_V30)) - { - if (!m_thread->m_fFloatStateValid) - { - HRESULT hr = S_OK; - EX_TRY - { - m_thread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - - if ( !SUCCEEDED(hr) ) - { - return hr; - } - LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); - } - - regBuffer[iRegister++] = *(CORDB_REGISTER*) - &(m_thread->m_floatValues[(i - REGISTER_ARM64_V0)]); - continue; - } - - switch (i) - { - case REGISTER_ARM64_PC: - regBuffer[iRegister++] = m_context.Pc; break; - case REGISTER_ARM64_SP: - regBuffer[iRegister++] = m_context.Sp; break; - case REGISTER_ARM64_FP: - regBuffer[iRegister++] = m_context.Fp; break; - case REGISTER_ARM64_LR: - regBuffer[iRegister++] = m_context.Lr; break; - default: - _ASSERTE(false); break; - } - } - } - - _ASSERTE (iRegister <= regCount); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); - - for (int i = 0 ; i < (int)regCount ; ++i) - { - if (i * 8 <= REGISTER_ARM64_V31) - { - pAvailable[i] = (i * 8 == REGISTER_ARM64_V31) ? BYTE(0x1) : BYTE(0xff); - } - else - { - pAvailable[i] = 0; - } - } - - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - UINT iRegister = 0; - - for (int m = 0 ; m < (int)maskCount ; ++m) - { - for (int bit = 0 ; bit < 8 ; ++bit) - { - if (mask[m] & SETBITULONG64(bit)) - { - _ASSERTE (iRegister < regCount); - - int i = m * 8 + bit; - - if ((i >= REGISTER_ARM64_X0) && (i <= REGISTER_ARM64_X28)) - { - regBuffer[iRegister++] = m_context.X[i - REGISTER_ARM64_X0]; - continue; - } - - if ((i >= REGISTER_ARM64_V0) && (i <= REGISTER_ARM64_V31)) - { - if (!m_thread->m_fFloatStateValid) - { - HRESULT hr = S_OK; - EX_TRY - { - m_thread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - - if ( !SUCCEEDED(hr) ) - { - return hr; - } - LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); - } - - regBuffer[iRegister++] = *(CORDB_REGISTER*) - &(m_thread->m_floatValues[(i - REGISTER_ARM64_V0)]); - continue; - } - - switch (i) - { - case REGISTER_ARM64_PC: - regBuffer[iRegister++] = m_context.Pc; break; - case REGISTER_ARM64_SP: - regBuffer[iRegister++] = m_context.Sp; break; - case REGISTER_ARM64_FP: - regBuffer[iRegister++] = m_context.Fp; break; - case REGISTER_ARM64_LR: - regBuffer[iRegister++] = m_context.Lr; break; - default: - _ASSERTE(false); break; - } - } - } - } - - return S_OK; -} diff --git a/src/coreclr/debug/di/arm64/floatconversion.S b/src/coreclr/debug/di/arm64/floatconversion.S deleted file mode 100644 index c6370f28e8f811..00000000000000 --- a/src/coreclr/debug/di/arm64/floatconversion.S +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include - -// Arguments -// input: (in X0) the _NEON128 value to be converted to a double -// output: the double corresponding to the _NEON128 input value - -LEAF_ENTRY FPFillR8, .TEXT - LDR Q0, [X0] - ret lr -LEAF_END FPFillR8, .TEXT diff --git a/src/coreclr/debug/di/arm64/floatconversion.asm b/src/coreclr/debug/di/arm64/floatconversion.asm deleted file mode 100644 index 8ad73c8884fb41..00000000000000 --- a/src/coreclr/debug/di/arm64/floatconversion.asm +++ /dev/null @@ -1,16 +0,0 @@ -; Licensed to the .NET Foundation under one or more agreements. -; The .NET Foundation licenses this file to you under the MIT license. - -#include "ksarm64.h" - -;; Arguments -;; input: (in X0) the _NEON128 value to be converted to a double -;; output: the double corresponding to the _NEON128 input value - - LEAF_ENTRY FPFillR8 - LDR Q0, [X0] - ret lr - LEAF_END - -;; Must be at very end of file - END diff --git a/src/coreclr/debug/di/cordb.cpp b/src/coreclr/debug/di/cordb.cpp index 036ae1fb217491..295b42f444c2e7 100644 --- a/src/coreclr/debug/di/cordb.cpp +++ b/src/coreclr/debug/di/cordb.cpp @@ -431,18 +431,17 @@ STDAPI GetRequestedRuntimeInfo(LPCWSTR pExe, return E_NOTIMPL; } -#ifdef TARGET_ARM BOOL DbiGetThreadContext(HANDLE hThread, - DT_CONTEXT *lpContext) + T_CONTEXT *lpContext) { // if we aren't local debugging this isn't going to work -#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING +#if defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget"); return FALSE; #else BOOL res = FALSE; - if (((ULONG)lpContext) & ~0x10) + if (((ULONG_PTR)lpContext) & 0xF) { CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16); if (ctx) @@ -450,7 +449,7 @@ DbiGetThreadContext(HANDLE hThread, ctx->ContextFlags = lpContext->ContextFlags; if (::GetThreadContext(hThread, ctx)) { - *lpContext = *(DT_CONTEXT*)ctx; + *lpContext = *(T_CONTEXT*)ctx; res = TRUE; } @@ -474,14 +473,14 @@ DbiGetThreadContext(HANDLE hThread, BOOL DbiSetThreadContext(HANDLE hThread, - const DT_CONTEXT *lpContext) + const T_CONTEXT *lpContext) { -#if !defined(HOST_ARM) || defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING +#if defined(FEATURE_DBGIPC_TRANSPORT_DI) || !SUPPORT_LOCAL_DEBUGGING _ASSERTE(!"Can't use local GetThreadContext remotely, this needed to go to datatarget"); return FALSE; #else BOOL res = FALSE; - if (((ULONG)lpContext) & ~0x10) + if (((ULONG_PTR)lpContext) & 0xF) { CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16); if (ctx) @@ -505,4 +504,3 @@ DbiSetThreadContext(HANDLE hThread, return res; #endif } -#endif diff --git a/src/coreclr/debug/di/i386/cordbregisterset.cpp b/src/coreclr/debug/di/i386/cordbregisterset.cpp deleted file mode 100644 index 1bf9056912536d..00000000000000 --- a/src/coreclr/debug/di/i386/cordbregisterset.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64 *pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); - - (*pAvailable) = SETBITULONG64( REGISTER_INSTRUCTION_POINTER ) - | SETBITULONG64( REGISTER_STACK_POINTER ) - | SETBITULONG64( REGISTER_FRAME_POINTER ); - - if (!m_quickUnwind || m_active) - (*pAvailable) |= SETBITULONG64( REGISTER_X86_EAX ) - | SETBITULONG64( REGISTER_X86_ECX ) - | SETBITULONG64( REGISTER_X86_EDX ) - | SETBITULONG64( REGISTER_X86_EBX ) - | SETBITULONG64( REGISTER_X86_ESI ) - | SETBITULONG64( REGISTER_X86_EDI ); - - if (m_active) - (*pAvailable) |= SETBITULONG64( REGISTER_X86_FPSTACK_0 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_1 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_2 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_3 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_4 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_5 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_6 ) - | SETBITULONG64( REGISTER_X86_FPSTACK_7 ); - - return S_OK; -} - - -#define FPSTACK_FROM_INDEX( _index ) (m_thread->m_floatValues[m_thread->m_floatStackTop -( (REGISTER_X86_FPSTACK_##_index)-REGISTER_X86_FPSTACK_0 ) ] ) - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, - CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - - UINT iRegister = 0; - - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - //If we need some floating point value, tell the thread to get it - if ( mask & ( SETBITULONG64(REGISTER_X86_FPSTACK_0) - | SETBITULONG64(REGISTER_X86_FPSTACK_1) - | SETBITULONG64(REGISTER_X86_FPSTACK_2) - | SETBITULONG64(REGISTER_X86_FPSTACK_3) - | SETBITULONG64(REGISTER_X86_FPSTACK_4) - | SETBITULONG64(REGISTER_X86_FPSTACK_5) - | SETBITULONG64(REGISTER_X86_FPSTACK_6) - | SETBITULONG64(REGISTER_X86_FPSTACK_7 ) ) ) - { - HRESULT hr = S_OK; - - if (!m_active) - return E_INVALIDARG; - - if (!m_thread->m_fFloatStateValid) - { - EX_TRY - { - m_thread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - if ( !SUCCEEDED(hr) ) - { - return hr; - } - LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); - } - } - - // Make sure that the registers are really available - if ( mask & ( SETBITULONG64( REGISTER_X86_EAX ) - | SETBITULONG64( REGISTER_X86_ECX ) - | SETBITULONG64( REGISTER_X86_EDX ) - | SETBITULONG64( REGISTER_X86_EBX ) - | SETBITULONG64( REGISTER_X86_ESI ) - | SETBITULONG64( REGISTER_X86_EDI ) ) ) - { - if (!m_active && m_quickUnwind) - return E_INVALIDARG; - } - - for ( int i = REGISTER_INSTRUCTION_POINTER - ; i<=REGISTER_X86_FPSTACK_7 && iRegister < regCount - ; i++) - { - if( mask & SETBITULONG64(i) ) - { - switch( i ) - { - case REGISTER_INSTRUCTION_POINTER: - regBuffer[iRegister++] = m_context.Eip; break; - case REGISTER_STACK_POINTER: - regBuffer[iRegister++] = m_context.Esp; break; - case REGISTER_FRAME_POINTER: - regBuffer[iRegister++] = m_context.Ebp; break; - case REGISTER_X86_EAX: - regBuffer[iRegister++] = m_context.Eax; break; - case REGISTER_X86_EBX: - regBuffer[iRegister++] = m_context.Ebx; break; - case REGISTER_X86_ECX: - regBuffer[iRegister++] = m_context.Ecx; break; - case REGISTER_X86_EDX: - regBuffer[iRegister++] = m_context.Edx; break; - case REGISTER_X86_ESI: - regBuffer[iRegister++] = m_context.Esi; break; - case REGISTER_X86_EDI: - regBuffer[iRegister++] = m_context.Edi; break; - - //for floats, copy the bits, not the integer part of - //the value, into the register - case REGISTER_X86_FPSTACK_0: - memcpy(®Buffer[iRegister++], - &(FPSTACK_FROM_INDEX(0)), - sizeof(CORDB_REGISTER)); - break; - case REGISTER_X86_FPSTACK_1: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 1 ) ), - sizeof(CORDB_REGISTER) ); - break; - case REGISTER_X86_FPSTACK_2: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 2 ) ), - sizeof(CORDB_REGISTER) ); break; - case REGISTER_X86_FPSTACK_3: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 3 ) ), - sizeof(CORDB_REGISTER) ); break; - case REGISTER_X86_FPSTACK_4: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 4 ) ), - sizeof(CORDB_REGISTER) ); break; - case REGISTER_X86_FPSTACK_5: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 5 ) ), - sizeof(CORDB_REGISTER) ); break; - case REGISTER_X86_FPSTACK_6: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 6 ) ), - sizeof(CORDB_REGISTER) ); break; - case REGISTER_X86_FPSTACK_7: - memcpy( ®Buffer[iRegister++], - & (FPSTACK_FROM_INDEX( 7 ) ), - sizeof(CORDB_REGISTER) ); break; - } - } - } - - _ASSERTE( iRegister <= regCount ); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAvailableAdapter(regCount, pAvailable); -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - // Defer to adapter for v1.0 interface - return GetRegistersAdapter(maskCount, mask, regCount, regBuffer); -} diff --git a/src/coreclr/debug/di/loongarch64/cordbregisterset.cpp b/src/coreclr/debug/di/loongarch64/cordbregisterset.cpp deleted file mode 100644 index faec1079c1b059..00000000000000 --- a/src/coreclr/debug/di/loongarch64/cordbregisterset.cpp +++ /dev/null @@ -1,269 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64* pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); - - *pAvailable = SETBITULONG64(REGISTER_LOONGARCH64_PC) - | SETBITULONG64(REGISTER_LOONGARCH64_SP) - | SETBITULONG64(REGISTER_LOONGARCH64_FP) - | SETBITULONG64(REGISTER_LOONGARCH64_RA) - | SETBITULONG64(REGISTER_LOONGARCH64_TP) - | SETBITULONG64(REGISTER_LOONGARCH64_A0) - | SETBITULONG64(REGISTER_LOONGARCH64_A1) - | SETBITULONG64(REGISTER_LOONGARCH64_A2) - | SETBITULONG64(REGISTER_LOONGARCH64_A3) - | SETBITULONG64(REGISTER_LOONGARCH64_A4) - | SETBITULONG64(REGISTER_LOONGARCH64_A5) - | SETBITULONG64(REGISTER_LOONGARCH64_A6) - | SETBITULONG64(REGISTER_LOONGARCH64_A7) - | SETBITULONG64(REGISTER_LOONGARCH64_T0) - | SETBITULONG64(REGISTER_LOONGARCH64_T1) - | SETBITULONG64(REGISTER_LOONGARCH64_T2) - | SETBITULONG64(REGISTER_LOONGARCH64_T3) - | SETBITULONG64(REGISTER_LOONGARCH64_T4) - | SETBITULONG64(REGISTER_LOONGARCH64_T5) - | SETBITULONG64(REGISTER_LOONGARCH64_T6) - | SETBITULONG64(REGISTER_LOONGARCH64_T7) - | SETBITULONG64(REGISTER_LOONGARCH64_T8) - | SETBITULONG64(REGISTER_LOONGARCH64_X0) - | SETBITULONG64(REGISTER_LOONGARCH64_S0) - | SETBITULONG64(REGISTER_LOONGARCH64_S1) - | SETBITULONG64(REGISTER_LOONGARCH64_S2) - | SETBITULONG64(REGISTER_LOONGARCH64_S3) - | SETBITULONG64(REGISTER_LOONGARCH64_S4) - | SETBITULONG64(REGISTER_LOONGARCH64_S5) - | SETBITULONG64(REGISTER_LOONGARCH64_S6) - | SETBITULONG64(REGISTER_LOONGARCH64_S7) - | SETBITULONG64(REGISTER_LOONGARCH64_S8) - | SETBITULONG64(REGISTER_LOONGARCH64_F0) - | SETBITULONG64(REGISTER_LOONGARCH64_F1) - | SETBITULONG64(REGISTER_LOONGARCH64_F2) - | SETBITULONG64(REGISTER_LOONGARCH64_F3) - | SETBITULONG64(REGISTER_LOONGARCH64_F4) - | SETBITULONG64(REGISTER_LOONGARCH64_F5) - | SETBITULONG64(REGISTER_LOONGARCH64_F6) - | SETBITULONG64(REGISTER_LOONGARCH64_F7) - | SETBITULONG64(REGISTER_LOONGARCH64_F8) - | SETBITULONG64(REGISTER_LOONGARCH64_F9) - | SETBITULONG64(REGISTER_LOONGARCH64_F10) - | SETBITULONG64(REGISTER_LOONGARCH64_F11) - | SETBITULONG64(REGISTER_LOONGARCH64_F12) - | SETBITULONG64(REGISTER_LOONGARCH64_F13) - | SETBITULONG64(REGISTER_LOONGARCH64_F14) - | SETBITULONG64(REGISTER_LOONGARCH64_F15) - | SETBITULONG64(REGISTER_LOONGARCH64_F16) - | SETBITULONG64(REGISTER_LOONGARCH64_F17) - | SETBITULONG64(REGISTER_LOONGARCH64_F18) - | SETBITULONG64(REGISTER_LOONGARCH64_F19) - | SETBITULONG64(REGISTER_LOONGARCH64_F20) - | SETBITULONG64(REGISTER_LOONGARCH64_F21) - | SETBITULONG64(REGISTER_LOONGARCH64_F22) - | SETBITULONG64(REGISTER_LOONGARCH64_F23) - | SETBITULONG64(REGISTER_LOONGARCH64_F24) - | SETBITULONG64(REGISTER_LOONGARCH64_F25) - | SETBITULONG64(REGISTER_LOONGARCH64_F26) - | SETBITULONG64(REGISTER_LOONGARCH64_F27) - | SETBITULONG64(REGISTER_LOONGARCH64_F28) - | SETBITULONG64(REGISTER_LOONGARCH64_F29) - | SETBITULONG64(REGISTER_LOONGARCH64_F30) - | SETBITULONG64(REGISTER_LOONGARCH64_F31); - - return S_OK; -} - -// Reads the value of a single register (identified by a CorDebugRegister index) into *pValue. -// Shared by both GetRegisters overloads to avoid duplicating the per-register mapping. -static HRESULT GetRegisterValue(CordbThread * pThread, const DT_CONTEXT * pContext, int regIndex, CORDB_REGISTER * pValue) -{ - if ((regIndex >= REGISTER_LOONGARCH64_F0) && (regIndex <= REGISTER_LOONGARCH64_F31)) - { - if (!pThread->m_fFloatStateValid) - { - HRESULT hr = S_OK; - EX_TRY - { - pThread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - - if ( !SUCCEEDED(hr) ) - { - return hr; - } - LOG( ( LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n" ) ); - } - - *pValue = *(CORDB_REGISTER*)&(pThread->m_floatValues[(regIndex - REGISTER_LOONGARCH64_F0)]); - return S_OK; - } - - switch (regIndex) - { - case REGISTER_LOONGARCH64_A0: - *pValue = pContext->A0; break; - case REGISTER_LOONGARCH64_A1: - *pValue = pContext->A1; break; - case REGISTER_LOONGARCH64_A2: - *pValue = pContext->A2; break; - case REGISTER_LOONGARCH64_A3: - *pValue = pContext->A3; break; - case REGISTER_LOONGARCH64_A4: - *pValue = pContext->A4; break; - case REGISTER_LOONGARCH64_A5: - *pValue = pContext->A5; break; - case REGISTER_LOONGARCH64_A6: - *pValue = pContext->A6; break; - case REGISTER_LOONGARCH64_A7: - *pValue = pContext->A7; break; - case REGISTER_LOONGARCH64_S0: - *pValue = pContext->S0; break; - case REGISTER_LOONGARCH64_S1: - *pValue = pContext->S1; break; - case REGISTER_LOONGARCH64_S2: - *pValue = pContext->S2; break; - case REGISTER_LOONGARCH64_S3: - *pValue = pContext->S3; break; - case REGISTER_LOONGARCH64_S4: - *pValue = pContext->S4; break; - case REGISTER_LOONGARCH64_S5: - *pValue = pContext->S5; break; - case REGISTER_LOONGARCH64_S6: - *pValue = pContext->S6; break; - case REGISTER_LOONGARCH64_S7: - *pValue = pContext->S7; break; - case REGISTER_LOONGARCH64_S8: - *pValue = pContext->S8; break; - case REGISTER_LOONGARCH64_T0: - *pValue = pContext->T0; break; - case REGISTER_LOONGARCH64_T1: - *pValue = pContext->T1; break; - case REGISTER_LOONGARCH64_T2: - *pValue = pContext->T2; break; - case REGISTER_LOONGARCH64_T3: - *pValue = pContext->T3; break; - case REGISTER_LOONGARCH64_T4: - *pValue = pContext->T4; break; - case REGISTER_LOONGARCH64_T5: - *pValue = pContext->T5; break; - case REGISTER_LOONGARCH64_T6: - *pValue = pContext->T6; break; - case REGISTER_LOONGARCH64_T7: - *pValue = pContext->T7; break; - case REGISTER_LOONGARCH64_T8: - *pValue = pContext->T8; break; - case REGISTER_LOONGARCH64_X0: - *pValue = pContext->X0; break; - case REGISTER_LOONGARCH64_PC: - *pValue = pContext->Pc; break; - case REGISTER_LOONGARCH64_SP: - *pValue = pContext->Sp; break; - case REGISTER_LOONGARCH64_FP: - *pValue = pContext->Fp; break; - case REGISTER_LOONGARCH64_RA: - *pValue = pContext->Ra; break; - case REGISTER_LOONGARCH64_TP: - *pValue = pContext->Tp; break; - default: - _ASSERTE(false); break; - } - - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, - CORDB_REGISTER regBuffer[]) -{ - PUBLIC_REENTRANT_API_ENTRY(this); - FAIL_IF_NEUTERED(this); - ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - - UINT iRegister = 0; - - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - for (int i = REGISTER_LOONGARCH64_PC; - i <= REGISTER_LOONGARCH64_F31 && iRegister < regCount; - i++) - { - if (mask & SETBITULONG64(i)) - { - _ASSERTE (iRegister < regCount); - - HRESULT hr = GetRegisterValue(m_thread, &m_context, i, ®Buffer[iRegister]); - if (FAILED(hr)) - { - return hr; - } - iRegister++; - } - } - - _ASSERTE (iRegister <= regCount); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); - - for (int i = 0 ; i < (int)regCount ; ++i) - { - if (i * 8 <= REGISTER_LOONGARCH64_F31) - { - pAvailable[i] = (i * 8 == REGISTER_LOONGARCH64_F31) ? BYTE(0x1) : BYTE(0xff); - } - else - { - pAvailable[i] = 0; - } - } - - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); - - UINT iRegister = 0; - - for (int m = 0 ; m < (int)maskCount ; ++m) - { - for (int bit = 0 ; bit < 8 ; ++bit) - { - if (mask[m] & SETBITULONG64(bit)) - { - _ASSERTE (iRegister < regCount); - - int i = m * 8 + bit; - - HRESULT hr = GetRegisterValue(m_thread, &m_context, i, ®Buffer[iRegister]); - if (FAILED(hr)) - { - return hr; - } - iRegister++; - } - } - } - - return S_OK; -} diff --git a/src/coreclr/debug/di/loongarch64/floatconversion.S b/src/coreclr/debug/di/loongarch64/floatconversion.S deleted file mode 100644 index 83043e4ee66ca2..00000000000000 --- a/src/coreclr/debug/di/loongarch64/floatconversion.S +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include - -// Arguments -// input: (in A0) the value to be converted to a double -// output: the double corresponding to the _NEON128 input value -LEAF_ENTRY FPFillR8, .TEXT - ld.d $a0, $a0, 0 - jirl $r0, $ra, 0 -LEAF_END FPFillR8, .TEXT diff --git a/src/coreclr/debug/di/module.cpp b/src/coreclr/debug/di/module.cpp index 052dc4413676da..2b8c8d6af064bd 100644 --- a/src/coreclr/debug/di/module.cpp +++ b/src/coreclr/debug/di/module.cpp @@ -3842,15 +3842,14 @@ HRESULT CordbVariableHome::GetRegister(CorDebugRegister *pRegister) switch (m_nativeVarInfo.loc.vlType) { case ICorDebugInfo::VLT_REG: - *pRegister = ConvertRegNumToCorDebugRegister(m_nativeVarInfo.loc.vlReg.vlrReg); - break; + return m_pCode->GetProcess()->ConvertJitRegNumToCorDebugRegister( + m_nativeVarInfo.loc.vlReg.vlrReg, pRegister); case ICorDebugInfo::VLT_STK: - *pRegister = ConvertRegNumToCorDebugRegister(m_nativeVarInfo.loc.vlStk.vlsBaseReg); - break; + return m_pCode->GetProcess()->ConvertJitRegNumToCorDebugRegister( + m_nativeVarInfo.loc.vlStk.vlsBaseReg, pRegister); default: return E_FAIL; } - return S_OK; } //----------------------------------------------------------------------------- diff --git a/src/coreclr/debug/di/platformspecific.cpp b/src/coreclr/debug/di/platformspecific.cpp index cd690dccc2fd25..f57c9db0cf66fe 100644 --- a/src/coreclr/debug/di/platformspecific.cpp +++ b/src/coreclr/debug/di/platformspecific.cpp @@ -22,22 +22,16 @@ #endif #if TARGET_X86 -#include "i386/cordbregisterset.cpp" #include "i386/primitives.cpp" #elif TARGET_AMD64 -#include "amd64/cordbregisterset.cpp" #include "amd64/primitives.cpp" #elif TARGET_ARM -#include "arm/cordbregisterset.cpp" #include "arm/primitives.cpp" #elif TARGET_ARM64 -#include "arm64/cordbregisterset.cpp" #include "arm64/primitives.cpp" #elif TARGET_LOONGARCH64 -#include "loongarch64/cordbregisterset.cpp" #include "loongarch64/primitives.cpp" #elif TARGET_RISCV64 -#include "riscv64/cordbregisterset.cpp" #include "riscv64/primitives.cpp" #else #error Unsupported platform diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index cf1dc0d0ee0571..c8e46b4c6f04c1 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -648,6 +648,14 @@ IDacDbiInterface * CordbProcess::GetDAC() return m_pDacPrimitives; } +HRESULT CordbProcess::ConvertJitRegNumToCorDebugRegister(ULONG32 jitRegNum, CorDebugRegister * pReg) +{ + if (pReg == NULL) + return E_INVALIDARG; + + return GetDAC()->ConvertJitRegNumToCorDebugRegister(jitRegNum, pReg); +} + //--------------------------------------------------------------------------------------- // Get the Data-Target // @@ -855,7 +863,8 @@ CordbProcess::CordbProcess(ULONG64 clrInstanceId, m_pEventChannel(NULL), m_fAssertOnTargetInconsistency(false), m_runtimeOffsetsInitialized(false), - m_writableMetadataUpdateMode(LegacyCompatPolicy) + m_writableMetadataUpdateMode(LegacyCompatPolicy), + m_ctxSize(0) #ifdef OUT_OF_PROCESS_SETTHREADCONTEXT , m_dwOutOfProcessStepping(0), @@ -1447,6 +1456,21 @@ void CordbProcess::FreeDac() } } +ULONG32 CordbProcess::GetTargetContextSize() +{ + if (!IsDacInitialized()) + { + return sizeof(T_CONTEXT); + } + if (m_ctxSize == 0) + { + ULONG32 size = 0; + IfFailThrow(GetDAC()->GetTargetContextSize(IDacDbiInterface::kContextSizeExtendedRegisters, &size)); + m_ctxSize = size; + } + return m_ctxSize; +} + IEventChannel * CordbProcess::GetEventChannel() { _ASSERTE(m_pEventChannel != NULL); @@ -5791,7 +5815,7 @@ HRESULT CordbProcess::IsOSSuspended(DWORD threadID, BOOL *pbSuspended) // record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate // space for the extended registers. However, the CONTEXT struct that we compile with does have this space. // -HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, DT_CONTEXT * pCtx) +HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, BYTE * pCtx) { HRESULT hr = S_OK; @@ -5802,7 +5826,8 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, DT_CONTEXT * { void *pRemoteContext = pContext.UnsafeGet(); - TargetBuffer tbFull(pRemoteContext, sizeof(DT_CONTEXT)); + ULONG32 fullContextSize = GetTargetContextSize(); + TargetBuffer tbFull(pRemoteContext, fullContextSize); // The context may have 2 parts: // 1. Base register, which are always present. @@ -5810,32 +5835,30 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, DT_CONTEXT * // in the flags. // At a minimum we have room for a whole context up to the extended registers. - #if defined(DT_CONTEXT_EXTENDED_REGISTERS) - ULONG32 minContextSize = offsetof(DT_CONTEXT, ExtendedRegisters); - #else - ULONG32 minContextSize = sizeof(DT_CONTEXT); - #endif + ULONG32 minContextSize; + IfFailThrow(GetDAC()->GetTargetContextSize(IDacDbiInterface::kContextSizeBase, &minContextSize)); // Read the minimum part. TargetBuffer tbMin = tbFull.SubBuffer(0, minContextSize); SafeReadBuffer(tbMin, (BYTE*) pCtx); - #if defined(DT_CONTEXT_EXTENDED_REGISTERS) - void *pCurExtReg = (void*)((UINT_PTR)pCtx + minContextSize); - TargetBuffer tbExtended = tbFull.SubBuffer(minContextSize); - - // Now, read the extended registers if the context contains them. If the context does not have extended registers, - // just set them to zero. - if (SUCCEEDED(hr) && (pCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) - { - SafeReadBuffer(tbExtended, (BYTE*) pCurExtReg); - } - else + if (fullContextSize > minContextSize) { - memset(pCurExtReg, 0, tbExtended.cbSize); - } - #endif + void *pCurExtReg = (void*)((UINT_PTR)pCtx + minContextSize); + TargetBuffer tbExtended = tbFull.SubBuffer(minContextSize); + BOOL hasExtendedRegisters = FALSE; + IfFailThrow(GetDAC()->ContextHasExtendedRegisters(pCtx, fullContextSize, &hasExtendedRegisters)); + + if (hasExtendedRegisters) + { + SafeReadBuffer(tbExtended, (BYTE*) pCurExtReg); + } + else + { + memset(pCurExtReg, 0, tbExtended.cbSize); + } + } } EX_CATCH_HRESULT(hr); return hr; @@ -5846,25 +5869,23 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, DT_CONTEXT * // record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate // space for the extended registers. However, the CONTEXT struct that we compile with does have this space. // -HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const DT_CONTEXT * pCtx) +HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const BYTE * pCtx) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); HRESULT hr = S_OK; - DWORD sizeToWrite = sizeof(DT_CONTEXT); + ULONG32 sizeToWrite; + BOOL hasExtendedRegisters = FALSE; + IfFailThrow(GetDAC()->ContextHasExtendedRegisters(const_cast(pCtx), GetTargetContextSize(), &hasExtendedRegisters)); + IfFailThrow(GetDAC()->GetTargetContextSize( + hasExtendedRegisters ? IDacDbiInterface::kContextSizeExtendedRegisters : IDacDbiInterface::kContextSizeBase, + &sizeToWrite)); + IDacDbiInterface::TargetInfo targetInfo; BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); BYTE * pCtxSource = (BYTE*) pCtx; - - -#if defined(DT_CONTEXT_EXTENDED_REGISTERS) - // If our context has extended registers, then write the whole thing. Otherwise, just write the minimum part. - if ((pCtx->ContextFlags & DT_CONTEXT_EXTENDED_REGISTERS) != DT_CONTEXT_EXTENDED_REGISTERS) - { - sizeToWrite = offsetof(DT_CONTEXT, ExtendedRegisters); - } -#endif + IfFailThrow(GetDAC()->GetTargetInfo(&targetInfo)); // 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that // kernel to usermode transitions don't have to allocate a CONTEXT and do a separate sub rsp @@ -5873,11 +5894,12 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const DT_CO // can think of these members as not being part of the context, ie they don't represent something // which gets saved or restored on context switches. They are just space we shouldn't overwrite. // See issue 630276 for more details. -#if defined TARGET_AMD64 - pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 - pCtxSource += offsetof(CONTEXT, ContextFlags); - sizeToWrite -= offsetof(CONTEXT, ContextFlags); -#endif + if (targetInfo.arch == IDacDbiInterface::kArchAMD64) + { + pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 + pCtxSource += offsetof(CONTEXT, ContextFlags); + sizeToWrite -= offsetof(CONTEXT, ContextFlags); + } EX_TRY { @@ -5890,22 +5912,41 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const DT_CO return hr; } - -HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE context[]) +HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, T_CONTEXT * pCtx) { - PUBLIC_REENTRANT_API_ENTRY(this); + INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); - LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x\n", threadID)); - DT_CONTEXT * pContext; + HRESULT hr = S_OK; + DWORD sizeToWrite = sizeof(T_CONTEXT); - if (contextSize < sizeof(DT_CONTEXT)) + BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); + BYTE * pCtxSource = (BYTE*) pCtx; + + +#if defined(CONTEXT_EXTENDED_REGISTERS) + if ((pCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { - LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID)); - return E_INVALIDARG; + sizeToWrite = offsetof(T_CONTEXT, SegSs) + sizeof(pCtx->SegSs); } +#endif - pContext = reinterpret_cast(context); + EX_TRY + { + TargetBuffer tb(pRemoteContext, sizeToWrite); + SafeWriteBuffer(tb, (const BYTE*) pCtxSource); + } + EX_CATCH_HRESULT(hr); + + return hr; +} + + +HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE context[]) +{ + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x\n", threadID)); VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true); @@ -5924,7 +5965,7 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE return E_INVALIDARG; } - return ut->GetThreadContext((DT_CONTEXT*)context); + return ut->GetThreadContext(reinterpret_cast(context)); #else return E_NOTIMPL; #endif @@ -5937,6 +5978,11 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE HRESULT hr = S_OK; EX_TRY { + if (contextSize < GetTargetContextSize()) + { + LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID)); + return E_INVALIDARG; + } CordbThread* thread = this->TryLookupThreadByVolatileOSId(threadID); if (thread == NULL) { @@ -5946,9 +5992,9 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE } else { - DT_CONTEXT* managedContext; - hr = thread->GetManagedContext(&managedContext); - *pContext = *managedContext; + BYTE * managedContext = NULL; + IfFailThrow(thread->GetManagedContext(&managedContext)); + memcpy(context, managedContext, GetTargetContextSize()); } } EX_CATCH_HRESULT(hr) @@ -5969,14 +6015,12 @@ HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE FAIL_IF_NEUTERED(this); VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true); - if (contextSize != sizeof(DT_CONTEXT)) + if (contextSize != GetTargetContextSize()) { LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, context size is invalid.\n", threadID)); return E_INVALIDARG; } - DT_CONTEXT* pContext = (DT_CONTEXT*)context; - if (this->IsInteropDebugging()) { #ifdef FEATURE_INTEROP_DEBUGGING @@ -5993,7 +6037,7 @@ HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE return E_INVALIDARG; } - hr = ut->SetThreadContext(pContext); + hr = ut->SetThreadContext(reinterpret_cast(context)); // Update the register set for the leaf-unmanaged chain so that it's consistent w/ the context. // We may not necessarily be synchronized, and so these frames may be stale. Even so, no harm done. @@ -6035,7 +6079,7 @@ HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE hr = E_INVALIDARG; } - hr = thread->SetManagedContext(pContext); + hr = thread->SetManagedContext(context, contextSize); } EX_CATCH { @@ -10365,7 +10409,7 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) PRD_TYPE m_opcode = 0; public: - void Update(DT_CONTEXT * pContext) + void Update(T_CONTEXT * pContext) { this->m_lsContextAddr = (TADDR)pContext->Rcx; this->m_contextSize = (DWORD)pContext->Rdx; @@ -10444,13 +10488,13 @@ bool CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) return CORDBG_E_BAD_THREAD_STATE; } - DT_CONTEXT context = { 0 }; + T_CONTEXT context = { 0 }; context.ContextFlags = CONTEXT_FULL; // we originally used GetDataTarget()->GetThreadContext, but // the implementation uses ShimLocalDataTarget::GetThreadContext which // depends on OpenThread which might fail with an Access Denied error (see note above) - BOOL success = ::GetThreadContext(m_hThread, (CONTEXT*)(&context)); + BOOL success = ::GetThreadContext(m_hThread, &context); if (!success) { return HRESULT_FROM_WIN32(GetLastError()); @@ -11953,9 +11997,9 @@ Reaction CordbProcess::TriageExcep1stChanceAndInit(CordbUnmanagedThread * pUnman // WFDE will pick it up) but before we realize it's one of ours. STRESS_LOG2(LF_CORDB, LL_INFO1000, "CP::TE1stCAI: Phantom Int3: Tid=0x%x, addr=%p\n", pEvent->dwThreadId, pExAddress); - DT_CONTEXT context; + T_CONTEXT context; - context.ContextFlags = DT_CONTEXT_FULL; + context.ContextFlags = CONTEXT_FULL; BOOL fSuccess = DbiGetThreadContext(pUnmanagedThread->m_handle, &context); @@ -12447,8 +12491,8 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven //Verify that GetThreadContext agrees with the exception address if (pEvent->dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { - DT_CONTEXT tempDebugContext; - tempDebugContext.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT tempDebugContext; + tempDebugContext.ContextFlags = CONTEXT_FULL; DbiGetThreadContext(pUnmanagedThread->m_handle, &tempDebugContext); CordbUnmanagedThread::LogContext(&tempDebugContext); #if defined(TARGET_X86) || defined(TARGET_AMD64) @@ -12655,11 +12699,11 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven if(pUnmanagedThread->IsFirstChanceHijacked()) { LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: hijack complete will restore context...\n")); - DT_CONTEXT tempContext = { 0 }; -#if defined(DT_CONTEXT_EXTENDED_REGISTERS) - tempContext.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS; + T_CONTEXT tempContext = { 0 }; +#if defined(CONTEXT_EXTENDED_REGISTERS) + tempContext.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else - tempContext.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT; + tempContext.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; #endif HRESULT hr = pUnmanagedThread->GetThreadContext(&tempContext); _ASSERTE(SUCCEEDED(hr)); @@ -13092,8 +13136,8 @@ void EnableDebugTrace(CordbUnmanagedThread *ut) // Get the context HRESULT hr = S_OK; - DT_CONTEXT context; - context.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT context; + context.ContextFlags = CONTEXT_FULL; hr = pProcess->GetThreadContext((DWORD) ut->m_id, sizeof(context), (BYTE*)&context); diff --git a/src/coreclr/debug/di/riscv64/cordbregisterset.cpp b/src/coreclr/debug/di/riscv64/cordbregisterset.cpp deleted file mode 100644 index abda3421346d98..00000000000000 --- a/src/coreclr/debug/di/riscv64/cordbregisterset.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -//***************************************************************************** -// File: CordbRegisterSet.cpp -// - -// -//***************************************************************************** -#include "primitives.h" - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64* pAvailable) -{ - FAIL_IF_NEUTERED(this); - VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); - - *pAvailable = SETBITULONG64(REGISTER_RISCV64_PC) - | SETBITULONG64(REGISTER_RISCV64_RA) - | SETBITULONG64(REGISTER_RISCV64_SP) - | SETBITULONG64(REGISTER_RISCV64_GP) - | SETBITULONG64(REGISTER_RISCV64_TP) - | SETBITULONG64(REGISTER_RISCV64_T0) - | SETBITULONG64(REGISTER_RISCV64_T1) - | SETBITULONG64(REGISTER_RISCV64_T2) - | SETBITULONG64(REGISTER_RISCV64_FP) - | SETBITULONG64(REGISTER_RISCV64_S1) - | SETBITULONG64(REGISTER_RISCV64_A0) - | SETBITULONG64(REGISTER_RISCV64_A1) - | SETBITULONG64(REGISTER_RISCV64_A2) - | SETBITULONG64(REGISTER_RISCV64_A3) - | SETBITULONG64(REGISTER_RISCV64_A4) - | SETBITULONG64(REGISTER_RISCV64_A5) - | SETBITULONG64(REGISTER_RISCV64_A6) - | SETBITULONG64(REGISTER_RISCV64_A7) - | SETBITULONG64(REGISTER_RISCV64_S2) - | SETBITULONG64(REGISTER_RISCV64_S3) - | SETBITULONG64(REGISTER_RISCV64_S4) - | SETBITULONG64(REGISTER_RISCV64_S5) - | SETBITULONG64(REGISTER_RISCV64_S6) - | SETBITULONG64(REGISTER_RISCV64_S7) - | SETBITULONG64(REGISTER_RISCV64_S8) - | SETBITULONG64(REGISTER_RISCV64_S9) - | SETBITULONG64(REGISTER_RISCV64_S10) - | SETBITULONG64(REGISTER_RISCV64_S11) - | SETBITULONG64(REGISTER_RISCV64_T3) - | SETBITULONG64(REGISTER_RISCV64_T4) - | SETBITULONG64(REGISTER_RISCV64_T5) - | SETBITULONG64(REGISTER_RISCV64_T6) - | SETBITULONG64(REGISTER_RISCV64_F0) - | SETBITULONG64(REGISTER_RISCV64_F1) - | SETBITULONG64(REGISTER_RISCV64_F2) - | SETBITULONG64(REGISTER_RISCV64_F3) - | SETBITULONG64(REGISTER_RISCV64_F4) - | SETBITULONG64(REGISTER_RISCV64_F5) - | SETBITULONG64(REGISTER_RISCV64_F6) - | SETBITULONG64(REGISTER_RISCV64_F7) - | SETBITULONG64(REGISTER_RISCV64_F8) - | SETBITULONG64(REGISTER_RISCV64_F9) - | SETBITULONG64(REGISTER_RISCV64_F10) - | SETBITULONG64(REGISTER_RISCV64_F11) - | SETBITULONG64(REGISTER_RISCV64_F12) - | SETBITULONG64(REGISTER_RISCV64_F13) - | SETBITULONG64(REGISTER_RISCV64_F14) - | SETBITULONG64(REGISTER_RISCV64_F15) - | SETBITULONG64(REGISTER_RISCV64_F16) - | SETBITULONG64(REGISTER_RISCV64_F17) - | SETBITULONG64(REGISTER_RISCV64_F18) - | SETBITULONG64(REGISTER_RISCV64_F19) - | SETBITULONG64(REGISTER_RISCV64_F20) - | SETBITULONG64(REGISTER_RISCV64_F21) - | SETBITULONG64(REGISTER_RISCV64_F22) - | SETBITULONG64(REGISTER_RISCV64_F23) - | SETBITULONG64(REGISTER_RISCV64_F24) - | SETBITULONG64(REGISTER_RISCV64_F25) - | SETBITULONG64(REGISTER_RISCV64_F26) - | SETBITULONG64(REGISTER_RISCV64_F27) - | SETBITULONG64(REGISTER_RISCV64_F28) - | SETBITULONG64(REGISTER_RISCV64_F29) - | SETBITULONG64(REGISTER_RISCV64_F30) - | SETBITULONG64(REGISTER_RISCV64_F31); - - return S_OK; -} - -HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, - CORDB_REGISTER regBuffer[]) -{ - _ASSERTE(!"RISCV64:NYI"); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, - BYTE pAvailable[]) -{ - _ASSERTE(!"RISCV64:NYI"); - return S_OK; -} - - -HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - _ASSERTE(!"RISCV64:NYI"); - return S_OK; -} diff --git a/src/coreclr/debug/di/riscv64/floatconversion.S b/src/coreclr/debug/di/riscv64/floatconversion.S deleted file mode 100644 index 138db0bc9dd243..00000000000000 --- a/src/coreclr/debug/di/riscv64/floatconversion.S +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include - -// Arguments -// input: (in A0) the address of the ULONGLONG to be converted to a double -// output: the double corresponding to the ULONGLONG input value -LEAF_ENTRY FPFillR8, .TEXT - fld fa0, 0(a0) - ret -LEAF_END FPFillR8, .TEXT diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index ace851825d6721..6ff92b165cac1f 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -3583,8 +3583,9 @@ class CordbProcess : void AddToLeftSideResourceCleanupList(CordbBase * pObject); // Routines to read and write thread context records between the processes safely. - HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, DT_CONTEXT * pCtx); - HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, const DT_CONTEXT * pCtx); + HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, BYTE * pCtx); + HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, const BYTE * pCtx); + HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, T_CONTEXT * pCtx); #ifdef FEATURE_INTEROP_DEBUGGING // Record a win32 event for debugging purposes. @@ -3598,6 +3599,8 @@ class CordbProcess : // Get the DAC interface. IDacDbiInterface * GetDAC(); + HRESULT ConvertJitRegNumToCorDebugRegister(ULONG32 jitRegNum, CorDebugRegister * pReg); + // Get the data-target, which provides access to the debuggee. ICorDebugDataTarget * GetDataTarget(); @@ -4003,6 +4006,7 @@ class CordbProcess : #endif // FEATURE_INTEROP_DEBUGGING bool IsBreakOpcodeAtAddress(const void * address); + ULONG32 GetTargetContextSize(); private: // @@ -4097,6 +4101,7 @@ class CordbProcess : // controls how metadata updated in the target is handled WriteableMetadataUpdateMode m_writableMetadataUpdateMode; + ULONG32 m_ctxSize; COM_METHOD GetObjectInternal(CORDB_ADDRESS addr, ICorDebugObjectValue **pObject); @@ -6076,18 +6081,6 @@ class CordbThread : public CordbBase, public ICorDebugThread, void MarkStackFramesDirty(); -#if defined(TARGET_X86) - // Converts the values in the floating point register area of the context to real number values. - void Get32bitFPRegisters(CONTEXT * pContext); - -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) - // Converts the values in the floating point register area of the context to real number values. - void Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters); - -#endif // TARGET_X86 - - // Initializes the float state members of this instance of CordbThread. This function gets the context and - // converts the floating point values from their context representation to real number values. void LoadFloatState(); @@ -6133,8 +6126,8 @@ class CordbThread : public CordbBase, public ICorDebugThread, // // ////////////////////////////////////////////////////////////////////////// - HRESULT GetManagedContext( DT_CONTEXT ** ppContext ); - HRESULT SetManagedContext( DT_CONTEXT * pContext ); + HRESULT GetManagedContext(BYTE ** ppContext); + HRESULT SetManagedContext(BYTE * pContext, ULONG32 cbCtx); // API to retrieve the thread handle from the LS. void InternalGetHandle(HANDLE * phThread); @@ -6177,7 +6170,8 @@ class CordbThread : public CordbBase, public ICorDebugThread, BOOL IsThreadExceptionManaged(); // This is a private hook for the shim to create a CordbRegisterSet for a ShimChain. - void CreateCordbRegisterSet(DT_CONTEXT * pContext, + void CreateCordbRegisterSet(const BYTE * pContext, + ULONG32 contextSize, BOOL fActive, CorDebugChainReason reason, ICorDebugRegisterSet ** ppRegSet); @@ -6193,8 +6187,7 @@ class CordbThread : public CordbBase, public ICorDebugThread, public: // RS Cache for LS context. - // NULL if we haven't allocated memory for a Right side context - DT_CONTEXT * m_pContext; + NewArrayHolder m_pContext; // Set to the CONTEXT pointer in the LS if this LS thread is // stopped in managed code. This may be either stopped for execution control @@ -6235,7 +6228,9 @@ class CordbThread : public CordbBase, public ICorDebugThread, bool m_fFloatStateValid; unsigned int m_floatStackTop; - double m_floatValues[DebuggerIPCE_FloatCount]; + int m_firstFloatReg; + ULONG32 m_floatValuesCount; + double m_floatValues[CORDB_MAX_FLOAT_REGISTERS]; private: // True for the window after an Exception callback, but before it's been continued. @@ -6374,8 +6369,7 @@ class CordbStackWalk : public CordbBase, public ICorDebugStackWalk // This is the same iterator used by the runtime itself. IDacDbiInterface::StackWalkHandle m_pSFIHandle; - // buffers used for stackwalking - DT_CONTEXT m_context; + NewArrayHolder m_pContextBuffer; // Used to figure out if we have to refresh any reference objects // on the left side. We set it to CordbProcess::m_flushCounter on @@ -6480,7 +6474,10 @@ class CordbFrame : public CordbBase, public ICorDebugFrame // This is basically a complicated cast function. We are casting from an ICorDebugFrame to a CordbFrame. static CordbFrame* GetCordbFrameFromInterface(ICorDebugFrame *pFrame); - virtual const DT_CONTEXT * GetContext() const { return NULL; } + virtual const BYTE * GetContext() const { return NULL; } + + // Reads an integer register from this frame's CONTEXT buffer via the DAC. + HRESULT ReadContextRegister(CorDebugRegister reg, TADDR * pValue) const; public: // this represents the IL offset for a CordbJITILFrame, the native offset for a CordbNativeFrame, @@ -6677,7 +6674,7 @@ class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUn CordbRuntimeUnwindableFrame(CordbThread * pThread, FramePointer fp, CordbAppDomain * pCurrentAppDomain, - DT_CONTEXT * pContext); + BYTE * pContext); virtual void Neuter(); @@ -6759,10 +6756,11 @@ class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUn return NULL; } - virtual const DT_CONTEXT * GetContext() const; + virtual const BYTE * GetContext() const; private: - DT_CONTEXT m_context; + NewArrayHolder m_pContextBuffer; + }; // Function signature for retrieving a value at a specific index @@ -6849,7 +6847,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public TADDR addrAmbientESP, CordbAppDomain * pCurrentAppDomain, CordbMiscFrame * pMisc = NULL, - DT_CONTEXT * pContext = NULL); + BYTE * pContext = NULL); virtual ~CordbNativeFrame(); virtual void Neuter(); @@ -6960,7 +6958,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public CordbFunction * GetFunction(); CordbNativeCode * GetNativeCode(); - virtual const DT_CONTEXT * GetContext() const; + virtual const BYTE * GetContext() const; // Given the native variable information of a variable, return its value. // This function assumes that the value is either in a register or on the stack @@ -6988,12 +6986,17 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public CorDebugRegister lowWordRegister, CordbType * pType, ICorDebugValue **ppValue); - UINT_PTR * GetAddressOfRegister(CorDebugRegister regNum) const; CORDB_ADDRESS GetLeftSideAddressOfRegister(CorDebugRegister regNum) const; HRESULT GetLocalFloatingPointValue(DWORD index, CordbType * pType, ICorDebugValue **ppValue); + HRESULT ReadJitRegFromContext(ULONG32 jitRegNum, TADDR * pValue) const; + + CorDebugRegister ConvertJitRegToCorDebugRegister(ULONG32 jitRegNum) const; + + CORDB_ADDRESS GetStackPointer() const; + CORDB_ADDRESS GetLSStackAddress(ICorDebugInfo::RegNum regNum, signed offset); @@ -7013,7 +7016,6 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public SIZE_T GetParentIP(); TADDR GetAmbientESP() { return m_taAmbientESP; } - TADDR GetReturnRegisterValue(); // accessor for the shim private hook code:CordbThread::ConvertFrameForILMethodWithoutMetadata BOOL ConvertNativeFrameForILMethodWithoutMetadata(ICorDebugInternalFrame2 ** ppInternalFrame2); @@ -7023,7 +7025,6 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public //----------------------------------------------------------- public: - // each CordbNativeFrame corresponds to exactly one CordbJITILFrame and one CordbNativeCode RSSmartPtr m_JITILFrame; RSSmartPtr m_nativeCode; @@ -7035,8 +7036,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public // the ambient SP value only used on x86 to retrieve sp-relative local variables // (most likely in a frameless method) TADDR m_taAmbientESP; - - DT_CONTEXT m_context; + NewArrayHolder m_pContextBuffer; }; @@ -7058,10 +7058,12 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public ICorDebugRegisterSet2 { public: - CordbRegisterSet(CordbThread * pThread, - DT_CONTEXT * pContext, + CordbRegisterSet(const BYTE * pContextBuffer, + ULONG32 contextSize, + CordbThread * pThread, bool fActive, - bool fQuickUnwind); + bool fQuickUnwind, + bool fTakeOwnershipOfContext = false); ~CordbRegisterSet(); @@ -7157,15 +7159,13 @@ class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public I } protected: - - // Adapters to impl v2.0 interfaces on top of v1.0 interfaces. - HRESULT GetRegistersAvailableAdapter(ULONG32 regCount, BYTE pAvailable[]); - HRESULT GetRegistersAdapter(ULONG32 maskCount, BYTE mask[], ULONG32 regCount, CORDB_REGISTER regBuffer[]); - - DT_CONTEXT m_context; + BYTE *m_pContext; + ULONG32 m_contextSize; CordbThread *m_thread; bool m_active; // true if we're the leafmost register set. bool m_quickUnwind; + + bool m_fOwnsContext; } ; @@ -7722,7 +7722,7 @@ class EnregisteredValueHome // Note: Throws E_FAIL for invalid input or various HRESULTs from an // unsuccessful call to WriteProcessMemory virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) = 0; + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) = 0; // Gets an enregistered value and returns it to the caller // Arguments: @@ -7774,7 +7774,7 @@ class RegValueHome: public EnregisteredValueHome EnregisteredValueHome(pFrame), m_reg1Info(regNum, pFrame->GetLeftSideAddressOfRegister(regNum), - *(pFrame->GetAddressOfRegister(regNum))) + ReadFrameRegister(pFrame, regNum)) {}; // copy constructor @@ -7791,14 +7791,13 @@ class RegValueHome: public EnregisteredValueHome virtual RegValueHome * Clone() const { return new RegValueHome(*this); }; - // updates a register in a given context, and in the regdisplay of a given frame. - void SetContextRegister(DT_CONTEXT * pContext, + void SetContextRegister(BYTE * pContext, CorDebugRegister regNum, SIZE_T newVal); // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -7808,6 +7807,15 @@ class RegValueHome: public EnregisteredValueHome virtual void CopyToIPCEType(RemoteAddress * pRegAddr); +protected: + static SIZE_T ReadFrameRegister(const CordbNativeFrame * pFrame, CorDebugRegister regNum) + { + TADDR v = 0; + HRESULT hr = pFrame->ReadContextRegister(regNum, &v); + IfFailThrow(hr); + return (SIZE_T)v; + } + //------------------------------------- // data members //------------------------------------- @@ -7839,7 +7847,7 @@ class RegRegValueHome: public RegValueHome RegValueHome(pFrame, reg1Num), m_reg2Info(reg2Num, pFrame->GetLeftSideAddressOfRegister(reg2Num), - *(pFrame->GetAddressOfRegister(reg2Num))) + ReadFrameRegister(pFrame, reg2Num)) {}; // copy constructor @@ -7858,7 +7866,7 @@ class RegRegValueHome: public RegValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -7915,7 +7923,7 @@ class RegAndMemBaseValueHome: public RegValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * DT_pContext, bool fIsSigned) = 0; + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) = 0; // Gets an enregistered value and returns it to the caller virtual @@ -7973,7 +7981,7 @@ class RegMemValueHome: public RegAndMemBaseValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -8023,7 +8031,7 @@ class MemRegValueHome: public RegAndMemBaseValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -8068,7 +8076,7 @@ class FloatRegValueHome: public EnregisteredValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -10361,8 +10369,8 @@ class CordbUnmanagedThread : public CordbBase // These are wrappers for the OS calls which hide // the effects of hijacking and internal SS flag usage - HRESULT GetThreadContext(DT_CONTEXT * pContext); - HRESULT SetThreadContext(DT_CONTEXT * pContext); + HRESULT GetThreadContext(T_CONTEXT * pContext); + HRESULT SetThreadContext(T_CONTEXT * pContext); // Turns on and off the internal usage of the SS flag VOID BeginStepping(); @@ -10370,7 +10378,7 @@ class CordbUnmanagedThread : public CordbBase // An accessor for &m_context, this value generally stores // a context we may need to restore after a hijack completes - DT_CONTEXT * GetHijackCtx(); + T_CONTEXT * GetHijackCtx(); private: CORDB_ADDRESS m_stackBase; @@ -10407,9 +10415,7 @@ class CordbUnmanagedThread : public CordbBase } void ClearState(CordbUnmanagedThreadState state) {LIMITED_METHOD_CONTRACT; m_state = (CordbUnmanagedThreadState)(m_state & ~state); } - void HijackToRaiseException(); void RestoreFromRaiseExceptionHijack(); - void SaveRaiseExceptionEntryContext(); void ClearRaiseExceptionEntryContext(); BOOL IsExceptionFromLastRaiseException(const EXCEPTION_RECORD* pExceptionRecord); @@ -10430,7 +10436,7 @@ class CordbUnmanagedThread : public CordbBase #endif // Logs basic data about a context to the debugging log - static VOID LogContext(DT_CONTEXT* pContext); + static VOID LogContext(T_CONTEXT* pContext); public: HANDLE m_handle; @@ -10459,10 +10465,7 @@ class CordbUnmanagedThread : public CordbBase private: // Spare context used for various purposes. // See CordbUnmanagedThread::GetThreadContext for details - DT_CONTEXT m_context; - - // The context of the thread the last time it called into kernel32!RaiseException - DT_CONTEXT m_raiseExceptionEntryContext; + T_CONTEXT m_context; DWORD m_raiseExceptionExceptionCode; DWORD m_raiseExceptionExceptionFlags; diff --git a/src/coreclr/debug/di/rsregsetcommon.cpp b/src/coreclr/debug/di/rsregsetcommon.cpp index c5f7e85ee3cca4..5a7fd605bd7fbe 100644 --- a/src/coreclr/debug/di/rsregsetcommon.cpp +++ b/src/coreclr/debug/di/rsregsetcommon.cpp @@ -4,9 +4,10 @@ // File: RSRegSetCommon.cpp // -// Common cross-platform behavior of reg sets. -// Platform specific stuff is in CordbRegisterSet.cpp located in -// the platform sub-dir. +// Common cross-platform behavior of reg sets. The ICorDebugRegisterSet / +// ICorDebugRegisterSet2 surface is implemented in CordbRegisterSet.cpp using the +// ReadRegistersFromContext / WriteRegistersToContext / GetAvailableRegistersMask +// DDIs; float / SIMD register VALUES come from ReadFloatRegistersFromContext. // //***************************************************************************** #include "stdafx.h" @@ -18,21 +19,25 @@ CordbRegisterSet::CordbRegisterSet( + const BYTE * pContextBuffer, + ULONG32 contextSize, CordbThread * pThread, - DT_CONTEXT * pContext, bool fActive, - bool fQuickUnwind) + bool fQuickUnwind, + bool fTakeOwnershipOfContext /*= false*/) : CordbBase(pThread->GetProcess(), 0, enumCordbRegisterSet) { - _ASSERTE( pContext != NULL ); + _ASSERTE( pContextBuffer != NULL ); _ASSERTE( pThread != NULL ); - m_thread = pThread; - m_context = *pContext; - m_active = fActive; - m_quickUnwind = fQuickUnwind; - // Add to our parent thread's neuter list. + m_pContext = const_cast(pContextBuffer); + m_contextSize = contextSize; + m_fOwnsContext = fTakeOwnershipOfContext; + m_thread = pThread; + m_active = fActive; + m_quickUnwind = fQuickUnwind; + // Add to our parent thread's neuter list. HRESULT hr = S_OK; EX_TRY { @@ -45,6 +50,14 @@ CordbRegisterSet::CordbRegisterSet( void CordbRegisterSet::Neuter() { m_thread = NULL; + + if (m_fOwnsContext) + { + delete[] m_pContext; + } + m_pContext = NULL; + m_contextSize = 0; + CordbBase::Neuter(); } @@ -108,23 +121,17 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) EX_TRY { _ASSERTE( m_thread != NULL ); - if( contextSize < sizeof( DT_CONTEXT )) + if( contextSize < m_contextSize) { ThrowHR(E_INVALIDARG); } ValidateOrThrow(context); - DT_CONTEXT *pInputContext = reinterpret_cast (context); + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + ULONG32 targetContextSize = GetProcess()->GetTargetContextSize(); - // Just to be safe, zero out the buffer we got in while preserving the ContextFlags. - // On X64 the ContextFlags field is not the first 4 bytes of the DT_CONTEXT. - DWORD dwContextFlags = pInputContext->ContextFlags; - ZeroMemory(context, contextSize); - pInputContext->ContextFlags = dwContextFlags; - - // Augment the leafmost (active) register w/ information from the current context. - DT_CONTEXT * pLeafContext = NULL; + BYTE * pLeafContext = NULL; if (m_active) { EX_TRY @@ -140,95 +147,16 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) if (pLeafContext != NULL) { - // @todo - shouldn't this be a context-flags sensitive copy? - memmove( pInputContext, pLeafContext, sizeof( DT_CONTEXT) ); + // Raw byte copy of the leaf context, which carries the leaf's ContextFlags into the + // destination so the flag-sensitive overlay below is gated on those flags. + memcpy( context, pLeafContext, targetContextSize); } } - CORDbgCopyThreadContext(pInputContext, &m_context); + + // Overlay this frame's registers from the cached CONTEXT buffer, honoring the destination's + // ContextFlags (the leaf's if copied above, otherwise the caller's incoming flags). + pDAC->CopyContext(context, contextSize, m_pContext, m_contextSize, 0); } EX_CATCH_HRESULT(hr); return hr; } - -//----------------------------------------------------------------------------- -// Helpers to impl IRegSet2 on top of original IRegSet. -// These are useful on platforms that don't need IRegSet2 (like x86 + amd64). -// See CorDebug.idl for details. -// -// Inputs: -// regCount - size of pAvailable buffer in bytes -// pAvailable - buffer to hold bitvector of available registers. -// On success, bit at position CorDebugRegister is 1 iff that -// register is available. -// Returns S_OK on success. -//----------------------------------------------------------------------------- -HRESULT CordbRegisterSet::GetRegistersAvailableAdapter( - ULONG32 regCount, - BYTE pAvailable[]) -{ - // Defer to call on v1.0 interface - HRESULT hr = S_OK; - - if (regCount < sizeof(ULONG64)) - { - return E_INVALIDARG; - } - - _ASSERTE(pAvailable != NULL); - - ULONG64 availRegs; - hr = this->GetRegistersAvailable(&availRegs); - if (FAILED(hr)) - { - return hr; - } - - // Nor marshal our 64-bit value into the outgoing byte array. - for(int iBit = 0; iBit < (int) sizeof(availRegs) * 8; iBit++) - { - ULONG64 test = SETBITULONG64(iBit); - if (availRegs & test) - { - SET_BIT_MASK(pAvailable, iBit); - } - else - { - RESET_BIT_MASK(pAvailable, iBit); - } - } - return S_OK; -} - -//----------------------------------------------------------------------------- -// Helpers to impl IRegSet2 on top of original IRegSet. -// These are useful on platforms that don't need IRegSet2 (like x86 + amd64). -// See CorDebug.idl for details. -// -// Inputs: -// maskCount - size of mask buffer in bytes. -// mask - input buffer specifying registers to request -// regCount - size of regBuffer in bytes -// regBuffer - output buffer, regBuffer[n] = value of register at n-th active -// bit in mask. -// Returns S_OK on success. -//----------------------------------------------------------------------------- - -// mask input request registers, which get written to regCount buffer. -HRESULT CordbRegisterSet::GetRegistersAdapter( - ULONG32 maskCount, BYTE mask[], - ULONG32 regCount, CORDB_REGISTER regBuffer[]) -{ - // Convert input mask to orig mask. - ULONG64 maskOrig = 0; - - for(UINT iBit = 0; iBit < maskCount * 8; iBit++) - { - if (IS_SET_BIT_MASK(mask, iBit)) - { - maskOrig |= SETBITULONG64(iBit); - } - } - - return this->GetRegisters(maskOrig, - regCount, regBuffer); -} diff --git a/src/coreclr/debug/di/rsstackwalk.cpp b/src/coreclr/debug/di/rsstackwalk.cpp index 3842f08e2a06c2..e87f7f818fad53 100644 --- a/src/coreclr/debug/di/rsstackwalk.cpp +++ b/src/coreclr/debug/di/rsstackwalk.cpp @@ -38,8 +38,10 @@ void CordbStackWalk::Init() m_lastSyncFlushCounter = pProcess->m_flushCounter; IDacDbiInterface * pDAC = pProcess->GetDAC(); + m_pContextBuffer = new BYTE[pProcess->GetTargetContextSize()]; + IfFailThrow(pDAC->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - &m_context, + m_pContextBuffer, &m_pSFIHandle)); // see the function header of code:CordbStackWalk::CheckForLegacyHijackCase @@ -77,13 +79,14 @@ void CordbStackWalk::CheckForLegacyHijackCase() if (pUT->IsFirstChanceHijacked() || pUT->IsGenericHijacked()) { // The GetThreadContext function hides the effects of hijacking and returns the unhijacked context - m_context.ContextFlags = DT_CONTEXT_FULL; - pUT->GetThreadContext(&m_context); IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + T_CONTEXT * pContext = reinterpret_cast(m_pContextBuffer.GetValue()); + pContext->ContextFlags = CONTEXT_FULL; + pUT->GetThreadContext(pContext); IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, SET_CONTEXT_FLAG_ACTIVE_FRAME, - &m_context)); + m_pContextBuffer)); } } } @@ -204,14 +207,14 @@ void CordbStackWalk::RefreshIfNeeded() { // Make a local copy of the CONTEXT here. DeleteAll() will delete the CONTEXT on the cached frame, // and CreateStackWalk() actually uses the CONTEXT buffer we pass to it. - DT_CONTEXT ctx; + NewArrayHolder ctx(new BYTE[pProcess->GetTargetContextSize()]); if (m_fIsOneFrameAhead) { - ctx = *(m_pCachedFrame->GetContext()); + memcpy(ctx, m_pCachedFrame->GetContext(), pProcess->GetTargetContextSize()); } else { - ctx = m_context; + memcpy(ctx, m_pContextBuffer, pProcess->GetTargetContextSize()); } // clear all the state @@ -219,11 +222,11 @@ void CordbStackWalk::RefreshIfNeeded() // create a new stackwalk handle IfFailThrow(pProcess->GetDAC()->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - &m_context, + m_pContextBuffer, &m_pSFIHandle)); // advance the stackwalker to where we originally were - SetContextWorker(m_cachedSetContextFlag, sizeof(DT_CONTEXT), reinterpret_cast(&ctx)); + SetContextWorker(m_cachedSetContextFlag, pProcess->GetTargetContextSize(), ctx); // update the sync counter m_lastSyncFlushCounter = pProcess->m_flushCounter; @@ -260,7 +263,7 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, // set the required size for the CONTEXT buffer if (pContextSize != NULL) { - *pContextSize = ContextSizeForFlags(contextFlags); + *pContextSize = GetProcess()->GetTargetContextSize(); } // If all the user wants to know is the CONTEXT size, then we are done. @@ -271,25 +274,26 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } - DT_CONTEXT * pContext = reinterpret_cast(pbContextBuf); - - // Some helper functions that examine the context expect the flags to be initialized. - pContext->ContextFlags = contextFlags; - // check the size of the incoming buffer - if (!CheckContextSizeForBuffer(contextBufSize, pbContextBuf)) + if (contextBufSize < GetProcess()->GetTargetContextSize()) { ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } - // Check if we are one frame ahead. If so, returned the CONTEXT on the cached frame. + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + + // Check if we are one frame ahead. If so, return the CONTEXT on the cached frame. if (m_fIsOneFrameAhead) { if (m_pCachedFrame != NULL) { - const DT_CONTEXT * pSrcContext = m_pCachedFrame->GetContext(); + const BYTE * pSrcContext = reinterpret_cast(m_pCachedFrame->GetContext()); _ASSERTE(pSrcContext); - CORDbgCopyThreadContext(pContext, pSrcContext); + // Stamp the requested contextFlags on the destination so the copy + // pulls exactly those chunks from the source. + IfFailThrow(pDAC->CopyContext(pbContextBuf, contextBufSize, + pSrcContext, GetProcess()->GetTargetContextSize(), + contextFlags)); } else { @@ -303,8 +307,6 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, else { // No easy way out in this case. We have to call the DDI. - IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - IDacDbiInterface::FrameType ft; IfFailThrow(pDAC->GetStackWalkCurrentFrameInfo(m_pSFIHandle, NULL, &ft)); if (ft == IDacDbiInterface::kInvalid) @@ -322,7 +324,11 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, else { // We always store the current CONTEXT, so just copy it into the buffer. - CORDbgCopyThreadContext(pContext, &m_context); + // Stamp the requested contextFlags on the destination so the copy + // pulls exactly those chunks from the source. + IfFailThrow(pDAC->CopyContext(pbContextBuf, contextBufSize, + m_pContextBuffer, GetProcess()->GetTargetContextSize(), + contextFlags)); } } } @@ -371,7 +377,7 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte ThrowHR(E_INVALIDARG); } - if (!CheckContextSizeForBuffer(contextSize, context)) + if (contextSize < GetProcess()->GetTargetContextSize()) { ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } @@ -381,28 +387,22 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte m_cachedHR = S_OK; m_fIsOneFrameAhead = false; - DT_CONTEXT * pSrcContext = reinterpret_cast(context); - - // Check the incoming CONTEXT using a temporary CONTEXT buffer before updating our real CONTEXT buffer. - // The incoming CONTEXT is not required to have all the bits set in its CONTEXT flags, so only update - // the registers specified by the CONTEXT flags. Note that CORDbgCopyThreadContext() honours the CONTEXT - // flags on both the source and the destination CONTEXTs when it copies them. - DT_CONTEXT tmpCtx = m_context; - tmpCtx.ContextFlags |= pSrcContext->ContextFlags; - CORDbgCopyThreadContext(&tmpCtx, pSrcContext); - IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, &tmpCtx)); - // At this point we have done all of our checks to verify that the incoming CONTEXT is sane, so we can - // update our internal CONTEXT buffer. - m_context = tmpCtx; + ULONG32 cbCtx = GetProcess()->GetTargetContextSize(); + NewArrayHolder tmpCtx(new BYTE[cbCtx]); + memcpy(tmpCtx, m_pContextBuffer, cbCtx); + // flags == 0: tmpCtx already carries the desired ContextFlags (copied above). + IfFailThrow(pDAC->CopyContext(tmpCtx, cbCtx, context, contextSize, 0)); + IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, tmpCtx)); + + memcpy(m_pContextBuffer, tmpCtx, cbCtx); m_cachedSetContextFlag = flag; IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, flag, - &m_context)); + m_pContextBuffer)); } //--------------------------------------------------------------------------------------- @@ -428,7 +428,7 @@ BOOL CordbStackWalk::UnwindStackFrame() // Now that we have unwound, make sure we update the CONTEXT buffer to reflect the current stack frame. if (retVal) - IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, &m_context)); + IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, m_pContextBuffer)); return retVal; } // CordbStackWalk::UnwindStackWalkFrame @@ -574,20 +574,20 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) } } - IDacDbiInterface * pDAC = NULL; + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); Debugger_STRData frameData; ZeroMemory(&frameData, sizeof(frameData)); - // Allocate the DT_CONTEXT buffer on the dbi stack and - // hand the address to the DAC via Debugger_STRData. The DAC writes the - // populated context through this pointer. - DT_CONTEXT frameCtx; - ZeroMemory(&frameCtx, sizeof(frameCtx)); - frameData.ctx = &frameCtx; + // Allocate the CONTEXT buffer (sized to the target's CONTEXT) on the dbi heap + // and hand its address to the DAC via Debugger_STRData. The DAC writes the + // populated context through this pointer. The buffer is opaque target bytes; + // see the comment on Debugger_STRData in dbgipcevents.h for the protocol. + NewArrayHolder frameCtx(new BYTE[GetProcess()->GetTargetContextSize()]); + ZeroMemory(frameCtx, GetProcess()->GetTargetContextSize()); + frameData.ctx = frameCtx; IDacDbiInterface::FrameType ft = IDacDbiInterface::kInvalid; - pDAC = GetProcess()->GetDAC(); IfFailThrow(pDAC->GetStackWalkCurrentFrameInfo(m_pSFIHandle, &frameData, &ft)); if (ft == IDacDbiInterface::kInvalid) @@ -692,7 +692,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) (TADDR)frameData.v.taAmbientESP, pCurrentAppDomain, &miscFrame, - &frameCtx); + frameCtx); pResultFrame.Assign(static_cast(pNativeFrame)); m_pCachedFrame.Assign(static_cast(pNativeFrame)); @@ -831,7 +831,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) CordbRuntimeUnwindableFrame * pRuntimeFrame = new CordbRuntimeUnwindableFrame(m_pCordbThread, frameData.fp, pCurrentAppDomain, - &frameCtx); + frameCtx); pResultFrame.Assign(static_cast(pRuntimeFrame)); m_pCachedFrame.Assign(static_cast(pRuntimeFrame)); diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index d2d4cf5b25518c..138770b1e5c99c 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -79,6 +79,8 @@ CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) : m_fFramesFresh(false), m_fFloatStateValid(false), m_floatStackTop(0), + m_firstFloatReg(-1), + m_floatValuesCount(0), m_fException(false), m_EnCRemapFunctionIP(0), m_userState(kInvalidUserState), @@ -104,15 +106,6 @@ CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) : m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); m_vmExcepObjHandle = VMPTR_OBJECTHANDLE::NullPtr(); -#if defined(_DEBUG) - for (unsigned int i = 0; - i < (sizeof(m_floatValues) / sizeof(m_floatValues[0])); - i++) - { - m_floatValues[i] = 0; - } -#endif - // Set AppDomain m_pAppDomain = pProcess->GetAppDomain(); _ASSERTE(m_pAppDomain != NULL); @@ -154,11 +147,9 @@ void CordbThread::Neuter() m_hCachedThread = INVALID_HANDLE_VALUE; } - if( m_pContext != NULL ) - { - delete [] m_pContext; - m_pContext = NULL; - } + // Free the RS context cache buffer now (Neuter), so the destructor's + // m_pContext == NULL invariant holds. Clear() releases and resets to NULL. + m_pContext.Clear(); ClearStackFrameCache(); @@ -313,7 +304,8 @@ BOOL CordbThread::IsThreadExceptionManaged() // chain reason. // -void CordbThread::CreateCordbRegisterSet(DT_CONTEXT * pContext, +void CordbThread::CreateCordbRegisterSet(const BYTE * pContext, + ULONG32 contextSize, BOOL fLeaf, CorDebugChainReason reason, ICorDebugRegisterSet ** ppRegSet) @@ -328,11 +320,20 @@ void CordbThread::CreateCordbRegisterSet(DT_CONTEXT * pContext, IfFailThrow(EnsureThreadIsAlive()); + // Allocate and populate a CONTEXT buffer that the CordbRegisterSet will own. + // The caller passes the target's CONTEXT size (queried from the DAC). + NewArrayHolder pContextBuffer(new BYTE[contextSize]); + memcpy(pContextBuffer, pContext, contextSize); + // create the CordbRegisterSet - RSInitHolder pRS(new CordbRegisterSet(this, - pContext, + RSInitHolder pRS(new CordbRegisterSet(pContextBuffer, + contextSize, + this, (fLeaf == TRUE), - (reason == CHAIN_ENTER_MANAGED))); + (reason == CHAIN_ENTER_MANAGED), + true)); + pContextBuffer.SuppressRelease(); + pRS.TransferOwnershipExternal(ppRegSet); } @@ -1146,15 +1147,21 @@ HRESULT CordbThread::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters) IfFailThrow(hr); // retrieve the leaf CONTEXT - DT_CONTEXT ctx; - hr = pSW->GetContext(CONTEXT_FULL, sizeof(ctx), NULL, reinterpret_cast(&ctx)); - IfFailThrow(hr); + + // Allocate and populate a CONTEXT buffer that the CordbRegisterSet will own. + // The buffer is sized to the target's CONTEXT layout. + ULONG32 contextSize = GetProcess()->GetTargetContextSize(); + NewArrayHolder pContextBuffer(new BYTE[contextSize]); + IfFailThrow(pSW->GetContext(CONTEXT_FULL, contextSize, NULL, pContextBuffer)); // create the CordbRegisterSet - RSInitHolder pRS(new CordbRegisterSet(this, - &ctx, + RSInitHolder pRS(new CordbRegisterSet(pContextBuffer, + contextSize, + this, true, // active - false)); + false, // !fQuickUnwind + true)); // own context buffer + pContextBuffer.SuppressRelease(); pRS.TransferOwnershipExternal(ppRegisters); } @@ -1413,177 +1420,38 @@ HRESULT CordbThread::FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp) -#if defined(CROSS_COMPILE) && (defined(TARGET_ARM64) || defined(TARGET_ARM)) -extern "C" double FPFillR8(void* pFillSlot) -{ - _ASSERTE(!"nyi for platform"); - return 0; -} -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) -extern "C" double FPFillR8(void* pFillSlot); -#endif - - -#if defined(TARGET_X86) - -// CordbThread::Get32bitFPRegisters -// Converts the values in the floating point register area of the context to real number values. See -// code:CordbThread::LoadFloatState for more details. -// Arguments: -// input: pContext -// output: none (initializes m_floatValues) - -void CordbThread::Get32bitFPRegisters(CONTEXT * pContext) -{ - // On X86, we get the values by saving our current FPU state, loading - // the other thread's FPU state into our own, saving out each - // value off the FPU stack, and then restoring our FPU state. - // - FLOATING_SAVE_AREA floatarea = pContext->FloatSave; // copy FloatSave - - // - // Take the TOP out of the FPU status word. Note, our version of the - // stack runs from 0->7, not 7->0... - // - unsigned int floatStackTop = 7 - ((floatarea.StatusWord & 0x3800) >> 11); - - FLOATING_SAVE_AREA currentFPUState; - -#ifdef _MSC_VER - __asm fnsave currentFPUState // save the current FPU state. -#else - __asm__ __volatile__ - ( - " fnsave %0\n" \ - : "=m"(currentFPUState) - ); -#endif - - floatarea.StatusWord &= 0xFF00; // remove any error codes. - floatarea.ControlWord |= 0x3F; // mask all exceptions. - - // the x86 FPU stores real numbers as 10 byte values in IEEE format. Here we use - // the hardware to convert these to doubles. - - // @dbgtodo Microsoft crossplat: the conversion from a series of bytes to a floating - // point value will need to be done with an explicit conversion routine to unpack - // the IEEE format and compute the real number value represented. - -#ifdef _MSC_VER - __asm - { - fninit - frstor floatarea ;; reload the threads FPU state. - } -#else - __asm__ - ( - " fninit\n" \ - " frstor %0\n" \ - : /* no outputs */ - : "m"(floatarea) - ); -#endif - - unsigned int i; - - for (i = 0; i <= floatStackTop; i++) - { - double td = 0.0; -#ifdef _MSC_VER - __asm fstp td // copy out the double -#else - __asm("fstpl %0" : "=m" (td)); -#endif - m_floatValues[i] = td; - } - -#ifdef _MSC_VER - __asm - { - fninit - frstor currentFPUState ;; restore our saved FPU state. - } -#else - __asm__ - ( - " fninit\n" \ - " frstor %0\n" \ - : /* no outputs */ - : "m"(currentFPUState) - ); -#endif - - m_fFloatStateValid = true; - m_floatStackTop = floatStackTop; -} // CordbThread::Get32bitFPRegisters - -#elif defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) - -// CordbThread::Get64bitFPRegisters -// Converts the values in the floating point register area of the context to real number values. See -// code:CordbThread::LoadFloatState for more details. -// Arguments: -// input: pFPRegisterBase - starting address of the floating point register storage of the CONTEXT -// registerSize - the size of a floating point register -// start - the index into m_floatValues where we start initializing. For amd64, we start -// at the beginning, but for ia64, the first two registers have fixed values, -// so we start at two. -// nRegisters - the number of registers to be initialized -// output: none (initializes m_floatValues) - -void CordbThread::Get64bitFPRegisters(FPRegister64 * rgContextFPRegisters, int start, int nRegisters) -{ - // make sure no one has changed the type definition for 64-bit FP registers - _ASSERTE(sizeof(FPRegister64) == 16); - // We convert and copy all the fp registers. - for (int reg = start; reg < nRegisters; reg++) - { - // @dbgtodo Microsoft crossplat: the conversion from a FLOAT128 or M128A struct to a floating - // point value will need to be done with an explicit conversion routine instead - // of the call to FPFillR8 - m_floatValues[reg] = FPFillR8(&rgContextFPRegisters[reg - start]); - } -} // CordbThread::Get64bitFPRegisters - -#endif // TARGET_X86 - // CordbThread::LoadFloatState -// Initializes the float state members of this instance of CordbThread. This function gets the context and -// converts the floating point values from their context representation to a real number value. Floating -// point numbers are represented in IEEE format on all current platforms. We store them in the context as a -// pair of 64-bit integers (IA64 and AMD64) or a series of bytes (x86). Rather than unpack them explicitly -// and do the appropriate mathematical operations to produce the corresponding floating point value, we let -// the hardware do it instead. We load a floating point register with the representation from the context -// and then store it in m_floatValues. Using the hardware is obviously a huge perf win. If/when we make -// cross-plat work, we should at least code necessary conversion routines in assembly. Even with cross-plat, -// we can probably still use the hardware in most cases, as long as the size is appropriate. -// -// Arguments: none -// Return Value: none (initializes data members) +// +// Initializes the float state members of this instance of CordbThread by +// fetching the thread's CONTEXT and decoding its floating-point register area +// through IDacDbiInterface::ReadFloatRegistersFromContext. +// // Note: Throws - void CordbThread::LoadFloatState() { THROW_IF_NEUTERED(this); INTERNAL_SYNC_API_ENTRY(GetProcess()); - DT_CONTEXT tempContext; - IfFailThrow(GetProcess()->GetDAC()->GetContext(m_vmThreadToken, &tempContext)); - -#if defined(TARGET_X86) - Get32bitFPRegisters((CONTEXT*) &tempContext); -#elif defined(TARGET_AMD64) - // we have no fixed-value registers, so we begin with the first one and initialize all 16 - Get64bitFPRegisters((FPRegister64*) &(tempContext.Xmm0), 0, 16); -#elif defined(TARGET_ARM64) - Get64bitFPRegisters((FPRegister64*) &(tempContext.V), 0, 32); -#elif defined (TARGET_ARM) - Get64bitFPRegisters((FPRegister64*) &(tempContext.D), 0, 32); -#else - _ASSERTE(!"nyi for platform"); -#endif // !TARGET_X86 - + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + ULONG32 cbContext = GetProcess()->GetTargetContextSize(); + NewArrayHolder contextBuf(new BYTE[cbContext]); + IfFailThrow(pDAC->GetContext(m_vmThreadToken, contextBuf)); + + ULONG32 valuesCount = 0; + int firstFloatReg = -1; + ULONG32 floatStackTop = 0; + IfFailThrow(pDAC->ReadFloatRegistersFromContext( + contextBuf, + cbContext, + CORDB_MAX_FLOAT_REGISTERS, + m_floatValues, + &valuesCount, + &firstFloatReg, + &floatStackTop)); + + m_floatValuesCount = valuesCount; + m_firstFloatReg = firstFloatReg; + m_floatStackTop = floatStackTop; m_fFloatStateValid = true; } // CordbThread::LoadFloatState @@ -1672,7 +1540,7 @@ HRESULT CordbThread::SetIP(bool fCanSetIPOnly, // Get the context from a thread in managed code. // This thread should be stopped gracefully by the LS in managed code. -HRESULT CordbThread::GetManagedContext(DT_CONTEXT ** ppContext) +HRESULT CordbThread::GetManagedContext(BYTE ** ppContext) { FAIL_IF_NEUTERED(this); INTERNAL_SYNC_API_ENTRY(GetProcess()); @@ -1685,12 +1553,13 @@ HRESULT CordbThread::GetManagedContext(DT_CONTEXT ** ppContext) *ppContext = NULL; ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - // Each CordbThread object allocates the m_pContext's DT_CONTEXT structure only once, the first time GetContext is - // invoked. - if(m_pContext == NULL) + // Each CordbThread object allocates m_pContext only once, the first time + // GetContext is invoked. The buffer is sized to the target's CONTEXT + // (queried from the DAC); callers treat it as opaque target bytes. + if (m_pContext == NULL) { // Throw if the allocation fails. - m_pContext = reinterpret_cast(new BYTE[sizeof(DT_CONTEXT)]); + m_pContext = new BYTE[GetProcess()->GetTargetContextSize()]; } HRESULT hr = S_OK; @@ -1711,7 +1580,8 @@ HRESULT CordbThread::GetManagedContext(DT_CONTEXT ** ppContext) // The thread we're examining IS handling an exception, So grab the CONTEXT of the exception, NOT the // currently executing thread's CONTEXT (which would be the context of the exception handler.) - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), m_pContext); + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), + m_pContext.GetValue()); IfFailThrow(hr); } @@ -1725,12 +1595,12 @@ HRESULT CordbThread::GetManagedContext(DT_CONTEXT ** ppContext) return hr; } -HRESULT CordbThread::SetManagedContext(DT_CONTEXT * pContext) +HRESULT CordbThread::SetManagedContext(BYTE * pContext, ULONG32 cbCtx) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); - if(pContext == NULL) + if (pContext == NULL) { ThrowHR(E_INVALIDARG); } @@ -1753,13 +1623,16 @@ HRESULT CordbThread::SetManagedContext(DT_CONTEXT * pContext) // // Note: we read the remote context and merge the new one in, then write it back. This ensures that we don't // write too much information into the remote process. - DT_CONTEXT tempContext = { 0 }; - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), &tempContext); + NewArrayHolder tempContext(new BYTE[GetProcess()->GetTargetContextSize()]); + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), tempContext); IfFailThrow(hr); - CORDbgCopyThreadContext(&tempContext, pContext); + // flags == 0: tempContext already carries the target's ContextFlags (read above). + IfFailThrow(GetProcess()->GetDAC()->CopyContext( + tempContext.GetValue(), GetProcess()->GetTargetContextSize(), + pContext, cbCtx, 0)); - hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), &tempContext); + hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), tempContext.GetValue()); IfFailThrow(hr); // @todo - who's updating the regdisplay to guarantee that's in sync w/ our new context? @@ -1768,7 +1641,7 @@ HRESULT CordbThread::SetManagedContext(DT_CONTEXT * pContext) _ASSERTE(SUCCEEDED(hr)); if (m_fContextFresh && (m_pContext != NULL)) { - *m_pContext = *pContext; + memcpy(m_pContext, pContext, cbCtx); } return hr; @@ -2807,70 +2680,6 @@ HRESULT CordbUnmanagedThread::LoadTLSArrayPtr(void) return hr; } -/* -VOID CordbUnmanagedThread::VerifyFSChain() -{ -#if defined(TARGET_X86) - DT_CONTEXT temp; - temp.ContextFlags = DT_CONTEXT_FULL; - DbiGetThreadContext(m_handle, &temp); - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: 0x%x fs=0x%x TIB=0x%x\n", - m_id, temp.SegFs, m_threadLocalBase)); - REMOTE_PTR pExceptionRegRecordPtr; - HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(m_threadLocalBase), &pExceptionRegRecordPtr); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read fs:0 value: computed addr=0x%p err=%x\n", - m_id, m_threadLocalBase, hr)); - _ASSERTE(FALSE); - return; - } - while(pExceptionRegRecordPtr != EXCEPTION_CHAIN_END && pExceptionRegRecordPtr != NULL) - { - REMOTE_PTR prev; - REMOTE_PTR handler; - hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pExceptionRegRecordPtr), &prev); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read prev value: computed addr=0x%p err=%x\n", - m_id, pExceptionRegRecordPtr, hr)); - return; - } - hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS( (VOID*)((DWORD)pExceptionRegRecordPtr+4) ), &handler); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x failed to read handler value: computed addr=0x%p err=%x\n", - m_id, (DWORD)pExceptionRegRecordPtr+4, hr)); - return; - } - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: OK 0x%x record=0x%x prev=0x%x handler=0x%x\n", - m_id, pExceptionRegRecordPtr, prev, handler)); - if(handler == NULL) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x NULL handler found\n", m_id)); - _ASSERTE(FALSE); - return; - } - if(prev == NULL) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x NULL prev found\n", m_id)); - _ASSERTE(FALSE); - return; - } - if(prev == pExceptionRegRecordPtr) - { - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: ERROR 0x%x cyclic prev found\n", m_id)); - _ASSERTE(FALSE); - return; - } - pExceptionRegRecordPtr = prev; - } - - LOG((LF_CORDB, LL_INFO1000, "CUT::VFSC: OK 0x%x\n", m_id)); -#endif - return; -}*/ - #ifdef TARGET_X86 HRESULT CordbUnmanagedThread::SaveCurrentLeafSeh() { @@ -3416,7 +3225,7 @@ bool CordbUnmanagedThread::GetEEFrame() // Gets the thread context as if the thread were unhijacked, regardless // of whether it really is -HRESULT CordbUnmanagedThread::GetThreadContext(DT_CONTEXT* pContext) +HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) { // While hijacked there are 3 potential contexts we could be resuming back to // 1) A context provided in SetThreadContext that we defered applying @@ -3459,9 +3268,9 @@ HRESULT CordbUnmanagedThread::GetThreadContext(DT_CONTEXT* pContext) m_pLeftSideContext.UnsafeGet())); // Read the context into a temp context then copy to the out param. - DT_CONTEXT tempContext = { 0 }; + T_CONTEXT tempContext = { 0 }; - hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, &tempContext); + hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, reinterpret_cast(&tempContext)); if (SUCCEEDED(hr)) CORDbgCopyThreadContext(pContext, &tempContext); @@ -3489,7 +3298,7 @@ HRESULT CordbUnmanagedThread::GetThreadContext(DT_CONTEXT* pContext) // Sets the thread context as if the thread were unhijacked, regardless // of whether it really is. See GetThreadContext above for more details // on this abstraction -HRESULT CordbUnmanagedThread::SetThreadContext(DT_CONTEXT* pContext) +HRESULT CordbUnmanagedThread::SetThreadContext(T_CONTEXT* pContext) { HRESULT hr = S_OK; @@ -3554,8 +3363,8 @@ VOID CordbUnmanagedThread::BeginStepping() _ASSERTE(!IsSSFlagNeeded()); _ASSERTE(!IsSSFlagHidden()); - DT_CONTEXT tempContext; - tempContext.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT tempContext; + tempContext.ContextFlags = CONTEXT_FULL; BOOL succ = DbiGetThreadContext(m_handle, &tempContext); _ASSERTE(succ); @@ -3577,8 +3386,8 @@ VOID CordbUnmanagedThread::EndStepping() _ASSERTE(!IsGenericHijacked() && !IsFirstChanceHijacked()); _ASSERTE(IsSSFlagNeeded()); - DT_CONTEXT tempContext; - tempContext.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT tempContext; + tempContext.ContextFlags = CONTEXT_FULL; BOOL succ = DbiGetThreadContext(m_handle, &tempContext); _ASSERTE(succ); @@ -3595,7 +3404,7 @@ VOID CordbUnmanagedThread::EndStepping() // Writes some details of the given context into the debugger log -VOID CordbUnmanagedThread::LogContext(DT_CONTEXT* pContext) +VOID CordbUnmanagedThread::LogContext(T_CONTEXT* pContext) { #if defined(TARGET_X86) LOG((LF_CORDB, LL_INFO10000, @@ -3651,13 +3460,13 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: hijackCtx started as:\n")); LogContext(GetHijackCtx()); - // Save the thread's full context + DT_CONTEXT_EXTENDED_REGISTERS + // Save the thread's full context + CONTEXT_EXTENDED_REGISTERS // to avoid getting incomplete information and corrupt the thread context - DT_CONTEXT context; -#if defined(DT_CONTEXT_EXTENDED_REGISTERS) - context.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS; + T_CONTEXT context; +#if defined(CONTEXT_EXTENDED_REGISTERS) + context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else - context.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT; + context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; #endif BOOL succ = DbiGetThreadContext(m_handle, &context); _ASSERTE(succ); @@ -3667,10 +3476,10 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() DWORD error = GetLastError(); LOG((LF_CORDB, LL_ERROR, "CUT::SFCHFS: DbiGetThreadContext error=0x%x\n", error)); } -#if defined(DT_CONTEXT_EXTENDED_REGISTERS) - GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS; +#if defined(CONTEXT_EXTENDED_REGISTERS) + GetHijackCtx()->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else - GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT; + GetHijackCtx()->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; #endif CORDbgCopyThreadContext(GetHijackCtx(), &context); LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Hijacking for sync. Original context is:\n", this)); @@ -3802,7 +3611,7 @@ HRESULT CordbUnmanagedThread::SetupGenericHijack(DWORD eventCode, const EXCEPTIO _ASSERTE(!IsContextSet()); // Save the thread's full context. - GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL; + GetHijackCtx()->ContextFlags = CONTEXT_FULL; BOOL succ = DbiGetThreadContext(m_handle, GetHijackCtx()); @@ -3930,7 +3739,7 @@ HRESULT CordbUnmanagedThread::FixupFromGenericHijack() return S_OK; } -DT_CONTEXT * CordbUnmanagedThread::GetHijackCtx() +T_CONTEXT * CordbUnmanagedThread::GetHijackCtx() { return &m_context; } @@ -3940,8 +3749,8 @@ DT_CONTEXT * CordbUnmanagedThread::GetHijackCtx() // This can only be called after a bp. (because we assume that we executed a bp when we adjust the eip). HRESULT CordbUnmanagedThread::EnableSSAfterBP() { - DT_CONTEXT c; - c.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT c; + c.ContextFlags = CONTEXT_FULL; BOOL succ = DbiGetThreadContext(m_handle, &c); @@ -4076,7 +3885,7 @@ void CordbUnmanagedThread::FixupForSkipBreakpoint() m_pPatchSkipAddress = NULL; } -inline TADDR GetSP(DT_CONTEXT* context) +inline TADDR GetSP(T_CONTEXT* context) { #if defined(TARGET_X86) return (TADDR)context->Esp; @@ -4096,10 +3905,10 @@ BOOL CordbUnmanagedThread::GetStackRange(CORDB_ADDRESS *pBase, CORDB_ADDRESS *pL if (m_stackBase == 0 && m_stackLimit == 0) { HANDLE hProc; - DT_CONTEXT tempContext; + T_CONTEXT tempContext; MEMORY_BASIC_INFORMATION mbi; - tempContext.ContextFlags = DT_CONTEXT_FULL; + tempContext.ContextFlags = CONTEXT_FULL; if (SUCCEEDED(GetProcess()->GetHandle(&hProc)) && SUCCEEDED(GetThreadContext(&tempContext)) && ::VirtualQueryEx(hProc, (LPCVOID)GetSP(&tempContext), &mbi, sizeof(mbi)) != 0) @@ -4162,26 +3971,6 @@ BOOL CordbUnmanagedThread::GetStackRange(CORDB_ADDRESS *pBase, CORDB_ADDRESS *pL #endif // FEATURE_DBGIPC_TRANSPORT } -//----------------------------------------------------------------------------- -// Returns the thread context to the state it was in when it last entered RaiseException -// This allows the thread to retrigger an exception caused by RaiseException -//----------------------------------------------------------------------------- -void CordbUnmanagedThread::HijackToRaiseException() -{ - LOG((LF_CORDB, LL_INFO1000, "CP::HTRE: hijacking to RaiseException\n")); - _ASSERTE(HasRaiseExceptionEntryCtx()); - _ASSERTE(!IsRaiseExceptionHijacked()); - _ASSERTE(!IsGenericHijacked()); - _ASSERTE(!IsFirstChanceHijacked()); - _ASSERTE(!IsContextSet()); - - BOOL succ = DbiGetThreadContext(m_handle, GetHijackCtx()); - _ASSERTE(succ); - succ = DbiSetThreadContext(m_handle, &m_raiseExceptionEntryContext); - _ASSERTE(succ); - SetState(CUTS_IsRaiseExceptionHijacked); -} - //---------------------------------------------------------------------------- // Returns the context to its unhijacked state. //---------------------------------------------------------------------------- @@ -4190,8 +3979,8 @@ void CordbUnmanagedThread::RestoreFromRaiseExceptionHijack() LOG((LF_CORDB, LL_INFO1000, "CP::RFREH: ending RaiseException hijack\n")); _ASSERTE(IsRaiseExceptionHijacked()); - DT_CONTEXT restoreContext; - restoreContext.ContextFlags = DT_CONTEXT_FULL; + T_CONTEXT restoreContext; + restoreContext.ContextFlags = CONTEXT_FULL; HRESULT hr = GetThreadContext(&restoreContext); _ASSERTE(SUCCEEDED(hr)); @@ -4200,90 +3989,6 @@ void CordbUnmanagedThread::RestoreFromRaiseExceptionHijack() _ASSERTE(SUCCEEDED(hr)); } -//----------------------------------------------------------------------------- -// Attempts to store the state of a thread currently entering RaiseException -// This grabs both a full context and enough state to determine what exception -// RaiseException should be raising. If any of the state can not be retrieved -// then this entrance to RaiseException is silently ignored -//----------------------------------------------------------------------------- -void CordbUnmanagedThread::SaveRaiseExceptionEntryContext() -{ - _ASSERTE(FALSE); // should be unused now - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: saving raise exception context.\n")); - _ASSERTE(!HasRaiseExceptionEntryCtx()); - _ASSERTE(!IsRaiseExceptionHijacked()); - HRESULT hr = S_OK; - DT_CONTEXT context; - context.ContextFlags = DT_CONTEXT_FULL; - DbiGetThreadContext(m_handle, &context); - // if the flag is set, unset it - // we don't want to be single stepping through RaiseException the second time - // sending out OOB SS events. Ultimately we will rethrow the exception which would - // cleared the SS flag anyways. - UnsetSSFlag(&context); - memcpy(&m_raiseExceptionEntryContext, &context, sizeof(DT_CONTEXT)); - - // calculate the exception that we would expect to come from this invocation of RaiseException - REMOTE_PTR pExceptionInformation = NULL; -#if defined(TARGET_AMD64) - m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.Rcx; - m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.Rdx; - m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.R8; - pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.R9; -#elif defined(TARGET_ARM64) - m_raiseExceptionExceptionCode = (DWORD)m_raiseExceptionEntryContext.X0; - m_raiseExceptionExceptionFlags = (DWORD)m_raiseExceptionEntryContext.X1; - m_raiseExceptionNumberParameters = (DWORD)m_raiseExceptionEntryContext.X2; - pExceptionInformation = (REMOTE_PTR)m_raiseExceptionEntryContext.X3; -#elif defined(TARGET_X86) - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+4), &m_raiseExceptionExceptionCode); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception code.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+8), &m_raiseExceptionExceptionFlags); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception flags.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+12), &m_raiseExceptionNumberParameters); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read number of parameters.\n")); - return; - } - hr = m_pProcess->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)m_raiseExceptionEntryContext.Esp+16), &pExceptionInformation); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information pointer.\n")); - return; - } -#else - _ASSERTE(!"Implement this for your platform"); - return; -#endif - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: RaiseException parameters are 0x%x 0x%x 0x%x 0x%p.\n", - m_raiseExceptionExceptionCode, m_raiseExceptionExceptionFlags, - m_raiseExceptionNumberParameters, pExceptionInformation)); - TargetBuffer exceptionInfoTargetBuffer(pExceptionInformation, sizeof(REMOTE_PTR)*m_raiseExceptionNumberParameters); - EX_TRY - { - m_pProcess->SafeReadBuffer(exceptionInfoTargetBuffer, (BYTE*)m_raiseExceptionExceptionInformation); - } - EX_CATCH_HRESULT(hr); - if(FAILED(hr)) - { - LOG((LF_CORDB, LL_INFO1000, "CP::SREEC: failed to read exception information.\n")); - return; - } - - // If everything was successful then set this flag, otherwise none of the above data is considered valid - SetState(CUTS_HasRaiseExceptionEntryCtx); - return; -} - //----------------------------------------------------------------------------- // Clears all the state saved in SaveRaiseExceptionContext and returns the thread // to the state as if RaiseException has yet to be called. This is typically called @@ -4762,6 +4467,21 @@ bool CordbFrame::IsContainedInFrame(FramePointer fp) } } +// Reads an integer register from this frame's CONTEXT buffer via the DAC. +HRESULT CordbFrame::ReadContextRegister(CorDebugRegister reg, TADDR * pValue) const +{ + if (pValue == NULL) + return E_POINTER; + + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + return pDAC->ReadRegistersFromContext( + const_cast(GetContext()), + GetProcess()->GetTargetContextSize(), + ®, + 1, + pValue); +} + //--------------------------------------------------------------------------------------- // // Given an ICorDebugFrame interface pointer, return a pointer to the base class CordbFrame. @@ -5298,7 +5018,7 @@ BOOL CordbInternalFrame::IsCloserToLeafWorker(ICorDebugFrame * pFrameToCompare) // Compare the address of the "this" internal frame to the SP of the stack frame. // We can't compare frame pointers because the frame pointer means different things on // different platforms. - CORDB_ADDRESS stackFrameSP = CORDbgGetSP(pCNativeFrame->GetContext()); + CORDB_ADDRESS stackFrameSP = pCNativeFrame->GetStackPointer(); return (thisFrameAddr < stackFrameSP); } @@ -5310,8 +5030,9 @@ BOOL CordbInternalFrame::IsCloserToLeafWorker(ICorDebugFrame * pFrameToCompare) CordbRuntimeUnwindableFrame * pCRUFrame = static_cast(pRUFrame.GetValue()); - DT_CONTEXT * pResumeContext = const_cast(pCRUFrame->GetContext()); - CORDB_ADDRESS stackFrameSP = CORDbgGetSP(pResumeContext); + TADDR sp = 0; + IfFailThrow(pCRUFrame->ReadContextRegister(REGISTER_STACK_POINTER, &sp)); + CORDB_ADDRESS stackFrameSP = PTR_TO_CORDB_ADDRESS(sp); return (thisFrameAddr < stackFrameSP); } @@ -5370,10 +5091,12 @@ HRESULT CordbInternalFrame::IsCloserToLeaf(ICorDebugFrame * pFrameToCompare, CordbRuntimeUnwindableFrame::CordbRuntimeUnwindableFrame(CordbThread * pThread, FramePointer fp, CordbAppDomain * pCurrentAppDomain, - DT_CONTEXT * pContext) - : CordbFrame(pThread, fp, 0, pCurrentAppDomain), - m_context(*pContext) + BYTE * pContext) + : CordbFrame(pThread, fp, 0, pCurrentAppDomain) { + ULONG32 contextSize = pThread->GetProcess()->GetTargetContextSize(); + m_pContextBuffer = new BYTE[contextSize]; + memcpy(m_pContextBuffer, pContext, contextSize); } void CordbRuntimeUnwindableFrame::Neuter() @@ -5413,9 +5136,9 @@ HRESULT CordbRuntimeUnwindableFrame::QueryInterface(REFIID id, void ** ppInterfa // Return a pointer to the CONTEXT. // -const DT_CONTEXT * CordbRuntimeUnwindableFrame::GetContext() const +const BYTE * CordbRuntimeUnwindableFrame::GetContext() const { - return &m_context; + return m_pContextBuffer; } @@ -5447,7 +5170,7 @@ CordbNativeFrame::CordbNativeFrame(CordbThread * pThread, TADDR taAmbientESP, CordbAppDomain * pCurrentAppDomain, CordbMiscFrame * pMisc /*= NULL*/, - DT_CONTEXT * pContext /*= NULL*/) + BYTE * pContext /*= NULL*/) : CordbFrame(pThread, fp, ip, pCurrentAppDomain), m_JITILFrame(NULL), m_nativeCode(pNativeCode), // implicit InternalAddRef @@ -5457,7 +5180,9 @@ CordbNativeFrame::CordbNativeFrame(CordbThread * pThread, // Only new CordbNativeFrames created by the new stackwalk contain a CONTEXT. _ASSERTE(pContext != NULL); - m_context = *pContext; + ULONG32 contextSize = GetProcess()->GetTargetContextSize(); + m_pContextBuffer = new BYTE[contextSize]; + memcpy(m_pContextBuffer, pContext, contextSize); } /* @@ -5574,9 +5299,9 @@ HRESULT CordbNativeFrame::GetCode(ICorDebugCode **ppCode) // Return a pointer to the CONTEXT. // -const DT_CONTEXT * CordbNativeFrame::GetContext() const +const BYTE * CordbNativeFrame::GetContext() const { - return &m_context; + return m_pContextBuffer; } //--------------------------------------------------------------------------------------- @@ -5626,20 +5351,43 @@ ULONG32 CordbNativeFrame::GetIPOffset() return (ULONG32)m_ip; } -TADDR CordbNativeFrame::GetReturnRegisterValue() +// Reads an integer register from this frame's CONTEXT buffer via the DAC, using +// the JIT register number. Composes the JIT-RegNum -> CorDebugRegister +// translation with the generic register read. +HRESULT CordbNativeFrame::ReadJitRegFromContext(ULONG32 jitRegNum, TADDR * pValue) const { -#if defined(TARGET_X86) - return (TADDR)m_context.Eax; -#elif defined(TARGET_AMD64) - return (TADDR)m_context.Rax; -#elif defined(TARGET_ARM) - return (TADDR)m_context.R0; -#elif defined(TARGET_ARM64) - return (TADDR)m_context.X0; -#else - _ASSERTE(!"nyi for platform"); - return 0; -#endif + if (pValue == NULL) + return E_POINTER; + + CorDebugRegister reg; + HRESULT hr = GetProcess()->ConvertJitRegNumToCorDebugRegister(jitRegNum, ®); + if (FAILED(hr)) + return hr; + + return ReadContextRegister(reg, pValue); +} + +// Translates a JIT ICorDebugInfo::RegNum to its CorDebugRegister via the DAC, +// throwing on failure. See declaration in rspriv.h for full contract. +CorDebugRegister CordbNativeFrame::ConvertJitRegToCorDebugRegister(ULONG32 jitRegNum) const +{ + CorDebugRegister reg = (CorDebugRegister)0; + HRESULT hr = GetProcess()->ConvertJitRegNumToCorDebugRegister(jitRegNum, ®); + IfFailThrow(hr); + return reg; +} + +// Convenience wrapper around ReadContextRegister for the stack pointer. +CORDB_ADDRESS CordbNativeFrame::GetStackPointer() const +{ + TADDR sp = 0; + HRESULT hr = ReadContextRegister(REGISTER_STACK_POINTER, &sp); + if (FAILED(hr)) + { + _ASSERTE(!"ReadContextRegister(REGISTER_STACK_POINTER) failed"); + return (CORDB_ADDRESS)0; + } + return PTR_TO_CORDB_ADDRESS(sp); } // Determine if we can set IP at this point. The specified offset is the native offset. @@ -5702,8 +5450,6 @@ CORDB_ADDRESS CordbNativeFrame::GetLSStackAddress( ICorDebugInfo::RegNum regNum, signed offset) { - UINT_PTR *pRegAddr; - CORDB_ADDRESS pRemoteValue; if (regNum != DBG_TARGET_REGNUM_AMBIENT_SP) @@ -5714,15 +5460,13 @@ CORDB_ADDRESS CordbNativeFrame::GetLSStackAddress( // funclet prolog using the PSP. Thus, we just look up the frame pointer in the // current native frame. - pRegAddr = this->GetAddressOfRegister( - ConvertRegNumToCorDebugRegister(regNum)); - - // This should never be null as long as regNum is a member of the RegNum enum. - // If it is, an AV dereferencing a null-pointer in retail builds, or an assert in debug - // builds is exactly the behavior we want. - _ASSERTE(pRegAddr != NULL); + TADDR regVal = 0; + HRESULT hr = this->ReadJitRegFromContext(regNum, ®Val); + // This should never fail as long as regNum is a member of the RegNum enum. + _ASSERTE(SUCCEEDED(hr)); + IfFailThrow(hr); - pRemoteValue = PTR_TO_CORDB_ADDRESS(*pRegAddr + offset); + pRemoteValue = PTR_TO_CORDB_ADDRESS(regVal + offset); } else { @@ -5770,7 +5514,7 @@ HRESULT CordbNativeFrame::GetStackRange(CORDB_ADDRESS *pStart, if (pStart) { // From register set. - *pStart = CORDbgGetSP(&m_context); + *pStart = GetStackPointer(); } if (pEnd) @@ -5810,8 +5554,9 @@ HRESULT CordbNativeFrame::GetRegisterSet(ICorDebugRegisterSet **ppRegisters) EX_TRY { // allocate a new CordbRegisterSet object - RSInitHolder pRegisterSet(new CordbRegisterSet(m_pThread, - &m_context, + RSInitHolder pRegisterSet(new CordbRegisterSet(m_pContextBuffer, + GetProcess()->GetTargetContextSize(), + m_pThread, IsLeafFrame(), false)); @@ -5937,7 +5682,9 @@ HRESULT CordbNativeFrame::GetStackParameterSize(ULONG32 * pSize) #if defined(TARGET_X86) IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - IfFailThrow(pDAC->GetStackParameterSize(PTR_TO_CORDB_ADDRESS(CORDbgGetIP(&m_context)), pSize)); + TADDR ip = 0; + IfFailThrow(ReadContextRegister(REGISTER_INSTRUCTION_POINTER, &ip)); + IfFailThrow(pDAC->GetStackParameterSize(PTR_TO_CORDB_ADDRESS(ip), pSize)); #else // !TARGET_X86 hr = S_FALSE; *pSize = 0; @@ -5948,462 +5695,6 @@ HRESULT CordbNativeFrame::GetStackParameterSize(ULONG32 * pSize) return hr; } -// -// GetAddressOfRegister returns the address of the given register in the -// frame's current register display (eg, a local address). This is usually used to build a -// ICorDebugValue from. -// -UINT_PTR * CordbNativeFrame::GetAddressOfRegister(CorDebugRegister regNum) const -{ - UINT_PTR* ret = NULL; - - switch (regNum) - { -#if !defined(TARGET_WASM) - case REGISTER_STACK_POINTER: - ret = (UINT_PTR*)GetSPAddress(&m_context); - break; -#endif - -#if !defined(TARGET_AMD64) && !defined(TARGET_ARM) && !defined(TARGET_WASM) // @ARMTODO - case REGISTER_FRAME_POINTER: - ret = (UINT_PTR*)GetFPAddress(&m_context); - break; -#endif - -#if defined(TARGET_X86) - case REGISTER_X86_EAX: - ret = (UINT_PTR*)&m_context.Eax; - break; - - case REGISTER_X86_ECX: - ret = (UINT_PTR*)&m_context.Ecx; - break; - - case REGISTER_X86_EDX: - ret = (UINT_PTR*)&m_context.Edx; - break; - - case REGISTER_X86_EBX: - ret = (UINT_PTR*)&m_context.Ebx; - break; - - case REGISTER_X86_ESI: - ret = (UINT_PTR*)&m_context.Esi; - break; - - case REGISTER_X86_EDI: - ret = (UINT_PTR*)&m_context.Edi; - break; - -#elif defined(TARGET_AMD64) - case REGISTER_AMD64_RBP: - ret = (UINT_PTR*)&m_context.Rbp; - break; - - case REGISTER_AMD64_RAX: - ret = (UINT_PTR*)&m_context.Rax; - break; - - case REGISTER_AMD64_RCX: - ret = (UINT_PTR*)&m_context.Rcx; - break; - - case REGISTER_AMD64_RDX: - ret = (UINT_PTR*)&m_context.Rdx; - break; - - case REGISTER_AMD64_RBX: - ret = (UINT_PTR*)&m_context.Rbx; - break; - - case REGISTER_AMD64_RSI: - ret = (UINT_PTR*)&m_context.Rsi; - break; - - case REGISTER_AMD64_RDI: - ret = (UINT_PTR*)&m_context.Rdi; - break; - - case REGISTER_AMD64_R8: - ret = (UINT_PTR*)&m_context.R8; - break; - - case REGISTER_AMD64_R9: - ret = (UINT_PTR*)&m_context.R9; - break; - - case REGISTER_AMD64_R10: - ret = (UINT_PTR*)&m_context.R10; - break; - - case REGISTER_AMD64_R11: - ret = (UINT_PTR*)&m_context.R11; - break; - - case REGISTER_AMD64_R12: - ret = (UINT_PTR*)&m_context.R12; - break; - - case REGISTER_AMD64_R13: - ret = (UINT_PTR*)&m_context.R13; - break; - - case REGISTER_AMD64_R14: - ret = (UINT_PTR*)&m_context.R14; - break; - - case REGISTER_AMD64_R15: - ret = (UINT_PTR*)&m_context.R15; - break; -#elif defined(TARGET_ARM) - case REGISTER_ARM_R0: - ret = (UINT_PTR*)&m_context.R0; - break; - - case REGISTER_ARM_R1: - ret = (UINT_PTR*)&m_context.R1; - break; - - case REGISTER_ARM_R2: - ret = (UINT_PTR*)&m_context.R2; - break; - - case REGISTER_ARM_R3: - ret = (UINT_PTR*)&m_context.R3; - break; - - case REGISTER_ARM_R4: - ret = (UINT_PTR*)&m_context.R4; - break; - - case REGISTER_ARM_R5: - ret = (UINT_PTR*)&m_context.R5; - break; - - case REGISTER_ARM_R6: - ret = (UINT_PTR*)&m_context.R6; - break; - - case REGISTER_ARM_R7: - ret = (UINT_PTR*)&m_context.R7; - break; - - case REGISTER_ARM_R8: - ret = (UINT_PTR*)&m_context.R8; - break; - - case REGISTER_ARM_R9: - ret = (UINT_PTR*)&m_context.R9; - break; - - case REGISTER_ARM_R10: - ret = (UINT_PTR*)&m_context.R10; - break; - - case REGISTER_ARM_R11: - ret = (UINT_PTR*)&m_context.R11; - break; - - case REGISTER_ARM_R12: - ret = (UINT_PTR*)&m_context.R12; - break; - - case REGISTER_ARM_LR: - ret = (UINT_PTR*)&m_context.Lr; - break; - - case REGISTER_ARM_PC: - ret = (UINT_PTR*)&m_context.Pc; - break; -#elif defined(TARGET_ARM64) - case REGISTER_ARM64_X0: - case REGISTER_ARM64_X1: - case REGISTER_ARM64_X2: - case REGISTER_ARM64_X3: - case REGISTER_ARM64_X4: - case REGISTER_ARM64_X5: - case REGISTER_ARM64_X6: - case REGISTER_ARM64_X7: - case REGISTER_ARM64_X8: - case REGISTER_ARM64_X9: - case REGISTER_ARM64_X10: - case REGISTER_ARM64_X11: - case REGISTER_ARM64_X12: - case REGISTER_ARM64_X13: - case REGISTER_ARM64_X14: - case REGISTER_ARM64_X15: - case REGISTER_ARM64_X16: - case REGISTER_ARM64_X17: - case REGISTER_ARM64_X18: - case REGISTER_ARM64_X19: - case REGISTER_ARM64_X20: - case REGISTER_ARM64_X21: - case REGISTER_ARM64_X22: - case REGISTER_ARM64_X23: - case REGISTER_ARM64_X24: - case REGISTER_ARM64_X25: - case REGISTER_ARM64_X26: - case REGISTER_ARM64_X27: - case REGISTER_ARM64_X28: - ret = (UINT_PTR*)&m_context.X[regNum - REGISTER_ARM64_X0]; - break; - - case REGISTER_ARM64_LR: - ret = (UINT_PTR*)&m_context.Lr; - break; - - case REGISTER_ARM64_PC: - ret = (UINT_PTR*)&m_context.Pc; - break; -#elif defined(TARGET_RISCV64) - case REGISTER_RISCV64_PC: - ret = (UINT_PTR*)&m_context.Pc; - break; - - case REGISTER_RISCV64_RA: - ret = (UINT_PTR*)&m_context.Ra; - break; - - case REGISTER_RISCV64_GP: - ret = (UINT_PTR*)&m_context.Gp; - break; - - case REGISTER_RISCV64_TP: - ret = (UINT_PTR*)&m_context.Tp; - break; - - case REGISTER_RISCV64_T0: - ret = (UINT_PTR*)&m_context.T0; - break; - - case REGISTER_RISCV64_T1: - ret = (UINT_PTR*)&m_context.T1; - break; - - case REGISTER_RISCV64_T2: - ret = (UINT_PTR*)&m_context.T2; - break; - - case REGISTER_RISCV64_S1: - ret = (UINT_PTR*)&m_context.S1; - break; - - case REGISTER_RISCV64_A0: - ret = (UINT_PTR*)&m_context.A0; - break; - - case REGISTER_RISCV64_A1: - ret = (UINT_PTR*)&m_context.A1; - break; - - case REGISTER_RISCV64_A2: - ret = (UINT_PTR*)&m_context.A2; - break; - - case REGISTER_RISCV64_A3: - ret = (UINT_PTR*)&m_context.A3; - break; - - case REGISTER_RISCV64_A4: - ret = (UINT_PTR*)&m_context.A4; - break; - - case REGISTER_RISCV64_A5: - ret = (UINT_PTR*)&m_context.A5; - break; - - case REGISTER_RISCV64_A6: - ret = (UINT_PTR*)&m_context.A6; - break; - - case REGISTER_RISCV64_A7: - ret = (UINT_PTR*)&m_context.A7; - break; - - case REGISTER_RISCV64_S2: - ret = (UINT_PTR*)&m_context.S2; - break; - - case REGISTER_RISCV64_S3: - ret = (UINT_PTR*)&m_context.S3; - break; - - case REGISTER_RISCV64_S4: - ret = (UINT_PTR*)&m_context.S4; - break; - - case REGISTER_RISCV64_S5: - ret = (UINT_PTR*)&m_context.S5; - break; - - case REGISTER_RISCV64_S6: - ret = (UINT_PTR*)&m_context.S6; - break; - - case REGISTER_RISCV64_S7: - ret = (UINT_PTR*)&m_context.S7; - break; - - case REGISTER_RISCV64_S8: - ret = (UINT_PTR*)&m_context.S8; - break; - - case REGISTER_RISCV64_S9: - ret = (UINT_PTR*)&m_context.S9; - break; - - case REGISTER_RISCV64_S10: - ret = (UINT_PTR*)&m_context.S10; - break; - - case REGISTER_RISCV64_S11: - ret = (UINT_PTR*)&m_context.S11; - break; - - case REGISTER_RISCV64_T3: - ret = (UINT_PTR*)&m_context.T3; - break; - - case REGISTER_RISCV64_T4: - ret = (UINT_PTR*)&m_context.T4; - break; - - case REGISTER_RISCV64_T5: - ret = (UINT_PTR*)&m_context.T5; - break; - - case REGISTER_RISCV64_T6: - ret = (UINT_PTR*)&m_context.T6; - break; -#elif defined(TARGET_LOONGARCH64) - case REGISTER_LOONGARCH64_PC: - ret = (UINT_PTR*)&m_context.Pc; - break; - - case REGISTER_LOONGARCH64_RA: - ret = (UINT_PTR*)&m_context.Ra; - break; - - case REGISTER_LOONGARCH64_TP: - ret = (UINT_PTR*)&m_context.Tp; - break; - - case REGISTER_LOONGARCH64_A0: - ret = (UINT_PTR*)&m_context.A0; - break; - - case REGISTER_LOONGARCH64_A1: - ret = (UINT_PTR*)&m_context.A1; - break; - - case REGISTER_LOONGARCH64_A2: - ret = (UINT_PTR*)&m_context.A2; - break; - - case REGISTER_LOONGARCH64_A3: - ret = (UINT_PTR*)&m_context.A3; - break; - - case REGISTER_LOONGARCH64_A4: - ret = (UINT_PTR*)&m_context.A4; - break; - - case REGISTER_LOONGARCH64_A5: - ret = (UINT_PTR*)&m_context.A5; - break; - - case REGISTER_LOONGARCH64_A6: - ret = (UINT_PTR*)&m_context.A6; - break; - - case REGISTER_LOONGARCH64_A7: - ret = (UINT_PTR*)&m_context.A7; - break; - - case REGISTER_LOONGARCH64_T0: - ret = (UINT_PTR*)&m_context.T0; - break; - - case REGISTER_LOONGARCH64_T1: - ret = (UINT_PTR*)&m_context.T1; - break; - - case REGISTER_LOONGARCH64_T2: - ret = (UINT_PTR*)&m_context.T2; - break; - - case REGISTER_LOONGARCH64_T3: - ret = (UINT_PTR*)&m_context.T3; - break; - - case REGISTER_LOONGARCH64_T4: - ret = (UINT_PTR*)&m_context.T4; - break; - - case REGISTER_LOONGARCH64_T5: - ret = (UINT_PTR*)&m_context.T5; - break; - - case REGISTER_LOONGARCH64_T6: - ret = (UINT_PTR*)&m_context.T6; - break; - - case REGISTER_LOONGARCH64_T7: - ret = (UINT_PTR*)&m_context.T7; - break; - - case REGISTER_LOONGARCH64_T8: - ret = (UINT_PTR*)&m_context.T8; - break; - - case REGISTER_LOONGARCH64_X0: - ret = (UINT_PTR*)&m_context.X0; - break; - - case REGISTER_LOONGARCH64_S0: - ret = (UINT_PTR*)&m_context.S0; - break; - - case REGISTER_LOONGARCH64_S1: - ret = (UINT_PTR*)&m_context.S1; - break; - - case REGISTER_LOONGARCH64_S2: - ret = (UINT_PTR*)&m_context.S2; - break; - - case REGISTER_LOONGARCH64_S3: - ret = (UINT_PTR*)&m_context.S3; - break; - - case REGISTER_LOONGARCH64_S4: - ret = (UINT_PTR*)&m_context.S4; - break; - - case REGISTER_LOONGARCH64_S5: - ret = (UINT_PTR*)&m_context.S5; - break; - - case REGISTER_LOONGARCH64_S6: - ret = (UINT_PTR*)&m_context.S6; - break; - - case REGISTER_LOONGARCH64_S7: - ret = (UINT_PTR*)&m_context.S7; - break; - - case REGISTER_LOONGARCH64_S8: - ret = (UINT_PTR*)&m_context.S8; - break; -#endif - - default: - _ASSERT(!"Invalid register number!"); - } - - return ret; -} // // GetLeftSideAddressOfRegister returns the Left Side address of the given register in the frames current register @@ -6448,8 +5739,9 @@ SIZE_T CordbNativeFrame::GetRegisterOrStackValue(const ICorDebugInfo::NativeVarI if (pNativeVarInfo->loc.vlType == ICorDebugInfo::VLT_REG) { - CorDebugRegister reg = ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg); - uResult = *(reinterpret_cast(GetAddressOfRegister(reg))); + TADDR regVal = 0; + IfFailThrow(ReadJitRegFromContext(pNativeVarInfo->loc.vlReg.vlrReg, ®Val)); + uResult = (SIZE_T)regVal; } else if (pNativeVarInfo->loc.vlType == ICorDebugInfo::VLT_STK) { @@ -6719,10 +6011,10 @@ HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg, } #endif - // The address of the given register is the address of the value - // in this process. We have no remote address here. - void *pLocalValue = (void*)GetAddressOfRegister(reg); - HRESULT hr = S_OK; + TADDR regVal = 0; + HRESULT hr = ReadContextRegister(reg, ®Val); + if (FAILED(hr)) + return hr; EX_TRY { @@ -6736,7 +6028,7 @@ HRESULT CordbNativeFrame::GetLocalRegisterValue(CorDebugRegister reg, pType, false, EMPTY_BUFFER, - MemoryRange(pLocalValue, REG_SIZE), + MemoryRange(®Val, REG_SIZE), pRegHolder, &pValue); // throws @@ -7091,7 +6383,13 @@ bool CordbNativeFrame::IsLeafFrame() const if (pNFrame != NULL) { // check if the leaf frame in the leaf chain is "this" - if (CompareControlRegisters(GetContext(), pNFrame->GetContext())) + BOOL fSameControlRegisters = FALSE; + ULONG32 cbContext = GetProcess()->GetTargetContextSize(); + IfFailThrow(GetProcess()->GetDAC()->CompareControlRegisters( + GetContext(), cbContext, + pNFrame->GetContext(), cbContext, + &fSameControlRegisters)); + if (fSameControlRegisters) { m_optfIsLeafFrame = TRUE; } @@ -7108,7 +6406,7 @@ bool CordbNativeFrame::IsLeafFrame() const { IDacDbiInterface * pDAC = GetProcess()->GetDAC(); BOOL isLeaf; - IfFailThrow(pDAC->IsLeafFrame(m_pThread->m_vmThreadToken, &m_context, &isLeaf)); + IfFailThrow(pDAC->IsLeafFrame(m_pThread->m_vmThreadToken, m_pContextBuffer, &isLeaf)); m_optfIsLeafFrame = (isLeaf == TRUE); } } @@ -8235,14 +7533,17 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, { case ICorDebugInfo::VLT_REG: hr = m_nativeFrame->GetLocalRegisterValue( - ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg), + m_nativeFrame->ConvertJitRegToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg), type, ppValue); break; case ICorDebugInfo::VLT_REG_BYREF: { - CORDB_ADDRESS pRemoteByRefAddr = PTR_TO_CORDB_ADDRESS( - *( m_nativeFrame->GetAddressOfRegister(ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlReg.vlrReg))) ); + TADDR regVal = 0; + IfFailThrow(m_nativeFrame->ReadJitRegFromContext( + pNativeVarInfo->loc.vlReg.vlrReg, + ®Val)); + CORDB_ADDRESS pRemoteByRefAddr = PTR_TO_CORDB_ADDRESS(regVal); hr = m_nativeFrame->GetLocalMemoryValue(pRemoteByRefAddr, type, @@ -8296,8 +7597,8 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, case ICorDebugInfo::VLT_REG_REG: hr = m_nativeFrame->GetLocalDoubleRegisterValue( - ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg2), - ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg1), + m_nativeFrame->ConvertJitRegToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg2), + m_nativeFrame->ConvertJitRegToCorDebugRegister(pNativeVarInfo->loc.vlRegReg.vlrrReg1), type, ppValue); break; @@ -8308,7 +7609,7 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, hr = m_nativeFrame->GetLocalMemoryRegisterValue( pRemoteValue, - ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlRegStk.vlrsReg), + m_nativeFrame->ConvertJitRegToCorDebugRegister(pNativeVarInfo->loc.vlRegStk.vlrsReg), type, ppValue); } break; @@ -8319,7 +7620,7 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, pNativeVarInfo->loc.vlStkReg.vlsrStk.vlsrsBaseReg, pNativeVarInfo->loc.vlStkReg.vlsrStk.vlsrsOffset); hr = m_nativeFrame->GetLocalRegisterMemoryValue( - ConvertRegNumToCorDebugRegister(pNativeVarInfo->loc.vlStkReg.vlsrReg), + m_nativeFrame->ConvertJitRegToCorDebugRegister(pNativeVarInfo->loc.vlStkReg.vlsrReg), pRemoteValue, type, ppValue); } break; @@ -11400,4 +10701,4 @@ void CordbAsyncFrame::LoadGenericArgs() m_genericArgsLoaded = true; ppGenericArgs.SuppressRelease(); -} +} \ No newline at end of file diff --git a/src/coreclr/debug/di/shimlocaldatatarget.cpp b/src/coreclr/debug/di/shimlocaldatatarget.cpp index 8bad40ee735e29..136ff3d8a20dfb 100644 --- a/src/coreclr/debug/di/shimlocaldatatarget.cpp +++ b/src/coreclr/debug/di/shimlocaldatatarget.cpp @@ -392,7 +392,7 @@ ShimLocalDataTarget::GetThreadContext( if (hThread != NULL) { - DT_CONTEXT * pCtx = reinterpret_cast(pContext); + T_CONTEXT * pCtx = reinterpret_cast(pContext); pCtx->ContextFlags = contextFlags; if (DbiGetThreadContext(hThread, pCtx)) @@ -428,7 +428,7 @@ ShimLocalDataTarget::SetThreadContext( if (hThread != NULL) { - if (DbiSetThreadContext(hThread, reinterpret_cast(pContext))) + if (DbiSetThreadContext(hThread, reinterpret_cast(pContext))) { hr = S_OK; } diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index acbf2b5da4b522..dfe88b71972087 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -638,6 +638,10 @@ class ShimStackWalk ShimChain * GetChain(UINT32 index); ICorDebugFrame * GetFrame(UINT32 index); + // The target's CONTEXT size in bytes (forwards to CordbProcess::GetTargetContextSize, + // which memoizes it). ShimStackWalk owns no context buffer, so it caches nothing itself. + ULONG32 GetContextSize(); + // Get the number of frames and chains. ULONG GetChainCount(); ULONG GetFrameCount(); @@ -684,13 +688,25 @@ class ShimStackWalk struct ChainInfo { public: - ChainInfo() : m_rootFP(LEAF_MOST_FRAME), m_reason(CHAIN_NONE), m_fNeedEnterManagedChain(FALSE), m_fLeafNativeContextIsValid(FALSE) {} + ChainInfo(ULONG32 contextSize) + : m_leafNativeContext(new BYTE[contextSize]), + m_leafManagedContext(new BYTE[contextSize]), + m_contextSize(contextSize), + m_rootFP(LEAF_MOST_FRAME), + m_reason(CHAIN_NONE), + m_fNeedEnterManagedChain(FALSE), + m_fLeafNativeContextIsValid(FALSE) {} void CancelUMChain() { m_reason = CHAIN_NONE; } BOOL IsTrackingUMChain() { return (m_reason == CHAIN_ENTER_UNMANAGED); } - DT_CONTEXT m_leafNativeContext; - DT_CONTEXT m_leafManagedContext; + BYTE * GetLeafNativeContext() { return m_leafNativeContext; } + BYTE * GetLeafManagedContext() { return m_leafManagedContext; } + + // Leaf CONTEXT buffers, sized at construction to the target's CONTEXT size. + NewArrayHolder m_leafNativeContext; + NewArrayHolder m_leafManagedContext; + ULONG32 m_contextSize; FramePointer m_rootFP; CorDebugChainReason m_reason; bool m_fNeedEnterManagedChain; @@ -776,7 +792,7 @@ class ShimStackWalk void Clear(); // Get a FramePointer to mark the root boundary of a chain. - FramePointer GetFramePointerForChain(DT_CONTEXT * pContext); + FramePointer GetFramePointerForChain(const BYTE * pContext); FramePointer GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2); CorDebugInternalFrameType GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2); @@ -787,14 +803,14 @@ class ShimStackWalk // Append a chain to the array. void AppendChainWorker(StackWalkInfo * pStackWalkInfo, - DT_CONTEXT * pLeafContext, + const BYTE * pLeafContext, FramePointer fpRoot, CorDebugChainReason chainReason, BOOL fIsManagedChain); void AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo); // Save information on the ChainInfo regarding the current chain. - void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext); + void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, BYTE * pContext); // Check what we are process next, a internal frame or a stack frame. BOOL CheckInternalFrame(ICorDebugFrame * pNextStackFrame, @@ -842,7 +858,7 @@ class ShimChain : public ICorDebugChain { public: ShimChain(ShimStackWalk * pSW, - DT_CONTEXT * pContext, + const BYTE * pContext, FramePointer fpRoot, UINT32 chainIndex, UINT32 frameStartIndex, @@ -898,7 +914,10 @@ class ShimChain : public ICorDebugChain // end of the chain, and a frame pointer where the chain ends (rootmost). This stack range is exposed // publicly via ICDChain::GetStackRange(), and can be used to stitch managed and native stack frames // together into a unified stack. - DT_CONTEXT m_context; // the leaf end of the chain + // The CONTEXT is held as an opaque byte buffer sized to the target's CONTEXT (GetTargetContextSize), + // so ShimChain keeps no per-arch knowledge of the CONTEXT layout. + NewArrayHolder m_pContext; // the leaf end of the chain + ULONG32 m_contextSize; FramePointer m_fpRoot; // the root end of the chain ShimStackWalk * m_pStackWalk; // the owning ShimStackWalk diff --git a/src/coreclr/debug/di/shimstackwalk.cpp b/src/coreclr/debug/di/shimstackwalk.cpp index c580bb0c7842ce..40081b5cd42e57 100644 --- a/src/coreclr/debug/di/shimstackwalk.cpp +++ b/src/coreclr/debug/di/shimstackwalk.cpp @@ -22,6 +22,25 @@ static const ULONG32 REGISTER_AMD64_MAX = REGISTER_AMD64_XMM15 + 1; static const ULONG32 MAX_MASK_COUNT = (REGISTER_AMD64_MAX + 7) >> 3; #endif +namespace +{ + TADDR ReadCtxReg(CordbThread * pThread, + const BYTE * pCtx, + ULONG32 ctxSize, + CorDebugRegister reg) + { + TADDR value = 0; + IDacDbiInterface * pDAC = pThread->GetProcess()->GetDAC(); + IfFailThrow(pDAC->ReadRegistersFromContext( + const_cast(pCtx), + ctxSize, + ®, + 1, + &value)); + return value; + } +} + ShimStackWalk::ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread) : m_pChainEnumList(NULL), m_pFrameEnumList(NULL) @@ -33,6 +52,11 @@ ShimStackWalk::ShimStackWalk(ShimProcess * pProcess, ICorDebugThread * pThread) Populate(); } +ULONG32 ShimStackWalk::GetContextSize() +{ + return static_cast(m_pThread.GetValue())->GetProcess()->GetTargetContextSize(); +} + ShimStackWalk::~ShimStackWalk() { Clear(); @@ -184,7 +208,7 @@ void ShimStackWalk::Populate() IfFailThrow(hr); // structs used to store information during the stackwalk - ChainInfo chainInfo; + ChainInfo chainInfo(GetContextSize()); StackWalkInfo swInfo; // use the ICDStackWalk to retrieve the internal frames @@ -356,7 +380,7 @@ void ShimStackWalk::Populate() { // If we have hit any managed stack frame, then we may need to send // an enter-managed chain later. Save the CONTEXT now. - SaveChainContext(pSW, &chainInfo, &(chainInfo.m_leafManagedContext)); + SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafManagedContext()); chainInfo.m_fNeedEnterManagedChain = true; } @@ -411,7 +435,7 @@ void ShimStackWalk::Populate() // we have exhausted all the stack frames. // We need to save the CONTEXT to start tracking an unmanaged chain. - SaveChainContext(pSW, &chainInfo, &(chainInfo.m_leafNativeContext)); + SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafNativeContext()); chainInfo.m_fLeafNativeContextIsValid = true; // begin tracking UM chain if we're supposed to @@ -954,9 +978,11 @@ void ShimStackWalk::GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** } } -FramePointer ShimStackWalk::GetFramePointerForChain(DT_CONTEXT * pContext) +FramePointer ShimStackWalk::GetFramePointerForChain(const BYTE * pContext) { - return FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(CORDbgGetSP(pContext))); + CordbThread * pThread = static_cast(m_pThread.GetValue()); + TADDR sp = ReadCtxReg(pThread, pContext, GetContextSize(), REGISTER_STACK_POINTER); + return FramePointer::MakeFramePointer(reinterpret_cast(sp)); } FramePointer ShimStackWalk::GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2) @@ -1050,7 +1076,7 @@ void ShimStackWalk::AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, Stack // void ShimStackWalk::AppendChainWorker(StackWalkInfo * pStackWalkInfo, - DT_CONTEXT * pLeafContext, + const BYTE * pLeafContext, FramePointer fpRoot, CorDebugChainReason chainReason, BOOL fIsManagedChain) @@ -1104,12 +1130,12 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa fManagedChain = TRUE; } - DT_CONTEXT * pChainContext = NULL; + const BYTE * pChainContext = NULL; if (fManagedChain) { // The chain to be added is managed itself. So we don't need to send an enter-managed chain. pChainInfo->m_fNeedEnterManagedChain = false; - pChainContext = &(pChainInfo->m_leafManagedContext); + pChainContext = pChainInfo->GetLeafManagedContext(); } else { @@ -1118,7 +1144,10 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa { // We need to send an extra enter-managed chain. _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); - BYTE * sp = reinterpret_cast(CORDB_ADDRESS_TO_PTR(CORDbgGetSP(&(pChainInfo->m_leafNativeContext)))); + CordbThread * pThread = static_cast(m_pThread.GetValue()); + BYTE * sp = reinterpret_cast( + ReadCtxReg(pThread, pChainInfo->GetLeafNativeContext(), GetContextSize(), + REGISTER_STACK_POINTER)); #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) // Dev11 324806: on ARM we use the caller's SP for a frame's ending delimiter so we cannot // subtract 4 bytes from the chain's ending delimiter else the frame might never be in range. @@ -1128,7 +1157,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa FramePointer fp = FramePointer::MakeFramePointer(sp); AppendChainWorker(pStackWalkInfo, - &(pChainInfo->m_leafManagedContext), + pChainInfo->GetLeafManagedContext(), fp, CHAIN_ENTER_MANAGED, TRUE); @@ -1136,7 +1165,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa pChainInfo->m_fNeedEnterManagedChain = false; } _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); - pChainContext = &(pChainInfo->m_leafNativeContext); + pChainContext = pChainInfo->GetLeafNativeContext(); } // Add the actual chain. @@ -1160,12 +1189,12 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // * pContext - the destination CONTEXT // -void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, DT_CONTEXT * pContext) +void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, BYTE * pContext) { HRESULT hr = pSW->GetContext(CONTEXT_FULL, - sizeof(*pContext), + GetContextSize(), NULL, - reinterpret_cast(pContext)); + pContext); IfFailThrow(hr); pChainInfo->m_rootFP = GetFramePointerForChain(pContext); @@ -1209,14 +1238,14 @@ BOOL ShimStackWalk::CheckInternalFrame(ICorDebugFrame * pNextStackFrame, hr = pThread3->CreateStackWalk(&pTmpSW); IfFailThrow(hr); - // retrieve the current CONTEXT - DT_CONTEXT ctx; - ctx.ContextFlags = DT_CONTEXT_FULL; - hr = pSW->GetContext(ctx.ContextFlags, sizeof(ctx), NULL, reinterpret_cast(&ctx)); + // retrieve the current CONTEXT into an opaque target-sized buffer + ULONG32 ctxSize = GetContextSize(); + NewArrayHolder ctx(new BYTE[ctxSize]); + hr = pSW->GetContext(CONTEXT_FULL, ctxSize, NULL, ctx); IfFailThrow(hr); // set the CONTEXT on the temporary ICDStackWalk - hr = pTmpSW->SetContext(SET_CONTEXT_FLAG_ACTIVE_FRAME, sizeof(ctx), reinterpret_cast(&ctx)); + hr = pTmpSW->SetContext(SET_CONTEXT_FLAG_ACTIVE_FRAME, ctxSize, ctx); IfFailThrow(hr); // unwind the temporary ICDStackWalk by one frame @@ -1225,11 +1254,13 @@ BOOL ShimStackWalk::CheckInternalFrame(ICorDebugFrame * pNextStackFrame, // Unwinding from a managed stack frame will land us either in a managed stack frame or a native // stack frame. In either case, we have a CONTEXT. - hr = pTmpSW->GetContext(ctx.ContextFlags, sizeof(ctx), NULL, reinterpret_cast(&ctx)); + hr = pTmpSW->GetContext(CONTEXT_FULL, ctxSize, NULL, ctx); IfFailThrow(hr); // Get the SP from the CONTEXT. This is the caller SP. - CORDB_ADDRESS sp = CORDbgGetSP(&ctx); + CordbThread * pThread = static_cast(m_pThread.GetValue()); + CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS( + ReadCtxReg(pThread, ctx, ctxSize, REGISTER_STACK_POINTER)); // get the frame address CORDB_ADDRESS frameAddr = 0; @@ -1428,7 +1459,7 @@ void ShimStackWalk::TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackW { // check whether we get any stack range _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); - FramePointer fpLeaf = GetFramePointerForChain(&(pChainInfo->m_leafNativeContext)); + FramePointer fpLeaf = GetFramePointerForChain(pChainInfo->GetLeafNativeContext()); // Don't bother creating an unmanaged chain if the stack range is empty. if (fpLeaf != pChainInfo->m_rootFP) @@ -1572,7 +1603,7 @@ BOOL ShimStackWalk::StackWalkInfo::HasConvertedFrame() ShimChain::ShimChain(ShimStackWalk * pSW, - DT_CONTEXT * pContext, + const BYTE * pContext, FramePointer fpRoot, UINT32 chainIndex, UINT32 frameStartIndex, @@ -1580,7 +1611,7 @@ ShimChain::ShimChain(ShimStackWalk * pSW, CorDebugChainReason chainReason, BOOL fIsManaged, RSLock * pShimLock) - : m_context(*pContext), + : m_contextSize(pSW->GetContextSize()), m_fpRoot(fpRoot), m_pStackWalk(pSW), m_refCount(0), @@ -1592,6 +1623,9 @@ ShimChain::ShimChain(ShimStackWalk * pSW, m_fIsNeutered(FALSE), m_pShimLock(pShimLock) { + // Own a copy of the leaf CONTEXT as an opaque target-sized byte buffer. + m_pContext = new BYTE[m_contextSize]; + memcpy(m_pContext, pContext, m_contextSize); } ShimChain::~ShimChain() @@ -1677,7 +1711,9 @@ HRESULT ShimChain::GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd) // The leafmost end is represented by the register set. if (pStart) { - *pStart = CORDbgGetSP(&m_context); + CordbThread * pThread = static_cast(m_pStackWalk->GetThread()); + *pStart = PTR_TO_CORDB_ADDRESS( + ReadCtxReg(pThread, m_pContext, m_contextSize, REGISTER_STACK_POINTER)); } // Return the rootmost end of the stack range. It is represented by the frame pointer of the chain. @@ -1830,7 +1866,8 @@ HRESULT ShimChain::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters) // This is a private hook for calling back into the RS. Alternatively, we could have created a // ShimRegisterSet, but that's too much work for now. - pThread->CreateCordbRegisterSet(&m_context, + pThread->CreateCordbRegisterSet(m_pContext, + m_contextSize, (m_chainIndex == 0), m_chainReason, ppRegisters); diff --git a/src/coreclr/debug/di/stdafx.h b/src/coreclr/debug/di/stdafx.h index 0f1ae48265b9de..44b03d8b240507 100644 --- a/src/coreclr/debug/di/stdafx.h +++ b/src/coreclr/debug/di/stdafx.h @@ -44,10 +44,5 @@ using std::max; #include "utilcode.h" #endif -#ifndef TARGET_ARM -#define DbiGetThreadContext(hThread, lpContext) ::GetThreadContext(hThread, (CONTEXT*)(lpContext)) -#define DbiSetThreadContext(hThread, lpContext) ::SetThreadContext(hThread, (CONTEXT*)(lpContext)) -#else -BOOL DbiGetThreadContext(HANDLE hThread, DT_CONTEXT *lpContext); -BOOL DbiSetThreadContext(HANDLE hThread, const DT_CONTEXT *lpContext); -#endif +BOOL DbiGetThreadContext(HANDLE hThread, T_CONTEXT *lpContext); +BOOL DbiSetThreadContext(HANDLE hThread, const T_CONTEXT *lpContext); diff --git a/src/coreclr/debug/di/valuehome.cpp b/src/coreclr/debug/di/valuehome.cpp index 1317df02b810a4..1d7e53a3b7f422 100644 --- a/src/coreclr/debug/di/valuehome.cpp +++ b/src/coreclr/debug/di/valuehome.cpp @@ -37,144 +37,22 @@ void RegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // RegValueHome::SetContextRegister // This will update a register in a given context, and in the regdisplay of a given frame. // Arguments: -// input: pContext - context from which the register comes +// updates a register in a given context buffer using the DAC. +// Arguments: +// input: pContext - context buffer in which the register is to be updated // regnum - enumeration constant indicating which register is to be updated // newVal - the new value for the register contents -// output: no out parameters, but the new value will be written to the context and the frame -// Notes: We don't take a data target here because we are directly writing process memory and passing -// in a context, which has the location to update. -// Throws -void RegValueHome::SetContextRegister(DT_CONTEXT * pContext, +// output: no out parameters, but the new value will be written to the context buffer +void RegValueHome::SetContextRegister(BYTE * pContext, CorDebugRegister regNum, SIZE_T newVal) { - LPVOID rdRegAddr; - -#define _UpdateFrame() \ - if (m_pFrame != NULL) \ - { \ - rdRegAddr = m_pFrame->GetAddressOfRegister(regNum); \ - *(SIZE_T *)rdRegAddr = newVal; \ - } - - switch(regNum) + IDacDbiInterface * pDAC = m_pFrame->GetProcess()->GetDAC(); + TADDR value = (TADDR)newVal; + ULONG32 cbCtx = m_pFrame->GetProcess()->GetTargetContextSize(); + HRESULT hr = pDAC->WriteRegistersToContext(pContext, cbCtx, ®Num, 1, &value); + if (FAILED(hr)) { - case REGISTER_INSTRUCTION_POINTER: CORDbgSetIP(pContext, (LPVOID)newVal); break; - case REGISTER_STACK_POINTER: CORDbgSetSP(pContext, (LPVOID)newVal); break; - -#if defined(TARGET_X86) - case REGISTER_FRAME_POINTER: CORDbgSetFP(pContext, (LPVOID)newVal); - _UpdateFrame(); break; - - case REGISTER_X86_EAX: pContext->Eax = newVal; - _UpdateFrame(); break; - case REGISTER_X86_ECX: pContext->Ecx = newVal; - _UpdateFrame(); break; - case REGISTER_X86_EDX: pContext->Edx = newVal; - _UpdateFrame(); break; - case REGISTER_X86_EBX: pContext->Ebx = newVal; - _UpdateFrame(); break; - case REGISTER_X86_ESI: pContext->Esi = newVal; - _UpdateFrame(); break; - case REGISTER_X86_EDI: pContext->Edi = newVal; - _UpdateFrame(); break; - -#elif defined(TARGET_AMD64) - case REGISTER_AMD64_RBP: pContext->Rbp = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RAX: pContext->Rax = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RCX: pContext->Rcx = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RDX: pContext->Rdx = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RBX: pContext->Rbx = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RSI: pContext->Rsi = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_RDI: pContext->Rdi = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R8: pContext->R8 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R9: pContext->R9 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R10: pContext->R10 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R11: pContext->R11 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R12: pContext->R12 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R13: pContext->R13 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R14: pContext->R14 = newVal; - _UpdateFrame(); break; - case REGISTER_AMD64_R15: pContext->R15 = newVal; - _UpdateFrame(); break; -#elif defined(TARGET_ARM) - case REGISTER_ARM_R0: pContext->R0 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R1: pContext->R1 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R2: pContext->R2 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R3: pContext->R3 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R4: pContext->R4 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R5: pContext->R5 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R6: pContext->R6 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R7: pContext->R7 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R8: pContext->R8 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R9: pContext->R9 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R10: pContext->R10 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R11: pContext->R11 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_R12: pContext->R12 = newVal; - _UpdateFrame(); break; - case REGISTER_ARM_LR: pContext->Lr = newVal; - _UpdateFrame(); break; -#elif defined(TARGET_ARM64) - case REGISTER_ARM64_X0: - case REGISTER_ARM64_X1: - case REGISTER_ARM64_X2: - case REGISTER_ARM64_X3: - case REGISTER_ARM64_X4: - case REGISTER_ARM64_X5: - case REGISTER_ARM64_X6: - case REGISTER_ARM64_X7: - case REGISTER_ARM64_X8: - case REGISTER_ARM64_X9: - case REGISTER_ARM64_X10: - case REGISTER_ARM64_X11: - case REGISTER_ARM64_X12: - case REGISTER_ARM64_X13: - case REGISTER_ARM64_X14: - case REGISTER_ARM64_X15: - case REGISTER_ARM64_X16: - case REGISTER_ARM64_X17: - case REGISTER_ARM64_X18: - case REGISTER_ARM64_X19: - case REGISTER_ARM64_X20: - case REGISTER_ARM64_X21: - case REGISTER_ARM64_X22: - case REGISTER_ARM64_X23: - case REGISTER_ARM64_X24: - case REGISTER_ARM64_X25: - case REGISTER_ARM64_X26: - case REGISTER_ARM64_X27: - case REGISTER_ARM64_X28: pContext->X[regNum - REGISTER_ARM64_X0] = newVal; - _UpdateFrame(); break; - - case REGISTER_ARM64_LR: pContext->Lr = newVal; - _UpdateFrame(); break; -#endif - default: _ASSERTE(!"Invalid register number!"); ThrowHR(E_FAIL); } @@ -183,7 +61,7 @@ void RegValueHome::SetContextRegister(DT_CONTEXT * pContext, // RegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see code:EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +void RegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) { SIZE_T extendedVal = 0; @@ -237,11 +115,13 @@ void RegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pCont // for full header comment) void RegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) { - UINT_PTR* reg = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); - _ASSERTE(reg != NULL); - _ASSERTE(sizeof(*reg) == valueOutBuffer.Size()); + _ASSERTE(sizeof(TADDR) == valueOutBuffer.Size()); + + TADDR value = 0; + HRESULT hr = m_pFrame->ReadContextRegister(m_reg1Info.m_kRegNumber, &value); + IfFailThrow(hr); - memcpy(valueOutBuffer.StartAddress(), reg, sizeof(*reg)); + memcpy(valueOutBuffer.StartAddress(), &value, sizeof(value)); } // RegValueHome::GetEnregisteredValue @@ -266,7 +146,7 @@ void RegRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // RegRegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) { _ASSERTE(newValue.Size() == 8); _ASSERTE(REG_SIZE == sizeof(void*)); @@ -278,13 +158,10 @@ void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pC memcpy(&lowPart, newValue.StartAddress(), REG_SIZE); memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); - // Update the proper registers. + // Update the proper registers. SetContextRegister writes through to the + // active CONTEXT - which is the only source of truth now that REGDISPLAY is gone. SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws SetContextRegister(pContext, m_reg2Info.m_kRegNumber, lowPart); // throws - - // update the frame's register display - void * valueAddress = (void *)(m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber)); - memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); } // RegRegValueHome::SetEnregisteredValue // RegRegValueHome::GetEnregisteredValue @@ -292,16 +169,15 @@ void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pC // for full header comment) void RegRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) { - UINT_PTR* highWordAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); - _ASSERTE(highWordAddr != NULL); - - UINT_PTR* lowWordAddr = m_pFrame->GetAddressOfRegister(m_reg2Info.m_kRegNumber); - _ASSERTE(lowWordAddr != NULL); + TADDR highWord = 0; + TADDR lowWord = 0; + IfFailThrow(m_pFrame->ReadContextRegister(m_reg1Info.m_kRegNumber, &highWord)); + IfFailThrow(m_pFrame->ReadContextRegister(m_reg2Info.m_kRegNumber, &lowWord)); - _ASSERTE(sizeof(*highWordAddr) + sizeof(*lowWordAddr) == valueOutBuffer.Size()); + _ASSERTE(sizeof(highWord) + sizeof(lowWord) == valueOutBuffer.Size()); - memcpy(valueOutBuffer.StartAddress(), lowWordAddr, sizeof(*lowWordAddr)); - memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowWordAddr), highWordAddr, sizeof(*highWordAddr)); + memcpy(valueOutBuffer.StartAddress(), &lowWord, sizeof(lowWord)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowWord), &highWord, sizeof(highWord)); } // RegRegValueHome::GetEnregisteredValue @@ -325,7 +201,7 @@ void RegMemValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // RegMemValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) { _ASSERTE(newValue.Size() == REG_SIZE >> 1); // make sure we have bytes for two registers _ASSERTE(REG_SIZE == sizeof(void*)); @@ -352,18 +228,18 @@ void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pC void RegMemValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) { // Read the high bits from the register... - UINT_PTR* highBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); - _ASSERTE(highBitsAddr != NULL); + TADDR highBits = 0; + IfFailThrow(m_pFrame->ReadContextRegister(m_reg1Info.m_kRegNumber, &highBits)); // ... and the low bits from the remote process DWORD lowBits; HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowBits); IfFailThrow(hr); - _ASSERTE(sizeof(lowBits)+sizeof(*highBitsAddr) == valueOutBuffer.Size()); + _ASSERTE(sizeof(lowBits) + sizeof(highBits) == valueOutBuffer.Size()); memcpy(valueOutBuffer.StartAddress(), &lowBits, sizeof(lowBits)); - memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowBits), highBitsAddr, sizeof(*highBitsAddr)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowBits), &highBits, sizeof(highBits)); } // RegMemValueHome::GetEnregisteredValue @@ -387,7 +263,7 @@ void MemRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // MemRegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, DT_CONTEXT * pContext, bool fIsSigned) +void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) { _ASSERTE(newValue.Size() == REG_SIZE << 1); // make sure we have bytes for two registers _ASSERTE(REG_SIZE == sizeof(void *)); @@ -417,15 +293,14 @@ void MemRegValueHome::GetEnregisteredValue(MemoryRange valueOutBuffer) HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &highBits); IfFailThrow(hr); - // and the low bits from a register - UINT_PTR* lowBitsAddr = m_pFrame->GetAddressOfRegister(m_reg1Info.m_kRegNumber); - _ASSERTE(lowBitsAddr != NULL); + TADDR lowBits = 0; + IfFailThrow(m_pFrame->ReadContextRegister(m_reg1Info.m_kRegNumber, &lowBits)); - _ASSERTE(sizeof(*lowBitsAddr)+sizeof(highBits) == valueOutBuffer.Size()); + _ASSERTE(sizeof(lowBits) + sizeof(highBits) == valueOutBuffer.Size()); - memcpy(valueOutBuffer.StartAddress(), lowBitsAddr, sizeof(*lowBitsAddr)); - memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(*lowBitsAddr), &highBits, sizeof(highBits)); + memcpy(valueOutBuffer.StartAddress(), &lowBits, sizeof(lowBits)); + memcpy((BYTE *)valueOutBuffer.StartAddress() + sizeof(lowBits), &highBits, sizeof(highBits)); } // MemRegValueHome::GetEnregisteredValue @@ -445,127 +320,13 @@ void FloatRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) } // FloatRegValueHome::CopyToIPCEType // FloatValueHome::SetEnregisteredValue -// set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue -// for full header comment) +// set a remote enregistered location to a new value. void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, - DT_CONTEXT * pContext, + BYTE * pContext, bool fIsSigned) { _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); - // Convert the input to a double. - double newVal = 0.0; - - memcpy(&newVal, newValue.StartAddress(), newValue.Size()); - -#if defined(TARGET_X86) - - // What a pain, on X86 take the floating - // point state in the context and make it our current FP - // state, set the value into the current FP state, then - // save out the FP state into the context again and - // restore our original state. - DT_FLOATING_SAVE_AREA currentFPUState; - - #ifdef _MSC_VER - __asm fnsave currentFPUState // save the current FPU state. - #else - __asm__ __volatile__ - ( - " fnsave %0\n" \ - : "=m"(currentFPUState) - ); - #endif - - // Copy the state out of the context. - DT_FLOATING_SAVE_AREA floatarea = pContext->FloatSave; - floatarea.StatusWord &= 0xFF00; // remove any error codes. - floatarea.ControlWord |= 0x3F; // mask all exceptions. - - #ifdef _MSC_VER - __asm - { - fninit - frstor floatarea ;; reload the threads FPU state. - } - #else - __asm__ - ( - " fninit\n" \ - " frstor %0\n" \ - : /* no outputs */ - : "m"(floatarea) - ); - #endif - - double td; // temp double - double popArea[DebuggerIPCE_FloatCount]; - - // Pop off until we reach the value we want to change. - DWORD i = 0; - - while (i <= m_floatIndex) - { - #ifdef _MSC_VER - __asm fstp td - #else - __asm("fstpl %0" : "=m" (td)); - #endif - popArea[i++] = td; - } - - #ifdef _MSC_VER - __asm fld newVal; // push on the new value. - #else - __asm("fldl %0" : "=m" (newVal)); - #endif - - // Push any values that we popled off back onto the stack, - // _except_ the last one, which was the one we changed. - i--; - - while (i > 0) - { - td = popArea[--i]; - #ifdef _MSC_VER - __asm fld td - #else - __asm("fldl %0" : "=m" (td)); - #endif - } - - // Save out the modified float area. - #ifdef _MSC_VER - __asm fnsave floatarea - #else - __asm__ __volatile__ - ( - " fnsave %0\n" \ - : "=m"(floatarea) - ); - #endif - - // Put it into the context. - pContext->FloatSave= floatarea; - - // Restore our FPU state - #ifdef _MSC_VER - __asm - { - fninit - frstor currentFPUState ;; restore our saved FPU state. - } - #else - __asm__ - ( - " fninit\n" \ - " frstor %0\n" \ - : /* no outputs */ - : "m"(currentFPUState) - ); - #endif -#endif // TARGET_X86 - // update the thread's floating point stack void * valueAddress = (void *) &(m_pFrame->m_pThread->m_floatValues[m_floatIndex]); memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); @@ -799,8 +560,6 @@ void RegisterValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) { _ASSERTE(m_pRemoteRegAddr != NULL); - // Get the thread's context so we can update it. - DT_CONTEXT * cTemp = NULL; const CordbNativeFrame * frame = m_pRemoteRegAddr->GetFrame(); // Can't set an enregistered value unless the frame the value was @@ -812,6 +571,10 @@ void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); } + ULONG32 cbCtx = frame->GetProcess()->GetTargetContextSize(); + + // Get the thread's context so we can update it. + BYTE * cTemp = NULL; HRESULT hr = S_OK; EX_TRY { @@ -825,14 +588,17 @@ void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); } - // Its important to copy this context that we're given a ptr to. - DT_CONTEXT c; - c = *cTemp; + // Work on a local copy so failures in the chain below don't corrupt the + // thread's cached context. The subclass mutates this buffer to apply the + // new register value, and SetManagedContext then ships it to the LS and + // updates the cache. + NewArrayHolder ctxBuf(new BYTE[cbCtx]); + memcpy(ctxBuf, cTemp, cbCtx); - m_pRemoteRegAddr->SetEnregisteredValue(src, &c, fIsSigned); + m_pRemoteRegAddr->SetEnregisteredValue(src, ctxBuf, fIsSigned); // Set the thread's modified context. - IfFailThrow(frame->m_pThread->SetManagedContext(&c)); + IfFailThrow(frame->m_pThread->SetManagedContext(ctxBuf, cbCtx)); } // RegisterValueHome::SetEnregisteredValue diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 52a3fbe68d7024..6f08e1063ec452 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -3499,7 +3499,7 @@ void DebuggerController::ApplyTraceFlag(Thread *thread) g_pEEInterface->MarkThreadForDebugStepping(thread, true); LOG((LF_CORDB,LL_INFO1000, "DC::ApplyTraceFlag marked thread for debug stepping\n")); - SetSSFlag(reinterpret_cast(context) ARM_ARG(thread) ARM64_ARG(thread) RISCV64_ARG(thread) LOONGARCH64_ARG(thread)); + SetSSFlag(context ARM_ARG(thread) ARM64_ARG(thread) RISCV64_ARG(thread) LOONGARCH64_ARG(thread)); } // @@ -3549,7 +3549,7 @@ void DebuggerController::UnapplyTraceFlag(Thread *thread) // Always need to unmark for stepping g_pEEInterface->MarkThreadForDebugStepping(thread, false); - UnsetSSFlag(reinterpret_cast(context) ARM_ARG(thread) ARM64_ARG(thread) RISCV64_ARG(thread) LOONGARCH64_ARG(thread)); + UnsetSSFlag(context ARM_ARG(thread) ARM64_ARG(thread) RISCV64_ARG(thread) LOONGARCH64_ARG(thread)); } void DebuggerController::EnableExceptionHook() @@ -8327,7 +8327,7 @@ void DebuggerStepper::PrepareForSendEvent(StackTraceTicket ticket) CONTEXT *context = g_pEEInterface->GetThreadFilterContext(GetThread()); if (context == NULL) { - void * pIP = CORDbgGetIP(reinterpret_cast(context)); + void * pIP = CORDbgGetIP(context); DebuggerJitInfo * dji = g_pDebugger->GetJitInfoFromAddr((TADDR) pIP); DebuggerMethodInfo * dmi = NULL; @@ -9253,8 +9253,8 @@ TP_RESULT DebuggerFuncEvalComplete::TriggerPatch(DebuggerControllerPatch *patch, #error Not supported #endif #endif - CORDbgCopyThreadContext(reinterpret_cast(pCtx), - reinterpret_cast(&(m_pDE->m_context))); + CORDbgCopyThreadContext(reinterpret_cast(pCtx), + reinterpret_cast(&(m_pDE->m_context))); // We've hit our patch, so simply disable all (which removes the // patch) and trigger the event. diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 54bde6c60c6845..29288d15db1c32 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -13319,7 +13319,7 @@ VOID Debugger::M2UHandoffHijackWorker(CONTEXT *pContext, //win32 has a weird property where EIP points after the BP in the debug event //so we are adjusting it to point at the BP - CORDbgAdjustPCForBreakInstruction((DT_CONTEXT*)pContext); + CORDbgAdjustPCForBreakInstruction(pContext); LOG((LF_CORDB, LL_INFO1000, "D::M2UHHW: Context ip set to 0x%p\n", GetIP(pContext))); _ASSERTE(!ISREDIRECTEDTHREAD(pEEThread)); @@ -14956,7 +14956,7 @@ BOOL Debugger::IsThreadContextInvalid(Thread *pThread, CONTEXT *pCtx) if (success) { // Check single-step flag - if (IsSSFlagEnabled(reinterpret_cast(pCtx) ARM_ARG(pThread) ARM64_ARG(pThread) RISCV64_ARG(pThread) LOONGARCH64_ARG(pThread))) + if (IsSSFlagEnabled(pCtx ARM_ARG(pThread) ARM64_ARG(pThread) RISCV64_ARG(pThread) LOONGARCH64_ARG(pThread))) { // Can't hijack a thread whose SS-flag is set. This could lead to races // with the thread taking the SS-exception. diff --git a/src/coreclr/debug/inc/amd64/primitives.h b/src/coreclr/debug/inc/amd64/primitives.h index 7980e11dcb9695..26746151fcf875 100644 --- a/src/coreclr/debug/inc/amd64/primitives.h +++ b/src/coreclr/debug/inc/amd64/primitives.h @@ -21,8 +21,6 @@ typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; #define PRD_TYPE DWORD_PTR #endif -typedef M128A FPRegister64; - // From section 1.1 of AMD64 Programmers Manual Vol 3. #define MAX_INSTRUCTION_LENGTH 15 @@ -88,7 +86,7 @@ inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum re // // inline function to access/modify the CONTEXT // -inline LPVOID CORDbgGetIP(DT_CONTEXT* context) +inline LPVOID CORDbgGetIP(T_CONTEXT* context) { CONTRACTL { @@ -102,7 +100,7 @@ inline LPVOID CORDbgGetIP(DT_CONTEXT* context) return (LPVOID) context->Rip; } -inline void CORDbgSetIP(DT_CONTEXT* context, LPVOID rip) +inline void CORDbgSetIP(T_CONTEXT* context, LPVOID rip) { CONTRACTL { @@ -116,7 +114,7 @@ inline void CORDbgSetIP(DT_CONTEXT* context, LPVOID rip) context->Rip = (DWORD64) rip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { CONTRACTL { @@ -203,7 +201,7 @@ inline void CORDbgSetInstruction(UNALIGNED CORDB_ADDRESS_TYPE* address, } -inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) +inline void CORDbgAdjustPCForBreakInstruction(T_CONTEXT* pContext) { LIMITED_METHOD_CONTRACT; @@ -217,19 +215,19 @@ inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE *address) return *address == CORDbg_BREAK_INSTRUCTION; } -inline void SetSSFlag(DT_CONTEXT *pContext) +inline void SetSSFlag(T_CONTEXT *pContext) { _ASSERTE(pContext != NULL); pContext->EFlags |= 0x100; } -inline void UnsetSSFlag(DT_CONTEXT *pContext) +inline void UnsetSSFlag(T_CONTEXT *pContext) { _ASSERTE(pContext != NULL); pContext->EFlags &= ~0x100; } -inline bool IsSSFlagEnabled(DT_CONTEXT * context) +inline bool IsSSFlagEnabled(T_CONTEXT * context) { _ASSERTE(context != NULL); return (context->EFlags & 0x100) != 0; diff --git a/src/coreclr/debug/inc/arm/primitives.h b/src/coreclr/debug/inc/arm/primitives.h index 431d223fc73b39..d057f8565efb1a 100644 --- a/src/coreclr/debug/inc/arm/primitives.h +++ b/src/coreclr/debug/inc/arm/primitives.h @@ -16,7 +16,6 @@ #define THUMB_CODE 1 #endif -typedef ULONGLONG FPRegister64; typedef const BYTE CORDB_ADDRESS_TYPE; typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; @@ -86,13 +85,13 @@ constexpr CorDebugRegister g_JITToCorDbgReg[] = // // inline function to access/modify the CONTEXT // -inline void CORDbgSetIP(DT_CONTEXT *context, LPVOID eip) { +inline void CORDbgSetIP(T_CONTEXT *context, LPVOID eip) { LIMITED_METHOD_CONTRACT; context->Pc = (UINT32)(size_t)eip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) { +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { LIMITED_METHOD_CONTRACT; return (CORDB_ADDRESS)(context->Sp); diff --git a/src/coreclr/debug/inc/arm64/primitives.h b/src/coreclr/debug/inc/arm64/primitives.h index cb7553be3c075e..23ca84322d58e0 100644 --- a/src/coreclr/debug/inc/arm64/primitives.h +++ b/src/coreclr/debug/inc/arm64/primitives.h @@ -16,7 +16,6 @@ #include "executableallocator.h" #endif -typedef NEON128 FPRegister64; typedef const BYTE CORDB_ADDRESS_TYPE; typedef DPTR(CORDB_ADDRESS_TYPE) PTR_CORDB_ADDRESS_TYPE; @@ -97,13 +96,13 @@ constexpr CorDebugRegister g_JITToCorDbgReg[] = REGISTER_ARM64_PC }; -inline void CORDbgSetIP(DT_CONTEXT *context, LPVOID eip) { +inline void CORDbgSetIP(T_CONTEXT *context, LPVOID eip) { LIMITED_METHOD_CONTRACT; context->Pc = (DWORD64)eip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) { +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { LIMITED_METHOD_CONTRACT; return (CORDB_ADDRESS)(context->Sp); @@ -169,19 +168,19 @@ inline PRD_TYPE CORDbgGetInstruction(UNALIGNED CORDB_ADDRESS_TYPE* address) } -inline void SetSSFlag(DT_CONTEXT *pContext) +inline void SetSSFlag(T_CONTEXT *pContext) { _ASSERTE(pContext != NULL); pContext->Cpsr |= 0x00200000; } -inline void UnsetSSFlag(DT_CONTEXT *pContext) +inline void UnsetSSFlag(T_CONTEXT *pContext) { _ASSERTE(pContext != NULL); pContext->Cpsr &= ~0x00200000; } -inline bool IsSSFlagEnabled(DT_CONTEXT * pContext) +inline bool IsSSFlagEnabled(T_CONTEXT * pContext) { _ASSERTE(pContext != NULL); return (pContext->Cpsr & 0x00200000) != 0; diff --git a/src/coreclr/debug/inc/arm_primitives.h b/src/coreclr/debug/inc/arm_primitives.h index 8c21a44fb3e76e..de04ac395b10aa 100644 --- a/src/coreclr/debug/inc/arm_primitives.h +++ b/src/coreclr/debug/inc/arm_primitives.h @@ -66,11 +66,11 @@ inline void CORDbgInsertBreakpointExImpl(UNALIGNED CORDB_ADDRESS_TYPE *address) // After a breakpoint exception, the CPU points to _after_ the break instruction. // Adjust the IP so that it points at the break instruction. This lets us patch that // opcode and re-execute what was underneath the bp. -inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) +inline void CORDbgAdjustPCForBreakInstruction(T_CONTEXT* pContext) { LIMITED_METHOD_CONTRACT; -#if defined(TARGET_ARM64) +#if defined(HOST_ARM64) pContext->Pc -= CORDbg_BREAK_INSTRUCTION_SIZE; #else // @ARMTODO: ARM appears to leave the PC at the start of the breakpoint (at least according to Windbg, diff --git a/src/coreclr/debug/inc/common.h b/src/coreclr/debug/inc/common.h index 5e4000839846f8..b17bf7915533b2 100644 --- a/src/coreclr/debug/inc/common.h +++ b/src/coreclr/debug/inc/common.h @@ -59,7 +59,7 @@ void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent, // respecting the ContextFlags of both contexts. // -extern void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc); +extern void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc); //--------------------------------------------------------------------------------------- // diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index f63cd9fbcc79b9..94ed595598608d 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -1079,7 +1079,7 @@ IDacDbiInterface : public IUnknown // This is a special case that violates the 'no state' tenant. // - virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, DT_CONTEXT * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) = 0; + virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) = 0; // Delete the stackwalk object created from CreateStackWalk. virtual HRESULT STDMETHODCALLTYPE DeleteStackWalk(StackWalkHandle ppSFIHandle) = 0; @@ -1092,7 +1092,7 @@ IDacDbiInterface : public IUnknown // pContext - OUT: the CONTEXT to be filled out. The context control flags are ignored. // - virtual HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, DT_CONTEXT * pContext) = 0; + virtual HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext) = 0; // // Set the stackwalker to the given CONTEXT. The CorDebugSetContextFlag indicates whether @@ -1106,7 +1106,7 @@ IDacDbiInterface : public IUnknown // pContext - the specified CONTEXT. This may make correctional adjustments to the context's IP. // - virtual HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, DT_CONTEXT * pContext) = 0; + virtual HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContext) = 0; // // Unwind the stackwalker to the next frame. The next frame could be any actual stack frame, @@ -1136,7 +1136,7 @@ IDacDbiInterface : public IUnknown // virtual HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, - const DT_CONTEXT * pContext) = 0; + const BYTE * pContext) = 0; // // Fill in the Debugger_STRData structure with information about the current frame @@ -1253,7 +1253,7 @@ IDacDbiInterface : public IUnknown // This will be deprecated in V3. // - virtual HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const DT_CONTEXT * pContext, OUT BOOL * pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContext, OUT BOOL * pResult) = 0; // Get the context for a particular thread of the target process. // Arguments: @@ -1261,7 +1261,7 @@ IDacDbiInterface : public IUnknown // output: pContextBuffer - the address of the CONTEXT to be initialized. // The memory for this belongs to the caller. It must not be NULL. // Note: returns an appropriate failure HRESULT on error - virtual HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContextBuffer) = 0; + virtual HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, BYTE * pContextBuffer) = 0; typedef enum { @@ -2228,6 +2228,97 @@ IDacDbiInterface : public IUnknown VMPTR_MethodDesc vmMethod, OUT UINT32* pTokenIndex) = 0; + typedef enum + { + kContextSizeBase = 0, + kContextSizeExtendedRegisters, + } ContextSizeFlags; + + virtual HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize) = 0; + + virtual HRESULT STDMETHODCALLTYPE WriteRegistersToContext( + IN OUT BYTE * ctxBuf, + IN ULONG32 cb, + IN const CorDebugRegister * regs, + IN ULONG32 nRegs, + IN const TADDR * values) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReadRegistersFromContext( + IN BYTE * ctxBuf, + IN ULONG32 cb, + IN const CorDebugRegister * regs, + IN ULONG32 nRegs, + OUT TADDR * pValues) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetAvailableRegistersMask( + IN BOOL fActive, + IN BOOL fQuickUnwind, + IN ULONG32 regCount, + OUT BYTE pAvailable[]) = 0; + + virtual HRESULT STDMETHODCALLTYPE ConvertJitRegNumToCorDebugRegister( + IN ULONG32 jitRegNum, + OUT CorDebugRegister * pReg) = 0; + + virtual HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( + IN BYTE * ctxBuf, + IN ULONG32 cb, + IN ULONG32 regCount, + OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], + OUT ULONG32 * pValuesCount, + OUT int * pFirstFloatReg, + OUT ULONG32 * pFloatStackTop) = 0; + + typedef enum + { + kArchUnknown = 0, + kArchX86, + kArchAMD64, + kArchArm, + kArchArm64, + kArchLoongArch64, + kArchRiscV64, + kArchWasm, + } TargetArchitecture; + + typedef enum + { + kOSUnknown = 0, + kOSWindows, + kOSUnix, + } TargetOperatingSystem; + + struct TargetInfo + { + TargetArchitecture arch; + TargetOperatingSystem os; + }; + + virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; + + virtual HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters( + IN BYTE * ctxBuf, + IN ULONG32 cb, + OUT BOOL * pResult) = 0; + + virtual HRESULT STDMETHODCALLTYPE CompareControlRegisters( + IN const BYTE * ctxBuf1, + IN ULONG32 cb1, + IN const BYTE * ctxBuf2, + IN ULONG32 cb2, + OUT BOOL * pResult) = 0; + + // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both + // contexts. flags != 0 first stamps dstCtxBuf->ContextFlags = flags so the + // copy pulls exactly the requested chunks from the source; flags == 0 + // preserves the destination's existing ContextFlags. + virtual HRESULT STDMETHODCALLTYPE CopyContext( + IN OUT BYTE * dstCtxBuf, + IN ULONG32 cbDst, + IN const BYTE * srcCtxBuf, + IN ULONG32 cbSrc, + IN ULONG32 flags) = 0; + // The following tag tells the DD-marshalling tool to stop scanning. // END_MARSHAL diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index 0f4d5f8cfeb127..8766f9364b2c42 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -539,7 +539,7 @@ struct MSLAYOUT Debugger_JITFuncData struct MSLAYOUT Debugger_STRData { FramePointer fp; - DT_CONTEXT * ctx; + BYTE * ctx; // opaque target CONTEXT bytes (DT_CONTEXT image) VMPTR_AppDomain vmCurrentAppDomainToken; diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index 5b835b115f3224..efc069036991d8 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -958,50 +958,7 @@ struct MSLAYOUT IPCENames // We use a class/struct so that the function can rema #endif // !DACCESS_COMPILE -// -// NOTE: CPU-specific values below! -// DebuggerIPCE_FloatCount is the number of doubles in the processor's -// floating point stack. - -#if defined(TARGET_X86) -#define DebuggerIPCE_FloatCount 8 -#elif defined(TARGET_AMD64) -#define DebuggerIPCE_FloatCount 16 -#elif defined(TARGET_ARM) -#define DebuggerIPCE_FloatCount 32 -#elif defined(TARGET_ARM64) -#define DebuggerIPCE_FloatCount 32 -#elif defined(TARGET_LOONGARCH64) -#define DebuggerIPCE_FloatCount 32 -#elif defined(TARGET_RISCV64) -#define DebuggerIPCE_FloatCount 32 -#else -#define DebuggerIPCE_FloatCount 1 -#endif - -#if !defined(TARGET_WASM) -inline LPVOID GetSPAddress(const DT_CONTEXT * context) -{ -#if defined(TARGET_X86) - return (LPVOID)&context->Esp; -#elif defined(TARGET_AMD64) - return (LPVOID)&context->Rsp; -#else - return (LPVOID)&context->Sp; -#endif -} -#endif // !TARGET_WASM - -#if !defined(TARGET_AMD64) && !defined(TARGET_ARM) && !defined(TARGET_WASM) -inline LPVOID GetFPAddress(const DT_CONTEXT * context) -{ -#if defined(TARGET_X86) - return (LPVOID)&context->Ebp; -#else - return (LPVOID)&context->Fp; -#endif -} -#endif // !TARGET_AMD64 && !TARGET_ARM && !TARGET_WASM +#define CORDB_MAX_FLOAT_REGISTERS 32 class MSLAYOUT FramePointer diff --git a/src/coreclr/debug/inc/i386/primitives.h b/src/coreclr/debug/inc/i386/primitives.h index aa7d35a73a9bfa..0144d013399ee5 100644 --- a/src/coreclr/debug/inc/i386/primitives.h +++ b/src/coreclr/debug/inc/i386/primitives.h @@ -78,13 +78,13 @@ inline LPVOID CORDbgGetIP(DT_CONTEXT *context) { return (LPVOID)(size_t)(context->Eip); } -inline void CORDbgSetIP(DT_CONTEXT *context, LPVOID eip) { +inline void CORDbgSetIP(T_CONTEXT *context, LPVOID eip) { LIMITED_METHOD_CONTRACT; context->Eip = (UINT32)(size_t)eip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) { +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { LIMITED_METHOD_CONTRACT; return (CORDB_ADDRESS)(context->Esp); @@ -163,7 +163,7 @@ inline void CORDbgSetInstruction(CORDB_ADDRESS_TYPE* address, // After a breakpoint exception, the CPU points to _after_ the break instruction. // Adjust the IP so that it points at the break instruction. This lets us patch that // opcode and re-execute what was underneath the bp. -inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) +inline void CORDbgAdjustPCForBreakInstruction(T_CONTEXT* pContext) { LIMITED_METHOD_CONTRACT; @@ -178,14 +178,14 @@ inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE* address) } // Set the hardware trace flag. -inline void SetSSFlag(DT_CONTEXT *context) +inline void SetSSFlag(T_CONTEXT *context) { _ASSERTE(context != NULL); context->EFlags |= 0x100; } // Unset the hardware trace flag. -inline void UnsetSSFlag(DT_CONTEXT *context) +inline void UnsetSSFlag(T_CONTEXT *context) { SUPPORTS_DAC; _ASSERTE(context != NULL); @@ -193,7 +193,7 @@ inline void UnsetSSFlag(DT_CONTEXT *context) } // return true if the hardware trace flag applied. -inline bool IsSSFlagEnabled(DT_CONTEXT * context) +inline bool IsSSFlagEnabled(T_CONTEXT * context) { _ASSERTE(context != NULL); return (context->EFlags & 0x100) != 0; diff --git a/src/coreclr/debug/inc/loongarch64/primitives.h b/src/coreclr/debug/inc/loongarch64/primitives.h index e66743adfd084a..0fc5fcf4b3720b 100644 --- a/src/coreclr/debug/inc/loongarch64/primitives.h +++ b/src/coreclr/debug/inc/loongarch64/primitives.h @@ -83,13 +83,13 @@ constexpr CorDebugRegister g_JITToCorDbgReg[] = REGISTER_LOONGARCH64_PC }; -inline void CORDbgSetIP(DT_CONTEXT *context, LPVOID ip) { +inline void CORDbgSetIP(T_CONTEXT *context, LPVOID ip) { LIMITED_METHOD_CONTRACT; context->Pc = (DWORD64)ip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) { +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { LIMITED_METHOD_CONTRACT; return (CORDB_ADDRESS)(context->Sp); @@ -202,7 +202,7 @@ inline void CORDbgInsertBreakpointExImpl(UNALIGNED CORDB_ADDRESS_TYPE *address) // After a breakpoint exception, the CPU points to _after_ the break instruction. // Adjust the IP so that it points at the break instruction. This lets us patch that // opcode and re-execute what was underneath the bp. -inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) +inline void CORDbgAdjustPCForBreakInstruction(T_CONTEXT* pContext) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/debug/inc/riscv64/primitives.h b/src/coreclr/debug/inc/riscv64/primitives.h index 821a324281dcaf..abb80707a34626 100644 --- a/src/coreclr/debug/inc/riscv64/primitives.h +++ b/src/coreclr/debug/inc/riscv64/primitives.h @@ -84,13 +84,13 @@ constexpr CorDebugRegister g_JITToCorDbgReg[] = REGISTER_RISCV64_PC }; -inline void CORDbgSetIP(DT_CONTEXT *context, LPVOID ip) { +inline void CORDbgSetIP(T_CONTEXT *context, LPVOID ip) { LIMITED_METHOD_CONTRACT; context->Pc = (DWORD64)ip; } -inline CORDB_ADDRESS CORDbgGetSP(const DT_CONTEXT * context) { +inline CORDB_ADDRESS CORDbgGetSP(const T_CONTEXT * context) { LIMITED_METHOD_CONTRACT; return (CORDB_ADDRESS)(context->Sp); @@ -203,7 +203,7 @@ inline void CORDbgInsertBreakpointExImpl(UNALIGNED CORDB_ADDRESS_TYPE *address) // After a breakpoint exception, the CPU points to _after_ the break instruction. // Adjust the IP so that it points at the break instruction. This lets us patch that // opcode and re-execute what was underneath the bp. -inline void CORDbgAdjustPCForBreakInstruction(DT_CONTEXT* pContext) +inline void CORDbgAdjustPCForBreakInstruction(T_CONTEXT* pContext) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/debug/shared/amd64/primitives.cpp b/src/coreclr/debug/shared/amd64/primitives.cpp index ff23ab99b1003d..5f9e757dfc7705 100644 --- a/src/coreclr/debug/shared/amd64/primitives.cpp +++ b/src/coreclr/debug/shared/amd64/primitives.cpp @@ -16,7 +16,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { ULONG dstFlags = pDst->ContextFlags; ULONG srcFlags = pSrc->ContextFlags; diff --git a/src/coreclr/debug/shared/arm/primitives.cpp b/src/coreclr/debug/shared/arm/primitives.cpp index 4cdf1e82af643d..58015ef2fb9e7a 100644 --- a/src/coreclr/debug/shared/arm/primitives.cpp +++ b/src/coreclr/debug/shared/arm/primitives.cpp @@ -16,7 +16,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; @@ -24,20 +24,20 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); - if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) + if ((dstFlags & srcFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) CopyContextChunk(&(pDst->Sp), &(pSrc->Sp), &(pDst->Fpscr), DT_CONTEXT_CONTROL); - if ((dstFlags & srcFlags & DT_CONTEXT_INTEGER) == DT_CONTEXT_INTEGER) + if ((dstFlags & srcFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) CopyContextChunk(&(pDst->R0), &(pSrc->R0), &(pDst->Sp), - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); - if ((dstFlags & srcFlags & DT_CONTEXT_FLOATING_POINT) == DT_CONTEXT_FLOATING_POINT) + if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) CopyContextChunk(&(pDst->Fpscr), &(pSrc->Fpscr), &(pDst->Bvr[0]), - DT_CONTEXT_FLOATING_POINT); + CONTEXT_FLOATING_POINT); - if ((dstFlags & srcFlags & DT_CONTEXT_DEBUG_REGISTERS) == - DT_CONTEXT_DEBUG_REGISTERS) - CopyContextChunk(&(pDst->Bvr[0]), &(pSrc->Bvr[0]), &(pDst->Wcr[DT_ARM_MAX_WATCHPOINTS]), - DT_CONTEXT_DEBUG_REGISTERS); + if ((dstFlags & srcFlags & CONTEXT_DEBUG_REGISTERS) == + CONTEXT_DEBUG_REGISTERS) + CopyContextChunk(&(pDst->Bvr[0]), &(pSrc->Bvr[0]), &(pDst->Wcr[ARM_MAX_WATCHPOINTS]), + CONTEXT_DEBUG_REGISTERS); } diff --git a/src/coreclr/debug/shared/arm64/primitives.cpp b/src/coreclr/debug/shared/arm64/primitives.cpp index a381891b02d83d..7216bab9301413 100644 --- a/src/coreclr/debug/shared/arm64/primitives.cpp +++ b/src/coreclr/debug/shared/arm64/primitives.cpp @@ -16,7 +16,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; @@ -24,24 +24,24 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); - if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) + if ((dstFlags & srcFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { CopyContextChunk(&(pDst->Fp), &(pSrc->Fp), &(pDst->V), - DT_CONTEXT_CONTROL); + CONTEXT_CONTROL); CopyContextChunk(&(pDst->Cpsr), &(pSrc->Cpsr), &(pDst->X), - DT_CONTEXT_CONTROL); + CONTEXT_CONTROL); } - if ((dstFlags & srcFlags & DT_CONTEXT_INTEGER) == DT_CONTEXT_INTEGER) + if ((dstFlags & srcFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) CopyContextChunk(&(pDst->X[0]), &(pSrc->X[0]), &(pDst->Fp), - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); - if ((dstFlags & srcFlags & DT_CONTEXT_FLOATING_POINT) == DT_CONTEXT_FLOATING_POINT) + if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) CopyContextChunk(&(pDst->V[0]), &(pSrc->V[0]), &(pDst->Bcr[0]), - DT_CONTEXT_FLOATING_POINT); + CONTEXT_FLOATING_POINT); - if ((dstFlags & srcFlags & DT_CONTEXT_DEBUG_REGISTERS) == - DT_CONTEXT_DEBUG_REGISTERS) + if ((dstFlags & srcFlags & CONTEXT_DEBUG_REGISTERS) == + CONTEXT_DEBUG_REGISTERS) CopyContextChunk(&(pDst->Bcr[0]), &(pSrc->Bcr[0]), &(pDst->Wvr[ARM64_MAX_WATCHPOINTS]), - DT_CONTEXT_DEBUG_REGISTERS); + CONTEXT_DEBUG_REGISTERS); } diff --git a/src/coreclr/debug/shared/i386/primitives.cpp b/src/coreclr/debug/shared/i386/primitives.cpp index 96a5a8f9aea90f..fb17af347d672d 100644 --- a/src/coreclr/debug/shared/i386/primitives.cpp +++ b/src/coreclr/debug/shared/i386/primitives.cpp @@ -16,7 +16,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; @@ -24,32 +24,32 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); - if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) + if ((dstFlags & srcFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) CopyContextChunk(&(pDst->Ebp), &(pSrc->Ebp), pDst->ExtendedRegisters, - DT_CONTEXT_CONTROL); + CONTEXT_CONTROL); - if ((dstFlags & srcFlags & DT_CONTEXT_INTEGER) == DT_CONTEXT_INTEGER) + if ((dstFlags & srcFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) CopyContextChunk(&(pDst->Edi), &(pSrc->Edi), &(pDst->Ebp), - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); - if ((dstFlags & srcFlags & DT_CONTEXT_SEGMENTS) == DT_CONTEXT_SEGMENTS) + if ((dstFlags & srcFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) CopyContextChunk(&(pDst->SegGs), &(pSrc->SegGs), &(pDst->Edi), - DT_CONTEXT_SEGMENTS); + CONTEXT_SEGMENTS); - if ((dstFlags & srcFlags & DT_CONTEXT_FLOATING_POINT) == DT_CONTEXT_FLOATING_POINT) + if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) CopyContextChunk(&(pDst->FloatSave), &(pSrc->FloatSave), (&pDst->FloatSave)+1, - DT_CONTEXT_FLOATING_POINT); + CONTEXT_FLOATING_POINT); - if ((dstFlags & srcFlags & DT_CONTEXT_DEBUG_REGISTERS) == - DT_CONTEXT_DEBUG_REGISTERS) + if ((dstFlags & srcFlags & CONTEXT_DEBUG_REGISTERS) == + CONTEXT_DEBUG_REGISTERS) CopyContextChunk(&(pDst->Dr0), &(pSrc->Dr0), &(pDst->FloatSave), - DT_CONTEXT_DEBUG_REGISTERS); + CONTEXT_DEBUG_REGISTERS); - if ((dstFlags & srcFlags & DT_CONTEXT_EXTENDED_REGISTERS) == - DT_CONTEXT_EXTENDED_REGISTERS) + if ((dstFlags & srcFlags & CONTEXT_EXTENDED_REGISTERS) == + CONTEXT_EXTENDED_REGISTERS) CopyContextChunk(pDst->ExtendedRegisters, pSrc->ExtendedRegisters, &(pDst->ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]), - DT_CONTEXT_EXTENDED_REGISTERS); + CONTEXT_EXTENDED_REGISTERS); } diff --git a/src/coreclr/debug/shared/loongarch64/primitives.cpp b/src/coreclr/debug/shared/loongarch64/primitives.cpp index 11801fea05c106..25d0db5dfad483 100644 --- a/src/coreclr/debug/shared/loongarch64/primitives.cpp +++ b/src/coreclr/debug/shared/loongarch64/primitives.cpp @@ -17,7 +17,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; @@ -25,41 +25,41 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); - if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) + if ((dstFlags & srcFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: RA: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Ra, pSrc->Ra, DT_CONTEXT_CONTROL)); + pDst->Ra, pSrc->Ra, CONTEXT_CONTROL)); pDst->Ra = pSrc->Ra; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: SP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Sp, pSrc->Sp, DT_CONTEXT_CONTROL)); + pDst->Sp, pSrc->Sp, CONTEXT_CONTROL)); pDst->Sp = pSrc->Sp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: FP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Fp, pSrc->Fp, DT_CONTEXT_CONTROL)); + pDst->Fp, pSrc->Fp, CONTEXT_CONTROL)); pDst->Fp = pSrc->Fp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: PC: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Pc, pSrc->Pc, DT_CONTEXT_CONTROL)); + pDst->Pc, pSrc->Pc, CONTEXT_CONTROL)); pDst->Pc = pSrc->Pc; } - if ((dstFlags & srcFlags & DT_CONTEXT_INTEGER) == DT_CONTEXT_INTEGER) + if ((dstFlags & srcFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { CopyContextChunk(&pDst->A0, &pSrc->A0, &pDst->Fp, - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); CopyContextChunk(&pDst->S0, &pSrc->S0, &pDst->Pc, - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); } - if ((dstFlags & srcFlags & DT_CONTEXT_FLOATING_POINT) == DT_CONTEXT_FLOATING_POINT) + if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { CopyContextChunk(&pDst->F[0], &pSrc->F[0], &pDst->F[32*4], - DT_CONTEXT_FLOATING_POINT); + CONTEXT_FLOATING_POINT); pDst->Fcsr = pSrc->Fcsr; pDst->Fcc = pSrc->Fcc; } diff --git a/src/coreclr/debug/shared/riscv64/primitives.cpp b/src/coreclr/debug/shared/riscv64/primitives.cpp index cf306684ada4cd..f0e809e107fcb9 100644 --- a/src/coreclr/debug/shared/riscv64/primitives.cpp +++ b/src/coreclr/debug/shared/riscv64/primitives.cpp @@ -15,7 +15,7 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) +void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) { DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; @@ -23,45 +23,45 @@ void CORDbgCopyThreadContext(DT_CONTEXT* pDst, const DT_CONTEXT* pSrc) "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); - if ((dstFlags & srcFlags & DT_CONTEXT_CONTROL) == DT_CONTEXT_CONTROL) + if ((dstFlags & srcFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) { LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: RA: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Ra, pSrc->Ra, DT_CONTEXT_CONTROL)); + pDst->Ra, pSrc->Ra, CONTEXT_CONTROL)); pDst->Ra = pSrc->Ra; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: SP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Sp, pSrc->Sp, DT_CONTEXT_CONTROL)); + pDst->Sp, pSrc->Sp, CONTEXT_CONTROL)); pDst->Sp = pSrc->Sp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: FP: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Fp, pSrc->Fp, DT_CONTEXT_CONTROL)); + pDst->Fp, pSrc->Fp, CONTEXT_CONTROL)); pDst->Fp = pSrc->Fp; LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: PC: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->Pc, pSrc->Pc, DT_CONTEXT_CONTROL)); + pDst->Pc, pSrc->Pc, CONTEXT_CONTROL)); pDst->Pc = pSrc->Pc; } - if ((dstFlags & srcFlags & DT_CONTEXT_INTEGER) == DT_CONTEXT_INTEGER) + if ((dstFlags & srcFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) { CopyContextChunk(&pDst->Gp, &pSrc->Gp, &pDst->Fp, - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); CopyContextChunk(&pDst->S1, &pSrc->S1, &pDst->Pc, - DT_CONTEXT_INTEGER); + CONTEXT_INTEGER); LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: T0: pDst=0x%lx, pSrc=0x%lx, Flags=0x%x\n", - pDst->R0, pSrc->R0, DT_CONTEXT_INTEGER)); + pDst->R0, pSrc->R0, CONTEXT_INTEGER)); pDst->R0 = pSrc->R0; } - if ((dstFlags & srcFlags & DT_CONTEXT_FLOATING_POINT) == DT_CONTEXT_FLOATING_POINT) + if ((dstFlags & srcFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) { CopyContextChunk(&pDst->F[0], &pSrc->F[0], &pDst->F[32], - DT_CONTEXT_FLOATING_POINT); + CONTEXT_FLOATING_POINT); pDst->Fcsr = pSrc->Fcsr; } } diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index 573efcf95fe99d..56f8208722dd0c 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -75,7 +75,6 @@ typedef int mdMethodDef; // Context types typedef int T_CONTEXT; -typedef int DT_CONTEXT; typedef int EXCEPTION_RECORD; // Metadata interface @@ -129,6 +128,7 @@ typedef struct { void *pList; int nEntries; } DacDbiArrayList_CORDB_ADDRESS; typedef struct { void *pList; int nEntries; } DacDbiArrayList_GUID; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_SEGMENT; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_MEMORY_RANGE; +typedef struct { int arch; int os; } TargetInfo; cpp_quote("#endif") @@ -269,19 +269,19 @@ interface IDacDbiInterface : IUnknown // Context and Stack Walking HRESULT GetManagedStoppedContext([in] VMPTR_Thread vmThread, [out] VMPTR_CONTEXT * pRetVal); - HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in, out] DT_CONTEXT * pInternalContextBuffer, [out] StackWalkHandle * ppSFIHandle); + HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in, out] BYTE * pInternalContextBuffer, [out] StackWalkHandle * ppSFIHandle); HRESULT DeleteStackWalk([in] StackWalkHandle ppSFIHandle); - HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [out] DT_CONTEXT * pContext); - HRESULT SetStackWalkCurrentContext([in] VMPTR_Thread vmThread, [in] StackWalkHandle pSFIHandle, [in] CorDebugSetContextFlag flag, [in] DT_CONTEXT * pContext); + HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [out] BYTE * pContext); + HRESULT SetStackWalkCurrentContext([in] VMPTR_Thread vmThread, [in] StackWalkHandle pSFIHandle, [in] CorDebugSetContextFlag flag, [in] BYTE * pContext); HRESULT UnwindStackWalkFrame([in] StackWalkHandle pSFIHandle, [out] BOOL * pResult); - HRESULT CheckContext([in] VMPTR_Thread vmThread, [in] const DT_CONTEXT * pContext); + HRESULT CheckContext([in] VMPTR_Thread vmThread, [in] const BYTE * pContext); HRESULT GetStackWalkCurrentFrameInfo([in] StackWalkHandle pSFIHandle, [out] struct Debugger_STRData * pFrameData, [out] FrameType * pRetVal); HRESULT GetCountOfInternalFrames([in] VMPTR_Thread vmThread, [out] ULONG32 * pRetVal); HRESULT EnumerateInternalFrames([in] VMPTR_Thread vmThread, [in] FP_INTERNAL_FRAME_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); HRESULT GetStackParameterSize([in] CORDB_ADDRESS controlPC, [out] ULONG32 * pRetVal); HRESULT GetFramePointer([in] StackWalkHandle pSFIHandle, [out] FramePointer * pRetVal); - HRESULT IsLeafFrame([in] VMPTR_Thread vmThread, [in] const DT_CONTEXT * pContext, [out] BOOL * pResult); - HRESULT GetContext([in] VMPTR_Thread vmThread, [out] DT_CONTEXT * pContextBuffer); + HRESULT IsLeafFrame([in] VMPTR_Thread vmThread, [in] const BYTE * pContext, [out] BOOL * pResult); + HRESULT GetContext([in] VMPTR_Thread vmThread, [out] BYTE * pContextBuffer); // Method HRESULT IsDiagnosticsHiddenOrLCGMethod([in] VMPTR_MethodDesc vmMethodDesc, [out] DynamicMethodType * pRetVal); @@ -437,4 +437,54 @@ interface IDacDbiInterface : IUnknown // Generic Arg Token HRESULT GetGenericArgTokenIndex([in] VMPTR_MethodDesc vmMethod, [out] UINT32 * pTokenIndex); + + // Context size queries + HRESULT GetTargetContextSize([in] int flags, [out] ULONG32 * pSize); + + // CONTEXT register accessors. + HRESULT WriteRegistersToContext([in, out] BYTE * ctxBuf, [in] ULONG32 cb, [in] const int * regs, [in] ULONG32 nRegs, [in] const TADDR * values); + HRESULT ReadRegistersFromContext([in] BYTE * ctxBuf, [in] ULONG32 cb, [in] const int * regs, [in] ULONG32 nRegs, [out] TADDR * pValues); + + // Returns the full availability bitmask for the target architecture in + // CorDebugRegister bit positions, including both integer (GPR) and + // floating-point / SIMD registers. + HRESULT GetAvailableRegistersMask( + [in] BOOL fActive, + [in] BOOL fQuickUnwind, + [in] ULONG32 regCount, + [out, size_is(regCount)] BYTE pAvailable[]); + + // Translates a JIT ICorDebugInfo::RegNum to a CorDebugRegister value + HRESULT ConvertJitRegNumToCorDebugRegister([in] ULONG32 jitRegNum, [out] int * pReg); + + // Decodes the floating-point / SIMD register area of a DBI-side context buffer + // Out params: + // values[] - populated doubles + // pValuesCount - number of valid slots in values[] + // pFirstFloatReg - CorDebugRegister value of values[0] (logical + // numbering); -1 if the target arch exposes no floats + // via CordbRegisterSet (e.g. ARM today) + // pFloatStackTop - x87 top-of-stack depth on x86 (so DBI can preserve + // its stack-relative dispatch); 0 on every other arch + HRESULT ReadFloatRegistersFromContext( + [in] BYTE * ctxBuf, + [in] ULONG32 cb, + [in] ULONG32 regCount, + [out] DOUBLE values[32], + [out] ULONG32 * pValuesCount, + [out] int * pFirstFloatReg, + [out] ULONG32 * pFloatStackTop); + + // Returns the target's processor architecture and OS family. + HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); + + HRESULT ContextHasExtendedRegisters([in] BYTE * ctxBuf, [in] ULONG32 cb, [out] BOOL * pResult); + + HRESULT CompareControlRegisters([in] const BYTE * ctxBuf1, [in] ULONG32 cb1, [in] const BYTE * ctxBuf2, [in] ULONG32 cb2, [out] BOOL * pResult); + + // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both + // contexts. flags != 0 first stamps dstCtxBuf's ContextFlags so the copy + // pulls exactly the requested chunks from the source; flags == 0 preserves + // the destination's existing ContextFlags. + HRESULT CopyContext([in, out] BYTE * dstCtxBuf, [in] ULONG32 cbDst, [in] const BYTE * srcCtxBuf, [in] ULONG32 cbSrc, [in] ULONG32 flags); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs index 4603d6f1f1f2ec..1ed47ffac687fb 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs @@ -197,6 +197,50 @@ public bool TryReadRegister(int number, out TargetNUInt value) } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "cs"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "ss"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "eflags"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "rsp"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rax"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rcx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rdx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rbx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rbp"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rsi"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "rdi"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r8"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r9"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r10"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r11"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r12"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r13"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r14"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r15"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "ds"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "es"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "fs"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "gs"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + // Matches native CORDbgCopyThreadContext's CONTROL chunk [Rip, Xmm0), which + // copies Rip together with the legacy x87 save area that has no named field here. + ((uint)ContextFlagsValues.CONTEXT_CONTROL, + (int)Marshal.OffsetOf(nameof(Rip)), (int)Marshal.OffsetOf(nameof(Xmm))), + ((uint)ContextFlagsValues.CONTEXT_DEBUG_REGISTERS, + (int)Marshal.OffsetOf(nameof(Dr0)), (int)Marshal.OffsetOf(nameof(Rax))), + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(MxCsr)), (int)Marshal.OffsetOf(nameof(Cs))), + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(Xmm)), (int)Marshal.OffsetOf(nameof(Xmm)) + (16 * 2 * sizeof(ulong))), + ]; + [FieldOffset(0x0)] public ulong P1Home; @@ -218,12 +262,13 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0x30)] public uint ContextFlags; + [Register(RegisterType.FloatingPoint)] [FieldOffset(0x34)] public uint MxCsr; #region Segment registers - [Register(RegisterType.Segments)] + [Register(RegisterType.Control)] [FieldOffset(0x38)] public ushort Cs; @@ -243,13 +288,13 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0x40)] public ushort Gs; - [Register(RegisterType.Segments)] + [Register(RegisterType.Control)] [FieldOffset(0x42)] public ushort Ss; #endregion - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0x44)] public int EFlags; @@ -303,7 +348,7 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0x98)] public ulong Rsp; - [Register(RegisterType.Control | RegisterType.FramePointer)] + [Register(RegisterType.General | RegisterType.FramePointer)] [FieldOffset(0xa0)] public ulong Rbp; @@ -355,33 +400,24 @@ public bool TryReadRegister(int number, out TargetNUInt value) #region Floating point registers - // [Register(RegisterType.FloatPoint)] - // [FieldOffset(0x100)] - // public XmmSaveArea FltSave; - - // [Register(RegisterType.FloatPoint)] - // [FieldOffset(0x300)] - // public VectorRegisterArea VectorRegisters; + [Register(RegisterType.FloatingPoint)] + [FieldOffset(0x1a0)] + public unsafe fixed ulong Xmm[16 * 2]; #endregion - [Register(RegisterType.Debug)] [FieldOffset(0x4a8)] public ulong DebugControl; - [Register(RegisterType.Debug)] [FieldOffset(0x4b0)] public ulong LastBranchToRip; - [Register(RegisterType.Debug)] [FieldOffset(0x4b8)] public ulong LastBranchFromRip; - [Register(RegisterType.Debug)] [FieldOffset(0x4c0)] public ulong LastExceptionToRip; - [Register(RegisterType.Debug)] [FieldOffset(0x4c8)] public ulong LastExceptionFromRip; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs index 8016c0ac1765a2..df4effd35cdf73 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs @@ -238,6 +238,55 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "fp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "lr"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "sp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "pc"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "cpsr"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x8"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x9"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x10"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x11"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x12"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x13"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x14"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x15"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x16"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x17"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x18"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x19"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x20"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x21"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x22"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x23"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x24"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x25"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x26"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x27"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x28"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(V)), (int)Marshal.OffsetOf(nameof(Bcr))), + ((uint)ContextFlagsValues.CONTEXT_DEBUG_REGISTERS, + (int)Marshal.OffsetOf(nameof(Bcr)), (int)Marshal.OffsetOf(nameof(Wvr)) + (ARM64_MAX_WATCHPOINTS * sizeof(ulong))), + ]; + // Control flags [FieldOffset(0x0)] @@ -245,7 +294,7 @@ public bool TryReadRegister(int number, out TargetNUInt value) #region General registers - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0x4)] public uint Cpsr; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs index cde8ee0c0ce6f4..6fbe44d2981b53 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs @@ -162,6 +162,38 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "sp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "lr"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "pc"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "cpsr"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r8"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r9"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r10"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r11"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "r12"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(Fpscr)), (int)Marshal.OffsetOf(nameof(Bvr))), + ((uint)ContextFlagsValues.CONTEXT_DEBUG_REGISTERS, + (int)Marshal.OffsetOf(nameof(Bvr)), (int)Marshal.OffsetOf(nameof(Wcr)) + sizeof(uint)), + ]; + // Control flags [FieldOffset(0x0)] @@ -237,7 +269,7 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0x40)] public uint Pc; - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0x44)] public uint Cpsr; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs index 01457bab25b56a..133f4e545385ef 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs @@ -12,6 +12,8 @@ public sealed class ContextHolder : IPlatformAgnosticContext, IEquatable Context.Size; + public uint SizeWithoutExtendedRegisters => Context.SizeWithoutExtendedRegisters; + public uint ExtendedRegistersFlag => Context.ExtendedRegistersFlag; public uint ContextControlFlags => Context.ContextControlFlags; public uint FullContextFlags => Context.FullContextFlags; public uint AllContextFlags => Context.AllContextFlags; @@ -59,6 +61,9 @@ public unsafe byte[] GetBytes() public bool TrySetRegister(int number, TargetNUInt value) => Context.TrySetRegister(number, value); public bool TryReadRegister(int number, out TargetNUInt value) => Context.TryReadRegister(number, out value); + public (uint Flag, string Name)[] GetScalarRegisters() => Context.GetScalarRegisters(); + public (uint Flag, int Start, int End)[] GetWideSpans() => Context.GetWideSpans(); + public bool Equals(ContextHolder? other) { if (GetType() != other?.GetType()) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs index 3e45d381ecbc0d..778c6ddf7dfc67 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs @@ -8,6 +8,8 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; public interface IPlatformAgnosticContext { public abstract uint Size { get; } + public abstract uint SizeWithoutExtendedRegisters { get; } + public abstract uint ExtendedRegistersFlag { get; } public abstract uint ContextControlFlags { get; } public abstract uint FullContextFlags { get; } public abstract uint AllContextFlags { get; } @@ -30,6 +32,13 @@ public interface IPlatformAgnosticContext public abstract bool TrySetRegister(int number, TargetNUInt value); public abstract bool TryReadRegister(int number, out TargetNUInt value); + // The register copy set derived from the context's [Register]-tagged fields, used to + // implement CONTEXT-flag-gated copies. Integer/control/segment registers are named and + // copied through the register accessors; floating-point/debug/extended state is copied + // as a raw [Start, End) byte span. + public abstract (uint Flag, string Name)[] GetScalarRegisters(); + public abstract (uint Flag, int Start, int End)[] GetWideSpans(); + public abstract void Unwind(Target target); /// diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs index 2e71424e3d2191..22e487c288ba6f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs @@ -6,6 +6,11 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; public interface IPlatformContext { uint Size { get; } + + uint SizeWithoutExtendedRegisters => Size; + + uint ExtendedRegistersFlag => 0; + uint ContextControlFlags { get; } uint FullContextFlags { get; } uint AllContextFlags { get; } @@ -32,4 +37,6 @@ public interface IPlatformContext bool TrySetRegister(int number, TargetNUInt value); bool TryReadRegister(int number, out TargetNUInt value); + (uint Flag, string Name)[] GetScalarRegisters(); + (uint Flag, int Start, int End)[] GetWideSpans(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs index bf0081fa0033b7..91d3cae1d28d2d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs @@ -34,7 +34,7 @@ public enum ContextFlagsValues : uint CONTEXT_AREA_MASK = 0xFFFF, } - public readonly uint Size => 0x320; + public readonly uint Size => 0x520; public readonly uint ContextControlFlags => (uint)ContextFlagsValues.CONTEXT_CONTROL; @@ -105,7 +105,7 @@ public bool TrySetRegister(string name, TargetNUInt value) if (name.Equals("s7", StringComparison.OrdinalIgnoreCase)) { S7 = value.Value; return true; } if (name.Equals("s8", StringComparison.OrdinalIgnoreCase)) { S8 = value.Value; return true; } if (name.Equals("pc", StringComparison.OrdinalIgnoreCase)) { Pc = value.Value; return true; } - if (name.Equals("fcc", StringComparison.OrdinalIgnoreCase)) { Fcc = (uint)value.Value; return true; } + if (name.Equals("fcc", StringComparison.OrdinalIgnoreCase)) { Fcc = value.Value; return true; } if (name.Equals("fcsr", StringComparison.OrdinalIgnoreCase)) { Fcsr = (uint)value.Value; return true; } return false; } @@ -231,6 +231,50 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "ra"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "sp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "fp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "pc"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t8"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "x0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s8"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(F)), (int)Marshal.OffsetOf(nameof(Fcsr)) + sizeof(uint)), + ]; + // Control flags [FieldOffset(0x0)] @@ -238,19 +282,17 @@ public bool TryReadRegister(int number, out TargetNUInt value) #region General registers - [Register(RegisterType.General)] [FieldOffset(0x8)] public ulong R0; - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0x10)] public ulong Ra; - [Register(RegisterType.General)] [FieldOffset(0x18)] public ulong Tp; - [Register(RegisterType.General | RegisterType.StackPointer)] + [Register(RegisterType.Control | RegisterType.StackPointer)] [FieldOffset(0x20)] public ulong Sp; @@ -326,7 +368,7 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0xb0)] public ulong X0; - [Register(RegisterType.General | RegisterType.FramePointer)] + [Register(RegisterType.Control | RegisterType.FramePointer)] [FieldOffset(0xb8)] public ulong Fp; @@ -380,14 +422,14 @@ public bool TryReadRegister(int number, out TargetNUInt value) [Register(RegisterType.FloatingPoint)] [FieldOffset(0x110)] - public unsafe fixed ulong F[32]; + public unsafe fixed ulong F[4 * 32]; [Register(RegisterType.FloatingPoint)] - [FieldOffset(0x210)] - public uint Fcc; + [FieldOffset(0x510)] + public ulong Fcc; [Register(RegisterType.FloatingPoint)] - [FieldOffset(0x214)] + [FieldOffset(0x518)] public uint Fcsr; #endregion diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs index f829c897e1c5c2..f329828a69798c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs @@ -228,6 +228,51 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "ra"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "sp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "fp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "pc"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "gp"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "tp"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a0"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a1"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "a7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s2"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s6"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s7"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s8"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s9"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s10"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "s11"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t3"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t4"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t5"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "t6"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(F)), (int)Marshal.OffsetOf(nameof(Fcsr)) + sizeof(uint)), + ]; + // Control flags [FieldOffset(0x0)] @@ -235,11 +280,11 @@ public bool TryReadRegister(int number, out TargetNUInt value) #region General registers - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0x8)] public ulong Ra; - [Register(RegisterType.General | RegisterType.StackPointer)] + [Register(RegisterType.Control | RegisterType.StackPointer)] [FieldOffset(0x10)] public ulong Sp; @@ -263,7 +308,7 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0x38)] public ulong T2; - [Register(RegisterType.General | RegisterType.FramePointer)] + [Register(RegisterType.Control | RegisterType.FramePointer)] [FieldOffset(0x40)] public ulong Fp; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RegisterAttribute.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RegisterAttribute.cs index 1ae0c32bf7ffa4..b37c30f09736b7 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RegisterAttribute.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RegisterAttribute.cs @@ -13,6 +13,7 @@ public enum RegisterType : byte Segments = 0x03, FloatingPoint = 0x04, Debug = 0x05, + Extended = 0x06, TypeMask = 0x0f, ProgramCounter = 0x10, diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs index 08fac2a6f5b3ea..840c582403b83b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs @@ -39,6 +39,10 @@ public enum ContextFlagsValues : uint public readonly uint Size => 0x2cc; + public readonly uint SizeWithoutExtendedRegisters => 0xcc; + + public readonly uint ExtendedRegistersFlag => (uint)ContextFlagsValues.CONTEXT_EXTENDED_REGISTERS; + public readonly uint ContextControlFlags => (uint)ContextFlagsValues.CONTEXT_CONTROL; public readonly uint FullContextFlags => (uint)ContextFlagsValues.CONTEXT_FULL; @@ -177,6 +181,39 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; + + private static readonly (uint Flag, string Name)[] s_scalarRegisters = + [ + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "ebp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "eip"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "cs"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "eflags"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "esp"), + ((uint)ContextFlagsValues.CONTEXT_CONTROL, "ss"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "edi"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "esi"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "ebx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "edx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "ecx"), + ((uint)ContextFlagsValues.CONTEXT_INTEGER, "eax"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "gs"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "fs"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "es"), + ((uint)ContextFlagsValues.CONTEXT_SEGMENTS, "ds"), + ]; + + private static readonly (uint Flag, int Start, int End)[] s_wideSpans = + [ + ((uint)ContextFlagsValues.CONTEXT_DEBUG_REGISTERS, + (int)Marshal.OffsetOf(nameof(Dr0)), (int)Marshal.OffsetOf(nameof(ControlWord))), + ((uint)ContextFlagsValues.CONTEXT_FLOATING_POINT, + (int)Marshal.OffsetOf(nameof(ControlWord)), (int)Marshal.OffsetOf(nameof(Gs))), + ((uint)ContextFlagsValues.CONTEXT_EXTENDED_REGISTERS, + (int)Marshal.OffsetOf(nameof(ExtendedRegisters)), (int)Marshal.OffsetOf(nameof(ExtendedRegisters)) + 512), + ]; + // Control flags [FieldOffset(0x0)] @@ -336,11 +373,11 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0xb8)] public uint Eip; - [Register(RegisterType.Segments)] + [Register(RegisterType.Control)] [FieldOffset(0xbc)] public uint Cs; - [Register(RegisterType.General)] + [Register(RegisterType.Control)] [FieldOffset(0xc0)] public uint EFlags; @@ -348,12 +385,13 @@ public bool TryReadRegister(int number, out TargetNUInt value) [FieldOffset(0xc4)] public uint Esp; - [Register(RegisterType.Segments)] + [Register(RegisterType.Control)] [FieldOffset(0xc8)] public uint Ss; #endregion + [Register(RegisterType.Extended)] [FieldOffset(0xcc)] public unsafe fixed byte ExtendedRegisters[512]; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 49be9cb115d8b1..c93d6be9fc517b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -5584,6 +5584,793 @@ public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) return hr; } + public int GetTargetContextSize(ContextSizeFlags flags, uint* pSize) + { + int hr = HResults.S_OK; + try + { + if (pSize is null) + throw new ArgumentNullException(nameof(pSize)); + + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + *pSize = flags switch + { + ContextSizeFlags.Base => ctx.SizeWithoutExtendedRegisters, + ContextSizeFlags.ExtendedRegisters => ctx.Size, + _ => throw new ArgumentException($"Invalid context size flags {(int)flags}", nameof(flags)), + }; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + uint sizeLocal; + int hrLocal = _legacy.GetTargetContextSize(flags, &sizeLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pSize == sizeLocal, $"cDAC: {*pSize}, DAC: {sizeLocal}"); + } +#endif + return hr; + } + + public int GetTargetInfo(TargetInfo* pTargetInfo) + { + int hr = HResults.S_OK; + try + { + if (pTargetInfo is null) + throw new ArgumentNullException(nameof(pTargetInfo)); + + Contracts.IRuntimeInfo runtimeInfo = _target.Contracts.RuntimeInfo; + + pTargetInfo->Arch = runtimeInfo.GetTargetArchitecture() switch + { + Contracts.RuntimeInfoArchitecture.X86 => TargetArchitecture.X86, + Contracts.RuntimeInfoArchitecture.X64 => TargetArchitecture.AMD64, + Contracts.RuntimeInfoArchitecture.Arm => TargetArchitecture.Arm, + Contracts.RuntimeInfoArchitecture.Arm64 => TargetArchitecture.Arm64, + Contracts.RuntimeInfoArchitecture.LoongArch64 => TargetArchitecture.LoongArch64, + Contracts.RuntimeInfoArchitecture.RiscV64 => TargetArchitecture.RiscV64, + Contracts.RuntimeInfoArchitecture.Wasm => TargetArchitecture.Wasm, + _ => TargetArchitecture.Unknown, + }; + + pTargetInfo->OS = runtimeInfo.GetTargetOperatingSystem() switch + { + Contracts.RuntimeInfoOperatingSystem.Windows => TargetOperatingSystem.Windows, + Contracts.RuntimeInfoOperatingSystem.Unix => TargetOperatingSystem.Unix, + Contracts.RuntimeInfoOperatingSystem.Apple => TargetOperatingSystem.Unix, + _ => TargetOperatingSystem.Unknown, + }; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + TargetInfo targetInfoLocal; + int hrLocal = _legacy.GetTargetInfo(&targetInfoLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pTargetInfo->Arch == targetInfoLocal.Arch, $"cDAC: {pTargetInfo->Arch}, DAC: {targetInfoLocal.Arch}"); + Debug.Assert(pTargetInfo->OS == targetInfoLocal.OS, $"cDAC: {pTargetInfo->OS}, DAC: {targetInfoLocal.OS}"); + } + } +#endif + return hr; + } + + public int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pResult) + { + int hr = HResults.S_OK; + try + { + if (ctxBuf is null) + throw new ArgumentNullException(nameof(ctxBuf)); + if (pResult is null) + throw new ArgumentNullException(nameof(pResult)); + + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + if (cb < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(cb)); + + if (ctx.ExtendedRegistersFlag == 0) + { + *pResult = Interop.BOOL.FALSE; + } + else + { + ctx.FillFromBuffer(new Span(ctxBuf, (int)cb)); + bool hasExtended = (ctx.RawContextFlags & ctx.ExtendedRegistersFlag) == ctx.ExtendedRegistersFlag; + *pResult = hasExtended ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + Interop.BOOL resultLocal; + int hrLocal = _legacy.ContextHasExtendedRegisters(ctxBuf, cb, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint cb2, Interop.BOOL* pResult) + { + int hr = HResults.S_OK; + try + { + if (ctxBuf1 is null || ctxBuf2 is null) + throw new ArgumentNullException(ctxBuf1 is null ? nameof(ctxBuf1) : nameof(ctxBuf2)); + if (pResult is null) + throw new ArgumentNullException(nameof(pResult)); + + IPlatformAgnosticContext ctx1 = IPlatformAgnosticContext.GetContextForPlatform(_target); + IPlatformAgnosticContext ctx2 = IPlatformAgnosticContext.GetContextForPlatform(_target); + if (cb1 < ctx1.Size || cb2 < ctx2.Size) + throw new ArgumentException("Context buffer too small"); + + ctx1.FillFromBuffer(new Span(ctxBuf1, (int)cb1)); + ctx2.FillFromBuffer(new Span(ctxBuf2, (int)cb2)); + + *pResult = ctx1.StackPointer == ctx2.StackPointer + && ctx1.InstructionPointer == ctx2.InstructionPointer + ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + Interop.BOOL resultLocal; + int hrLocal = _legacy.CompareControlRegisters(ctxBuf1, cb1, ctxBuf2, cb2, &resultLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); + } +#endif + return hr; + } + + public int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, uint flags) + { + int hr = HResults.S_OK; +#if DEBUG + // Capture the untouched destination image so the legacy cross-check below can + // replay the same copy from an identical starting state. + byte[]? originalDst = (dstCtxBuf is not null && cbDst > 0) ? new ReadOnlySpan(dstCtxBuf, (int)cbDst).ToArray() : null; +#endif + try + { + if (dstCtxBuf is null || srcCtxBuf is null) + throw new ArgumentNullException(dstCtxBuf is null ? nameof(dstCtxBuf) : nameof(srcCtxBuf)); + + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + if (cbDst < ctx.Size || cbSrc < ctx.Size) + throw new ArgumentException("Context buffer too small"); + + Span dst = new Span(dstCtxBuf, (int)cbDst); + Span src = new Span(srcCtxBuf, (int)cbSrc); + + IPlatformAgnosticContext dstCtx = IPlatformAgnosticContext.GetContextForPlatform(_target); + dstCtx.FillFromBuffer(dst); + IPlatformAgnosticContext srcCtx = IPlatformAgnosticContext.GetContextForPlatform(_target); + srcCtx.FillFromBuffer(src); + + // flags != 0 stamps the destination's ContextFlags so the copy pulls exactly the + // requested groups from the source; flags == 0 preserves the destination's flags. + if (flags != 0) + dstCtx.RawContextFlags = flags; + + uint dstFlags = dstCtx.RawContextFlags; + uint srcFlags = srcCtx.RawContextFlags; + + // Integer/control/segment registers copy by name; wide floating-point/debug/ + // extended state copies as a raw byte span. A group is copied only when its flag + // is set in both the source and destination contexts. + foreach ((uint flag, string name) in dstCtx.GetScalarRegisters()) + { + if ((dstFlags & srcFlags & flag) == flag && srcCtx.TryReadRegister(name, out TargetNUInt value)) + dstCtx.TrySetRegister(name, value); + } + + dstCtx.GetBytes().AsSpan(0, (int)ctx.Size).CopyTo(dst); + + foreach ((uint flag, int start, int end) in dstCtx.GetWideSpans()) + { + if ((dstFlags & srcFlags & flag) == flag) + src.Slice(start, end - start).CopyTo(dst.Slice(start)); + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null && originalDst is not null) + { + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + byte[] scratchDst = (byte[])originalDst.Clone(); + byte[] scratchSrc = new ReadOnlySpan(srcCtxBuf, (int)cbSrc).ToArray(); + fixed (byte* pScratchDst = scratchDst) + fixed (byte* pScratchSrc = scratchSrc) + { + int hrLocal = _legacy.CopyContext(pScratchDst, cbDst, pScratchSrc, cbSrc, flags); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(new ReadOnlySpan(dstCtxBuf, (int)ctx.Size).SequenceEqual(scratchDst.AsSpan(0, (int)ctx.Size)), + "cDAC and DAC produced different copied contexts"); + } + } +#endif + return hr; + } + + public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* values) + { + int hr = HResults.S_OK; + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + try + { + if (ctxBuf is null) + throw new ArgumentNullException(nameof(ctxBuf)); + if (nRegs > 0 && (regs is null || values is null)) + throw new ArgumentNullException(regs is null ? nameof(regs) : nameof(values)); + if (cb < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(cb)); + + Span bufSpan = new Span(ctxBuf, (int)cb); + ctx.FillFromBuffer(bufSpan); + + RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + for (uint i = 0; i < nRegs; i++) + { + // Registers with no CONTEXT slot (float / SIMD) are skipped. + string? name = MapToCdacName(arch, regs[i]); + if (name is not null) + ctx.TrySetRegister(name, new TargetNUInt(values[i])); + } + + ctx.GetBytes().AsSpan(0, (int)ctx.Size).CopyTo(bufSpan); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + byte[] scratch = new byte[ctx.Size]; + new ReadOnlySpan(ctxBuf, (int)ctx.Size).CopyTo(scratch); + fixed (byte* pScratch = scratch) + { + int hrLocal = _legacy.WriteRegistersToContext(pScratch, cb, regs, nRegs, values); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(new ReadOnlySpan(ctxBuf, (int)ctx.Size).SequenceEqual(scratch), + "cDAC and DAC produced different mutated contexts"); + } + } +#endif + return hr; + } + + public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* pValues) + { + int hr = HResults.S_OK; + try + { + if (ctxBuf is null) + throw new ArgumentNullException(nameof(ctxBuf)); + if (nRegs > 0 && (regs is null || pValues is null)) + throw new ArgumentNullException(regs is null ? nameof(regs) : nameof(pValues)); + + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + if (cb < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(cb)); + + ctx.FillFromBuffer(new Span(ctxBuf, (int)cb)); + + RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + for (uint i = 0; i < nRegs; i++) + { + // Registers with no CONTEXT slot (float / SIMD) read as zero. + string? name = MapToCdacName(arch, regs[i]); + pValues[i] = (name is not null && ctx.TryReadRegister(name, out TargetNUInt v)) ? v.Value : 0; + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong[] valuesLocal = new ulong[nRegs]; + int hrLocal; + fixed (ulong* pValuesLocal = valuesLocal) + hrLocal = _legacy.ReadRegistersFromContext(ctxBuf, cb, regs, nRegs, pValuesLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + for (uint i = 0; i < nRegs; i++) + Debug.Assert(pValues[i] == valuesLocal[i], $"reg[{i}] cDAC: {pValues[i]:x}, DAC: {valuesLocal[i]:x}"); + } + } +#endif + return hr; + } + + public int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable) + { + int hr = HResults.S_OK; + try + { + if (pAvailable is null) + throw new ArgumentNullException(nameof(pAvailable)); + if (regCount == 0) + throw new ArgumentException("regCount must be non-zero", nameof(regCount)); + + new Span(pAvailable, (int)regCount).Clear(); + + RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + WriteAvailableRegistersMask(arch, fActive != Interop.BOOL.FALSE, fQuickUnwind != Interop.BOOL.FALSE, + pAvailable, regCount); + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null && pAvailable is not null && regCount > 0) + { + byte[] localBuf = new byte[regCount]; + int hrLocal; + fixed (byte* pLocal = localBuf) + hrLocal = _legacy.GetAvailableRegistersMask(fActive, fQuickUnwind, regCount, pLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(new ReadOnlySpan(pAvailable, (int)regCount).SequenceEqual(localBuf), + "cDAC and DAC produced different availability masks"); + } +#endif + return hr; + } + + public int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* pReg) + { + int hr = HResults.S_OK; + try + { + if (pReg is null) + throw new ArgumentNullException(nameof(pReg)); + + RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + CorDebugRegister? reg = MapJitRegNumToCorDebugRegister(arch, jitRegNum); + if (reg is null) + throw new ArgumentException($"Unsupported JIT register {jitRegNum}", nameof(jitRegNum)); + + *pReg = reg.Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + if (pReg is not null) *pReg = default; + } +#if DEBUG + if (_legacy is not null) + { + CorDebugRegister regLocal; + int hrLocal = _legacy.ConvertJitRegNumToCorDebugRegister(jitRegNum, ®Local); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pReg == regLocal, $"cDAC: {(int)(*pReg)}, DAC: {(int)regLocal}"); + } +#endif + return hr; + } + + public int ReadFloatRegistersFromContext(byte* ctxBuf, uint cb, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop) + { + int hr = HResults.S_OK; + try + { + if (ctxBuf is null || values is null || pValuesCount is null || + pFirstFloatReg is null || pFloatStackTop is null || maxValues == 0) + { + throw new ArgumentException("Invalid argument to ReadFloatRegistersFromContext"); + } + + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); + if (cb < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(cb)); + + ReadOnlySpan buf = new ReadOnlySpan(ctxBuf, (int)cb); + + *pValuesCount = 0; + *pFirstFloatReg = -1; + *pFloatStackTop = 0; + new Span(values, (int)maxValues).Clear(); + + RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + + // Read a little-endian 64-bit reinterpret at the given offset, or 0 if the + // requested slot lies beyond the buffer. + static double ReadSlot64(ReadOnlySpan buf, int offset) + { + if (offset < 0 || offset + sizeof(ulong) > buf.Length) + return 0.0; + return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(buf.Slice(offset))); + } + + switch (arch) + { + case RuntimeInfoArchitecture.X86: + { + // FloatSave.StatusWord is at 0x20; the 80-bit ST register area starts at 0x38. + const int StatusWordOffset = 0x20; + const int RegisterAreaOffset = 0x38; + uint statusWord = BinaryPrimitives.ReadUInt32LittleEndian(buf.Slice(StatusWordOffset)); + uint rawTop = (statusWord >> 11) & 0x7; + uint floatStackTop = 7 - rawTop; + *pFloatStackTop = floatStackTop; + *pFirstFloatReg = (int)CorDebugRegister.REGISTER_X86_FPSTACK_0; + + uint count = floatStackTop + 1; + if (count > maxValues) + count = maxValues; + *pValuesCount = count; + + for (uint i = 0; i < count; i++) + { + uint physIdx = (rawTop + i) & 0x7; + int slot = RegisterAreaOffset + (int)physIdx * 10; + values[i] = (slot + 10 <= buf.Length) ? FloatConversion.X87ExtendedToDouble(buf.Slice(slot, 10)) : 0.0; + } + break; + } + case RuntimeInfoArchitecture.X64: + { + // Xmm0 lives in the FltSave area at offset 0x1a0; 16 registers, 16-byte stride. + const int Xmm0Offset = 0x1a0; + uint count = 16; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = (int)CorDebugRegister.REGISTER_AMD64_XMM0; + for (uint i = 0; i < count; i++) + values[i] = ReadSlot64(buf, Xmm0Offset + (int)i * 16); + break; + } + case RuntimeInfoArchitecture.Arm64: + { + const int V0Offset = 0x110; + uint count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = (int)CorDebugRegister.REGISTER_ARM64_V0; + for (uint i = 0; i < count; i++) + values[i] = ReadSlot64(buf, V0Offset + (int)i * 16); + break; + } + case RuntimeInfoArchitecture.Arm: + { + // ARM D registers overlay the Q register area at offset 0x50; 8-byte stride. + const int D0Offset = 0x50; + uint count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + for (uint i = 0; i < count; i++) + values[i] = ReadSlot64(buf, D0Offset + (int)i * 8); + break; + } + case RuntimeInfoArchitecture.LoongArch64: + { + const int F0Offset = 0x110; + uint count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = (int)CorDebugRegister.REGISTER_LOONGARCH64_F0; + for (uint i = 0; i < count; i++) + values[i] = ReadSlot64(buf, F0Offset + (int)i * 32); + break; + } + case RuntimeInfoArchitecture.RiscV64: + { + const int F0Offset = 0x110; + uint count = 32; + if (count > maxValues) count = maxValues; + *pValuesCount = count; + *pFirstFloatReg = (int)CorDebugRegister.REGISTER_RISCV64_F0; + for (uint i = 0; i < count; i++) + values[i] = ReadSlot64(buf, F0Offset + (int)i * 8); + break; + } + default: + throw new NotImplementedException($"ReadFloatRegistersFromContext: unsupported architecture {arch}"); + } + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null && pValuesCount is not null && pFirstFloatReg is not null && + pFloatStackTop is not null && values is not null && maxValues > 0) + { + double[] valuesLocal = new double[maxValues]; + uint valuesCountLocal; + int firstFloatRegLocal; + uint floatStackTopLocal; + int hrLocal; + fixed (double* pValuesLocal = valuesLocal) + hrLocal = _legacy.ReadFloatRegistersFromContext(ctxBuf, cb, maxValues, pValuesLocal, + &valuesCountLocal, &firstFloatRegLocal, &floatStackTopLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(*pValuesCount == valuesCountLocal, $"count cDAC: {*pValuesCount}, DAC: {valuesCountLocal}"); + Debug.Assert(*pFirstFloatReg == firstFloatRegLocal, $"firstFloatReg cDAC: {*pFirstFloatReg}, DAC: {firstFloatRegLocal}"); + Debug.Assert(*pFloatStackTop == floatStackTopLocal, $"floatStackTop cDAC: {*pFloatStackTop}, DAC: {floatStackTopLocal}"); + for (uint i = 0; i < *pValuesCount && i < maxValues; i++) + Debug.Assert(BitConverter.DoubleToInt64Bits(values[i]) == BitConverter.DoubleToInt64Bits(valuesLocal[i]), + $"float[{i}] cDAC: {values[i]}, DAC: {valuesLocal[i]}"); + } + } +#endif + return hr; + } + + private static void WriteAvailableRegistersMask(RuntimeInfoArchitecture arch, bool fActive, bool fQuickUnwind, + byte* pAvailable, uint regCount) + { + void SetBit(int reg) + { + uint byteIdx = (uint)reg / 8; + if (byteIdx < regCount) + pAvailable[byteIdx] |= (byte)(1 << (reg % 8)); + } + void SetRange(CorDebugRegister first, CorDebugRegister last) + { + for (int r = (int)first; r <= (int)last; r++) + SetBit(r); + } + switch (arch) + { + case RuntimeInfoArchitecture.X86: + SetBit((int)CorDebugRegister.REGISTER_X86_EIP); + SetBit((int)CorDebugRegister.REGISTER_X86_ESP); + SetBit((int)CorDebugRegister.REGISTER_X86_EBP); + if (!fQuickUnwind || fActive) + SetRange(CorDebugRegister.REGISTER_X86_EAX, CorDebugRegister.REGISTER_X86_EDI); + if (fActive) + SetRange(CorDebugRegister.REGISTER_X86_FPSTACK_0, CorDebugRegister.REGISTER_X86_FPSTACK_7); + break; + + case RuntimeInfoArchitecture.X64: + SetBit((int)CorDebugRegister.REGISTER_AMD64_RIP); + SetBit((int)CorDebugRegister.REGISTER_AMD64_RSP); + if (!fQuickUnwind || fActive) + SetRange(CorDebugRegister.REGISTER_AMD64_RBP, CorDebugRegister.REGISTER_AMD64_R15); + if (fActive) + SetRange(CorDebugRegister.REGISTER_AMD64_XMM0, CorDebugRegister.REGISTER_AMD64_XMM15); + break; + + case RuntimeInfoArchitecture.Arm: + SetBit((int)CorDebugRegister.REGISTER_ARM_PC); + SetBit((int)CorDebugRegister.REGISTER_ARM_SP); + SetRange(CorDebugRegister.REGISTER_ARM_R0, CorDebugRegister.REGISTER_ARM_LR); + break; + + case RuntimeInfoArchitecture.Arm64: + SetBit((int)CorDebugRegister.REGISTER_ARM64_PC); + SetBit((int)CorDebugRegister.REGISTER_ARM64_SP); + SetBit((int)CorDebugRegister.REGISTER_ARM64_FP); + SetRange(CorDebugRegister.REGISTER_ARM64_X0, CorDebugRegister.REGISTER_ARM64_X28); + SetBit((int)CorDebugRegister.REGISTER_ARM64_LR); + SetRange(CorDebugRegister.REGISTER_ARM64_V0, CorDebugRegister.REGISTER_ARM64_V31); + break; + + case RuntimeInfoArchitecture.LoongArch64: + for (int r = (int)CorDebugRegister.REGISTER_LOONGARCH64_PC; + r <= (int)CorDebugRegister.REGISTER_LOONGARCH64_S8; r++) + SetBit(r); + SetRange(CorDebugRegister.REGISTER_LOONGARCH64_F0, CorDebugRegister.REGISTER_LOONGARCH64_F31); + break; + + case RuntimeInfoArchitecture.RiscV64: + for (int r = (int)CorDebugRegister.REGISTER_RISCV64_PC; + r <= (int)CorDebugRegister.REGISTER_RISCV64_T6; r++) + SetBit(r); + SetRange(CorDebugRegister.REGISTER_RISCV64_F0, CorDebugRegister.REGISTER_RISCV64_F31); + break; + + default: + throw new NotImplementedException($"GetAvailableRegistersMask: unsupported architecture {arch}"); + } + } + + private static CorDebugRegister? MapJitRegNumToCorDebugRegister(RuntimeInfoArchitecture arch, uint jitRegNum) + { + switch (arch) + { + case RuntimeInfoArchitecture.X86: + return jitRegNum switch + { + 0 => CorDebugRegister.REGISTER_X86_EAX, + 1 => CorDebugRegister.REGISTER_X86_ECX, + 2 => CorDebugRegister.REGISTER_X86_EDX, + 3 => CorDebugRegister.REGISTER_X86_EBX, + 4 => CorDebugRegister.REGISTER_X86_ESP, + 5 => CorDebugRegister.REGISTER_X86_EBP, + 6 => CorDebugRegister.REGISTER_X86_ESI, + 7 => CorDebugRegister.REGISTER_X86_EDI, + _ => null, + }; + + case RuntimeInfoArchitecture.X64: + return jitRegNum switch + { + 0 => CorDebugRegister.REGISTER_AMD64_RAX, + 1 => CorDebugRegister.REGISTER_AMD64_RCX, + 2 => CorDebugRegister.REGISTER_AMD64_RDX, + 3 => CorDebugRegister.REGISTER_AMD64_RBX, + 4 => CorDebugRegister.REGISTER_AMD64_RSP, + 5 => CorDebugRegister.REGISTER_AMD64_RBP, + 6 => CorDebugRegister.REGISTER_AMD64_RSI, + 7 => CorDebugRegister.REGISTER_AMD64_RDI, + >= 8 and <= 15 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_AMD64_R8 + (int)(jitRegNum - 8)), + _ => null, + }; + + case RuntimeInfoArchitecture.Arm: + return jitRegNum switch + { + <= 12 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_ARM_R0 + (int)jitRegNum), + 13 => CorDebugRegister.REGISTER_ARM_SP, + 14 => CorDebugRegister.REGISTER_ARM_LR, + 15 => CorDebugRegister.REGISTER_ARM_PC, + _ => null, + }; + + case RuntimeInfoArchitecture.Arm64: + return jitRegNum switch + { + <= 28 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_ARM64_X0 + (int)jitRegNum), + 29 => CorDebugRegister.REGISTER_ARM64_FP, + 30 => CorDebugRegister.REGISTER_ARM64_LR, + 31 => CorDebugRegister.REGISTER_ARM64_SP, + 32 => CorDebugRegister.REGISTER_ARM64_PC, + _ => null, + }; + + case RuntimeInfoArchitecture.LoongArch64: + return jitRegNum switch + { + 0 => null, + 1 => CorDebugRegister.REGISTER_LOONGARCH64_RA, + 2 => CorDebugRegister.REGISTER_LOONGARCH64_TP, + 3 => CorDebugRegister.REGISTER_LOONGARCH64_SP, + >= 4 and <= 11 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_LOONGARCH64_A0 + (int)(jitRegNum - 4)), + >= 12 and <= 20 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_LOONGARCH64_T0 + (int)(jitRegNum - 12)), + 21 => CorDebugRegister.REGISTER_LOONGARCH64_X0, + 22 => CorDebugRegister.REGISTER_LOONGARCH64_FP, + >= 23 and <= 31 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_LOONGARCH64_S0 + (int)(jitRegNum - 23)), + 32 => CorDebugRegister.REGISTER_LOONGARCH64_PC, + _ => null, + }; + + case RuntimeInfoArchitecture.RiscV64: + return jitRegNum switch + { + 0 => null, + 1 => CorDebugRegister.REGISTER_RISCV64_RA, + 2 => CorDebugRegister.REGISTER_RISCV64_SP, + 3 => CorDebugRegister.REGISTER_RISCV64_GP, + 4 => CorDebugRegister.REGISTER_RISCV64_TP, + >= 5 and <= 7 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_RISCV64_T0 + (int)(jitRegNum - 5)), + 8 => CorDebugRegister.REGISTER_RISCV64_FP, + 9 => CorDebugRegister.REGISTER_RISCV64_S1, + >= 10 and <= 17 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_RISCV64_A0 + (int)(jitRegNum - 10)), + >= 18 and <= 27 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_RISCV64_S2 + (int)(jitRegNum - 18)), + >= 28 and <= 31 => (CorDebugRegister)((int)CorDebugRegister.REGISTER_RISCV64_T3 + (int)(jitRegNum - 28)), + 32 => CorDebugRegister.REGISTER_RISCV64_PC, + _ => null, + }; + + default: + return null; + } + } + + private static string? MapToCdacName(RuntimeInfoArchitecture arch, CorDebugRegister reg) + { + int n = (int)reg; + switch (arch) + { + case RuntimeInfoArchitecture.X86: + return n switch + { + 0 => "eip", 1 => "esp", 2 => "ebp", + 3 => "eax", 4 => "ecx", 5 => "edx", + 6 => "ebx", 7 => "esi", 8 => "edi", + _ => null, + }; + + case RuntimeInfoArchitecture.X64: + return n switch + { + 0 => "rip", 1 => "rsp", 2 => "rbp", + 3 => "rax", 4 => "rcx", 5 => "rdx", + 6 => "rbx", 7 => "rsi", 8 => "rdi", + >= 9 and <= 16 => "r" + (n - 9 + 8).ToString(), + _ => null, + }; + + case RuntimeInfoArchitecture.Arm: + return n switch + { + 0 => "pc", + 1 => "sp", + >= 2 and <= 14 => "r" + (n - 2).ToString(), + 15 => "lr", + _ => null, + }; + + case RuntimeInfoArchitecture.Arm64: + return n switch + { + 0 => "pc", + 1 => "sp", + 2 => "fp", + >= 3 and <= 31 => "x" + (n - 3).ToString(), + 32 => "lr", + _ => null, + }; + + case RuntimeInfoArchitecture.LoongArch64: + return n switch + { + 0 => "pc", 1 => "sp", 2 => "fp", 3 => "ra", 4 => "tp", + >= 5 and <= 12 => "a" + (n - 5).ToString(), + >= 13 and <= 21 => "t" + (n - 13).ToString(), + 22 => "x0", + >= 23 and <= 31 => "s" + (n - 23).ToString(), + _ => null, + }; + + case RuntimeInfoArchitecture.RiscV64: + return n switch + { + 0 => "pc", 1 => "sp", 2 => "fp", 3 => "ra", 4 => "gp", 5 => "tp", + >= 6 and <= 8 => "t" + (n - 6).ToString(), + 9 => "s1", + >= 10 and <= 17 => "a" + (n - 10).ToString(), + >= 18 and <= 27 => "s" + (n - 18 + 2).ToString(), + >= 28 and <= 31 => "t" + (n - 28 + 3).ToString(), + _ => null, + }; + + default: + return null; + } + } + // Fills a DebuggerIPCE_ExpandedTypeData entry for a single type parameter, falling back to System.__Canon on failure. private void FillExpandedTypeDataWithCanonFallback(IRuntimeTypeSystem rts, TypeHandle typeHandle, TypeHandle thCanon, DebuggerIPCE_ExpandedTypeData* pTypeInfo) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 37f627dd76238a..7d47e3dd770531 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -243,7 +243,7 @@ public enum EType } [FieldOffset(0)] public ulong fp; // FramePointer - [FieldOffset(8)] public ulong ctx; // DT_CONTEXT* + [FieldOffset(8)] public ulong ctx; // BYTE* [FieldOffset(16)] public ulong vmCurrentAppDomainToken; // VMPTR_AppDomain [FieldOffset(24)] public EType eType; [FieldOffset(32)] public DebuggerIPCE_STRData_MethodFrame v; @@ -409,6 +409,185 @@ public enum CorDebugSetContextFlags SET_CONTEXT_FLAG_UNWIND_FRAME = 0x2, } +public enum TargetArchitecture +{ + Unknown = 0, + X86, + AMD64, + Arm, + Arm64, + LoongArch64, + RiscV64, + Wasm, +} + +public enum TargetOperatingSystem +{ + Unknown = 0, + Windows, + Unix, +} + +public struct TargetInfo +{ + public TargetArchitecture Arch; + public TargetOperatingSystem OS; +} + +public enum ContextSizeFlags : int +{ + Base = 0, + ExtendedRegisters, +} + +public enum CorDebugRegister : int +{ + REGISTER_INSTRUCTION_POINTER = 0, + REGISTER_STACK_POINTER = 1, + REGISTER_FRAME_POINTER = 2, + + REGISTER_X86_EIP = 0, + REGISTER_X86_ESP = 1, + REGISTER_X86_EBP = 2, + REGISTER_X86_EAX = 3, + REGISTER_X86_ECX = 4, + REGISTER_X86_EDX = 5, + REGISTER_X86_EBX = 6, + REGISTER_X86_ESI = 7, + REGISTER_X86_EDI = 8, + REGISTER_X86_FPSTACK_0 = 9, + REGISTER_X86_FPSTACK_1 = 10, + REGISTER_X86_FPSTACK_2 = 11, + REGISTER_X86_FPSTACK_3 = 12, + REGISTER_X86_FPSTACK_4 = 13, + REGISTER_X86_FPSTACK_5 = 14, + REGISTER_X86_FPSTACK_6 = 15, + REGISTER_X86_FPSTACK_7 = 16, + + REGISTER_AMD64_RIP = 0, + REGISTER_AMD64_RSP = 1, + REGISTER_AMD64_RBP = 2, + REGISTER_AMD64_RAX = 3, + REGISTER_AMD64_RCX = 4, + REGISTER_AMD64_RDX = 5, + REGISTER_AMD64_RBX = 6, + REGISTER_AMD64_RSI = 7, + REGISTER_AMD64_RDI = 8, + REGISTER_AMD64_R8 = 9, + REGISTER_AMD64_R9 = 10, + REGISTER_AMD64_R10 = 11, + REGISTER_AMD64_R11 = 12, + REGISTER_AMD64_R12 = 13, + REGISTER_AMD64_R13 = 14, + REGISTER_AMD64_R14 = 15, + REGISTER_AMD64_R15 = 16, + REGISTER_AMD64_XMM0 = 17, + REGISTER_AMD64_XMM1 = 18, + REGISTER_AMD64_XMM2 = 19, + REGISTER_AMD64_XMM3 = 20, + REGISTER_AMD64_XMM4 = 21, + REGISTER_AMD64_XMM5 = 22, + REGISTER_AMD64_XMM6 = 23, + REGISTER_AMD64_XMM7 = 24, + REGISTER_AMD64_XMM8 = 25, + REGISTER_AMD64_XMM9 = 26, + REGISTER_AMD64_XMM10 = 27, + REGISTER_AMD64_XMM11 = 28, + REGISTER_AMD64_XMM12 = 29, + REGISTER_AMD64_XMM13 = 30, + REGISTER_AMD64_XMM14 = 31, + REGISTER_AMD64_XMM15 = 32, + + REGISTER_ARM_PC = 0, + REGISTER_ARM_SP = 1, + REGISTER_ARM_R0 = 2, + REGISTER_ARM_R1 = 3, + REGISTER_ARM_R2 = 4, + REGISTER_ARM_R3 = 5, + REGISTER_ARM_R4 = 6, + REGISTER_ARM_R5 = 7, + REGISTER_ARM_R6 = 8, + REGISTER_ARM_R7 = 9, + REGISTER_ARM_R8 = 10, + REGISTER_ARM_R9 = 11, + REGISTER_ARM_R10 = 12, + REGISTER_ARM_R11 = 13, + REGISTER_ARM_R12 = 14, + REGISTER_ARM_LR = 15, + REGISTER_ARM_D0 = 16, + REGISTER_ARM_D31 = 47, + + REGISTER_ARM64_PC = 0, + REGISTER_ARM64_SP = 1, + REGISTER_ARM64_FP = 2, + REGISTER_ARM64_X0 = 3, + REGISTER_ARM64_X1 = 4, + REGISTER_ARM64_X2 = 5, + REGISTER_ARM64_X3 = 6, + REGISTER_ARM64_X4 = 7, + REGISTER_ARM64_X5 = 8, + REGISTER_ARM64_X6 = 9, + REGISTER_ARM64_X7 = 10, + REGISTER_ARM64_X8 = 11, + REGISTER_ARM64_X9 = 12, + REGISTER_ARM64_X10 = 13, + REGISTER_ARM64_X11 = 14, + REGISTER_ARM64_X12 = 15, + REGISTER_ARM64_X13 = 16, + REGISTER_ARM64_X14 = 17, + REGISTER_ARM64_X15 = 18, + REGISTER_ARM64_X16 = 19, + REGISTER_ARM64_X17 = 20, + REGISTER_ARM64_X18 = 21, + REGISTER_ARM64_X19 = 22, + REGISTER_ARM64_X20 = 23, + REGISTER_ARM64_X21 = 24, + REGISTER_ARM64_X22 = 25, + REGISTER_ARM64_X23 = 26, + REGISTER_ARM64_X24 = 27, + REGISTER_ARM64_X25 = 28, + REGISTER_ARM64_X26 = 29, + REGISTER_ARM64_X27 = 30, + REGISTER_ARM64_X28 = 31, + REGISTER_ARM64_LR = 32, + REGISTER_ARM64_V0 = 33, + REGISTER_ARM64_V31 = 64, + + REGISTER_LOONGARCH64_PC = 0, + REGISTER_LOONGARCH64_SP = 1, + REGISTER_LOONGARCH64_FP = 2, + REGISTER_LOONGARCH64_RA = 3, + REGISTER_LOONGARCH64_TP = 4, + REGISTER_LOONGARCH64_A0 = 5, + REGISTER_LOONGARCH64_A7 = 12, + REGISTER_LOONGARCH64_T0 = 13, + REGISTER_LOONGARCH64_T8 = 21, + REGISTER_LOONGARCH64_X0 = 22, + REGISTER_LOONGARCH64_S0 = 23, + REGISTER_LOONGARCH64_S8 = 31, + REGISTER_LOONGARCH64_F0 = 32, + REGISTER_LOONGARCH64_F31 = 63, + + REGISTER_RISCV64_PC = 0, + REGISTER_RISCV64_SP = 1, + REGISTER_RISCV64_FP = 2, + REGISTER_RISCV64_RA = 3, + REGISTER_RISCV64_GP = 4, + REGISTER_RISCV64_TP = 5, + REGISTER_RISCV64_T0 = 6, + REGISTER_RISCV64_T1 = 7, + REGISTER_RISCV64_T2 = 8, + REGISTER_RISCV64_S1 = 9, + REGISTER_RISCV64_A0 = 10, + REGISTER_RISCV64_A7 = 17, + REGISTER_RISCV64_S2 = 18, + REGISTER_RISCV64_S11 = 27, + REGISTER_RISCV64_T3 = 28, + REGISTER_RISCV64_T6 = 31, + REGISTER_RISCV64_F0 = 32, + REGISTER_RISCV64_F31 = 63, +} + // Name-surface projection of IDacDbiInterface in native method order for COM binding validation. // Parameter shapes are intentionally coarse placeholders and will be refined with method implementation work. [GeneratedComInterface] @@ -801,4 +980,34 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); + + [PreserveSig] + int GetTargetContextSize(ContextSizeFlags flags, uint* pSize); + + [PreserveSig] + int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* values); + + [PreserveSig] + int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* pValues); + + [PreserveSig] + int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable); + + [PreserveSig] + int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* pReg); + + [PreserveSig] + int ReadFloatRegistersFromContext(byte* ctxBuf, uint cb, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop); + + [PreserveSig] + int GetTargetInfo(TargetInfo* pTargetInfo); + + [PreserveSig] + int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pResult); + + [PreserveSig] + int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint cb2, Interop.BOOL* pResult); + + [PreserveSig] + int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, uint flags); } From b259616bc03571e63bc3ede4d01569050514f17e Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 11:09:35 -0700 Subject: [PATCH 02/26] add untracked files --- src/coreclr/debug/di/cordbregisterset.cpp | 243 ++++++++++++++++++ src/coreclr/vm/amd64/getstate.asm | 3 - .../Dbi/Helpers/FloatConversion.cs | 91 +++++++ 3 files changed, 334 insertions(+), 3 deletions(-) create mode 100644 src/coreclr/debug/di/cordbregisterset.cpp create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs diff --git a/src/coreclr/debug/di/cordbregisterset.cpp b/src/coreclr/debug/di/cordbregisterset.cpp new file mode 100644 index 00000000000000..3e187186252743 --- /dev/null +++ b/src/coreclr/debug/di/cordbregisterset.cpp @@ -0,0 +1,243 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +//***************************************************************************** +// File: CordbRegisterSet.cpp +// +// Cross-platform implementation of CordbRegisterSet's ICorDebugRegisterSet / +// ICorDebugRegisterSet2 surface. +// +// Availability bits (for both GPRs and float / SIMD registers) come from a +// single byte-form DDI: IDacDbiInterface::GetAvailableRegistersMask. The DAC +// owns the per-arch policy that gates float visibility (active-only on +// x86 / amd64, suppressed on arm, always on for arm64 / loongarch64 / +// riscv64), so this file no longer reasons about it. +// +// GPR register VALUES come from the cached target CONTEXT byte buffer +// (m_pContext) via a single batched IDacDbiInterface::ReadRegistersFromContext +// call. Float / SIMD register VALUES come from the thread's float cache +// (IDacDbiInterface::ReadFloatRegistersFromContext, loaded up front so the +// requested bits can be partitioned into a GPR batch and a float batch). +// +// The single remaining per-arch wart here is the x87 stack-relative slot +// inversion on x86 (REGISTER_X86_FPSTACK_N points to a stack-relative +// position, not a physical slot). +// +//***************************************************************************** +#include "stdafx.h" +#include "primitives.h" + +namespace +{ + // Read the float-state cache, loading it on demand. Returns S_OK if the + // cache is populated (or there's nothing to do); failure HRESULT if + // LoadFloatState failed. + HRESULT EnsureFloatStateLoaded(CordbThread * pThread) + { + if (pThread->m_fFloatStateValid) + return S_OK; + + HRESULT hr = S_OK; + EX_TRY + { + pThread->LoadFloatState(); + } + EX_CATCH_HRESULT(hr); + if (FAILED(hr)) + return hr; + + LOG((LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n")); + return S_OK; + } + + // Buffer size for the byte-form availability mask. arm64 needs 9 bytes + // (REGISTER_ARM64_V31 is bit 64); 16 bytes covers every arch with room + // to spare without forcing dynamic allocation. + constexpr ULONG32 kAvailMaskBytes = 16; + + // Upper bound on distinct register bit positions (kAvailMaskBytes * 8), + // used to size the batched GPR request/value arrays on the stack. + constexpr ULONG32 kMaxRegisters = kAvailMaskBytes * 8; + + inline bool MaskBitSet(const BYTE * mask, ULONG32 maskCount, int bit) + { + ULONG32 byteIdx = (ULONG32)bit / 8; + if (byteIdx >= maskCount) + return false; + return (mask[byteIdx] & (BYTE)(1 << (bit % 8))) != 0; + } + + // Shared GetRegisters core. Validates that every bit set in the caller's + // request is also set in the available mask (E_INVALIDARG otherwise), then + // fills regBuffer in ascending bit order. The requested bits are partitioned + // into two batches: GPR bits are read in a single ReadRegistersFromContext + // call, and float bits are served from the thread's float cache. + HRESULT FillRegisters(IDacDbiInterface * pDAC, + BYTE * pContext, ULONG32 contextSize, + CordbThread * pThread, + const BYTE * requestMask, ULONG32 requestMaskCount, + const BYTE * availMask, ULONG32 availMaskCount, + ULONG32 regCount, CORDB_REGISTER regBuffer[]) + { + // Validate request is a subset of available. + for (ULONG32 b = 0; b < requestMaskCount * 8; b++) + { + if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) + continue; + if (!MaskBitSet(availMask, availMaskCount, (int)b)) + return E_INVALIDARG; + } + + // Load the float cache up front so its register range can classify the + // requested bits into GPR and float batches. + HRESULT hr = EnsureFloatStateLoaded(pThread); + bool areFloatsValid = !!SUCCEEDED(hr); + + int firstFloat = -1; + int lastFloat = -1; + if (pThread->m_floatValuesCount > 0 && pThread->m_firstFloatReg >= 0 && areFloatsValid) + { + firstFloat = pThread->m_firstFloatReg; + lastFloat = firstFloat + (int)pThread->m_floatValuesCount - 1; + } + + auto IsFloatBit = [firstFloat, lastFloat](int b) + { + return firstFloat >= 0 && b >= firstFloat && b <= lastFloat; + }; + + // First pass: collect the GPR register ids (ascending bit order) for the + // batched read. + CorDebugRegister gprRegs[kMaxRegisters]; + TADDR gprValues[kMaxRegisters]; + ULONG32 gprCount = 0; + for (ULONG32 b = 0; b < requestMaskCount * 8; b++) + { + if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) + continue; + if (IsFloatBit((int)b)) + continue; + if (gprCount >= kMaxRegisters) + return E_FAIL; + gprRegs[gprCount++] = (CorDebugRegister)b; + } + + if (gprCount > 0) + { + hr = pDAC->ReadRegistersFromContext(pContext, contextSize, gprRegs, gprCount, gprValues); + if (FAILED(hr)) + return hr; + } + + // Second pass: fill regBuffer in ascending bit order, consuming from the + // GPR batch and the float cache. + UINT iRegister = 0; + ULONG32 gprIdx = 0; + for (ULONG32 b = 0; b < requestMaskCount * 8 && iRegister < regCount; b++) + { + if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) + continue; + + if (IsFloatBit((int)b)) + { + ULONG32 idx = (ULONG32)((int)b - firstFloat); +#if defined(TARGET_X86) + // x86 storage is pop-physical order: m_floatValues[0] = ST(0) + // = top of stack. REGISTER_X86_FPSTACK_0 is the logical name + // of the BOTTOM of the stack, so flip. + idx = (ULONG32)(pThread->m_floatStackTop - ((int)b - REGISTER_X86_FPSTACK_0)); +#endif + memcpy(®Buffer[iRegister++], &pThread->m_floatValues[idx], sizeof(CORDB_REGISTER)); + } + else + { + regBuffer[iRegister++] = (CORDB_REGISTER)gprValues[gprIdx++]; + } + } + + _ASSERTE(iRegister <= regCount); + return S_OK; + } +} // anonymous namespace + +HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG64 * pAvailable) +{ + FAIL_IF_NEUTERED(this); + VALIDATE_POINTER_TO_OBJECT(pAvailable, ULONG64 *); + + BYTE availBytes[kAvailMaskBytes] = {}; + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + HRESULT hr = pDAC->GetAvailableRegistersMask( + m_active, m_quickUnwind, kAvailMaskBytes, availBytes); + if (FAILED(hr)) + return hr; + + // Fold the low 64 bits into the ULONG64 surface. Bits at positions >= 64 + // (e.g. arm64 V31) are only reachable through the v2 byte-mask overload. + ULONG64 mask = 0; + for (int b = 0; b < 64; b++) + { + if (availBytes[b / 8] & (BYTE)(1 << (b % 8))) + mask |= SETBITULONG64(b); + } + *pAvailable = mask; + return S_OK; +} + +HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, + CORDB_REGISTER regBuffer[]) +{ + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); + + VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); + + BYTE availBytes[kAvailMaskBytes] = {}; + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + HRESULT hr = pDAC->GetAvailableRegistersMask( + m_active, m_quickUnwind, kAvailMaskBytes, availBytes); + if (FAILED(hr)) + return hr; + + BYTE requestBytes[sizeof(ULONG64)] = {}; + for (int b = 0; b < 64; b++) + { + if (mask & SETBITULONG64(b)) + requestBytes[b / 8] |= (BYTE)(1 << (b % 8)); + } + + return FillRegisters(pDAC, m_pContext, m_contextSize, m_thread, + requestBytes, (ULONG32)sizeof(requestBytes), + availBytes, kAvailMaskBytes, regCount, regBuffer); +} + +HRESULT CordbRegisterSet::GetRegistersAvailable(ULONG32 regCount, BYTE pAvailable[]) +{ + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + VALIDATE_POINTER_TO_OBJECT_ARRAY(pAvailable, CORDB_REGISTER, regCount, true, true); + + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + return pDAC->GetAvailableRegistersMask(m_active, m_quickUnwind, regCount, pAvailable); +} + +HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], + ULONG32 regCount, CORDB_REGISTER regBuffer[]) +{ + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); + + VALIDATE_POINTER_TO_OBJECT_ARRAY(regBuffer, CORDB_REGISTER, regCount, true, true); + + BYTE availBytes[kAvailMaskBytes] = {}; + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + HRESULT hr = pDAC->GetAvailableRegistersMask( + m_active, m_quickUnwind, kAvailMaskBytes, availBytes); + if (FAILED(hr)) + return hr; + + return FillRegisters(pDAC, m_pContext, m_contextSize, m_thread, + mask, maskCount, + availBytes, kAvailMaskBytes, regCount, regBuffer); +} diff --git a/src/coreclr/vm/amd64/getstate.asm b/src/coreclr/vm/amd64/getstate.asm index 7033b7bf0c3d66..7487ca4e7c7ea1 100644 --- a/src/coreclr/vm/amd64/getstate.asm +++ b/src/coreclr/vm/amd64/getstate.asm @@ -29,9 +29,6 @@ LEAF_ENTRY GetRBP, _TEXT LEAF_END GetRBP, _TEXT -;// this is the same implementation as the function of the same name in di\amd64\floatconversion.asm and they must -;// remain in sync. - ;// @dbgtodo inspection: remove this function when we remove the ipc event to load the float state ; extern "C" double FPFillR8(void* fpContextSlot); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs new file mode 100644 index 00000000000000..28f3ff036d38a1 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs @@ -0,0 +1,91 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; + +namespace Microsoft.Diagnostics.DataContractReader.Legacy; + +internal static class FloatConversion +{ + // Convert an x87 80-bit double-extended value to IEEE-754 binary64 with + // round-to-nearest-even, matching the hardware FSTP conversion the legacy + // x86 path used. Layout (Intel SDM Vol 1 sec 8.2.2): bytes 0-7 = 64-bit + // significand with an explicit integer bit at 63; bytes 8-9 = 15-bit biased + // exponent (bias 16383) in bits 0-14 and the sign in bit 15. + public static double X87ExtendedToDouble(ReadOnlySpan slot10) + { + ulong significand = BinaryPrimitives.ReadUInt64LittleEndian(slot10); + ushort signExp = BinaryPrimitives.ReadUInt16LittleEndian(slot10.Slice(8)); + + ulong sign = (ulong)((signExp >> 15) & 1) << 63; + uint exp80 = (uint)(signExp & 0x7FFF); + + if (exp80 == 0x7FFF) + { + ulong frac = significand & ~(1UL << 63); + if (frac == 0) + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | ((ulong)0x7FF << 52)))); + // Force a quiet NaN (keeping the high payload bits) so a signaling + // NaN is never misencoded as an infinity. + ulong payload = (frac >> 12) & ((1UL << 51) - 1); + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | ((ulong)0x7FF << 52) | (1UL << 51) | payload))); + } + + // Zero, extended denormals and unnormals all fall below the binary64 + // subnormal floor (2^-1074) and map to signed zero. + if (exp80 == 0 || (significand & (1UL << 63)) == 0) + return BitConverter.Int64BitsToDouble(unchecked((long)sign)); + + int expD = (int)exp80 - 16383 + 1023; // pre-rounding binary64 biased exponent + + if (expD >= 0x7FF) + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | ((ulong)0x7FF << 52)))); // overflow -> infinity + + if (expD > 0) + { + // Normal: keep the top 52 fraction bits and round the low 11 to even. + ulong frac = significand & ~(1UL << 63); // 63 fraction bits + ulong result = frac >> 11; // top 52 bits + ulong discarded = frac & 0x7FF; // low 11 bits + if (discarded > 0x400 || (discarded == 0x400 && (result & 1) != 0)) + { + result++; + if ((result >> 52) != 0) // carry out of the fraction + { + result = 0; + expD++; + if (expD >= 0x7FF) + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | ((ulong)0x7FF << 52)))); + } + } + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | ((ulong)expD << 52) | (result & ((1UL << 52) - 1))))); + } + + // Subnormal / underflow (expD <= 0): right-shift the significand by + // (12 - expD) and round to nearest-even. A carry into bit 52 promotes the + // value to the smallest normal, which the encoding produces for free. + int shift = 12 - expD; // >= 12 + if (shift > 64) // below half the smallest subnormal + return BitConverter.Int64BitsToDouble(unchecked((long)sign)); + + ulong res; + ulong disc; + ulong half; + if (shift == 64) + { + res = 0; + disc = significand; + half = 1UL << 63; + } + else + { + res = significand >> shift; + disc = significand & ((1UL << shift) - 1); + half = 1UL << (shift - 1); + } + if (disc > half || (disc == half && (res & 1) != 0)) + res++; + return BitConverter.Int64BitsToDouble(unchecked((long)(sign | res))); + } +} From 4b72f504eb599f2477bf59d48c2ab845e1fc5993 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 11:56:02 -0700 Subject: [PATCH 03/26] fix build --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 2 +- src/coreclr/debug/inc/arm_primitives.h | 2 +- src/coreclr/debug/inc/i386/primitives.h | 2 +- src/coreclr/debug/inc/loongarch64/primitives.h | 2 +- src/coreclr/debug/inc/riscv64/primitives.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 69f1e6215ff9e2..81407fa1d1db3a 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -6117,7 +6117,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( IN BYTE * ctxBuf, IN ULONG32 cb, IN ULONG32 maxValues, - OUT DOUBLE values[], + OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], OUT ULONG32 * pValuesCount, OUT int * pFirstFloatReg, OUT ULONG32 * pFloatStackTop) diff --git a/src/coreclr/debug/inc/arm_primitives.h b/src/coreclr/debug/inc/arm_primitives.h index de04ac395b10aa..1d91943441708f 100644 --- a/src/coreclr/debug/inc/arm_primitives.h +++ b/src/coreclr/debug/inc/arm_primitives.h @@ -24,7 +24,7 @@ inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum re return g_JITToCorDbgReg[reg]; } -inline LPVOID CORDbgGetIP(DT_CONTEXT *context) +inline LPVOID CORDbgGetIP(T_CONTEXT *context) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/debug/inc/i386/primitives.h b/src/coreclr/debug/inc/i386/primitives.h index 0144d013399ee5..d5ef47b4e2451a 100644 --- a/src/coreclr/debug/inc/i386/primitives.h +++ b/src/coreclr/debug/inc/i386/primitives.h @@ -72,7 +72,7 @@ inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum re // // inline function to access/modify the CONTEXT // -inline LPVOID CORDbgGetIP(DT_CONTEXT *context) { +inline LPVOID CORDbgGetIP(T_CONTEXT *context) { LIMITED_METHOD_CONTRACT; return (LPVOID)(size_t)(context->Eip); diff --git a/src/coreclr/debug/inc/loongarch64/primitives.h b/src/coreclr/debug/inc/loongarch64/primitives.h index 0fc5fcf4b3720b..f6f95cc4d15141 100644 --- a/src/coreclr/debug/inc/loongarch64/primitives.h +++ b/src/coreclr/debug/inc/loongarch64/primitives.h @@ -160,7 +160,7 @@ inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum re return g_JITToCorDbgReg[reg]; } -inline LPVOID CORDbgGetIP(DT_CONTEXT *context) +inline LPVOID CORDbgGetIP(T_CONTEXT *context) { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/debug/inc/riscv64/primitives.h b/src/coreclr/debug/inc/riscv64/primitives.h index abb80707a34626..a8800223d35ccf 100644 --- a/src/coreclr/debug/inc/riscv64/primitives.h +++ b/src/coreclr/debug/inc/riscv64/primitives.h @@ -161,7 +161,7 @@ inline CorDebugRegister ConvertRegNumToCorDebugRegister(ICorDebugInfo::RegNum re return g_JITToCorDbgReg[reg]; } -inline LPVOID CORDbgGetIP(DT_CONTEXT *context) +inline LPVOID CORDbgGetIP(T_CONTEXT *context) { LIMITED_METHOD_CONTRACT; From b1cfa558c07104348207d3cd838214b12419aa25 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 13:14:23 -0700 Subject: [PATCH 04/26] fix build --- src/coreclr/debug/ee/arm/primitives.cpp | 4 ++-- src/coreclr/debug/ee/arm64/primitives.cpp | 12 ++++++------ src/coreclr/debug/ee/loongarch64/primitives.cpp | 6 +++--- src/coreclr/debug/ee/riscv64/primitives.cpp | 6 +++--- src/coreclr/debug/inc/arm/primitives.h | 6 +++--- src/coreclr/debug/inc/arm_primitives.h | 6 +++--- src/coreclr/debug/inc/loongarch64/primitives.h | 6 +++--- src/coreclr/debug/inc/riscv64/primitives.h | 6 +++--- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/coreclr/debug/ee/arm/primitives.cpp b/src/coreclr/debug/ee/arm/primitives.cpp index 4c085699e06ba9..84e008b7585369 100644 --- a/src/coreclr/debug/ee/arm/primitives.cpp +++ b/src/coreclr/debug/ee/arm/primitives.cpp @@ -20,7 +20,7 @@ void SetSSFlag(DT_CONTEXT *, Thread *pThread) pThread->EnableSingleStep(); } -void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) +void UnsetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); @@ -28,7 +28,7 @@ void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) } // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *, Thread *pThread) +bool IsSSFlagEnabled(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); diff --git a/src/coreclr/debug/ee/arm64/primitives.cpp b/src/coreclr/debug/ee/arm64/primitives.cpp index 3cfee11c692bd4..d5dadbf5e665e3 100644 --- a/src/coreclr/debug/ee/arm64/primitives.cpp +++ b/src/coreclr/debug/ee/arm64/primitives.cpp @@ -14,14 +14,14 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) } #ifdef FEATURE_EMULATE_SINGLESTEP -void SetSSFlag(DT_CONTEXT *, Thread *pThread) +void SetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); pThread->EnableSingleStep(); } -void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) +void UnsetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); @@ -29,25 +29,25 @@ void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) } // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *, Thread *pThread) +bool IsSSFlagEnabled(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); return pThread->IsSingleStepEnabled(); } #else // FEATURE_EMULATE_SINGLESTEP -void SetSSFlag(DT_CONTEXT *pContext, Thread *) +void SetSSFlag(T_CONTEXT *pContext, Thread *) { SetSSFlag(pContext); } -void UnsetSSFlag(DT_CONTEXT *pContext, Thread *) +void UnsetSSFlag(T_CONTEXT *pContext, Thread *) { UnsetSSFlag(pContext); } // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *pContext, Thread *) +bool IsSSFlagEnabled(T_CONTEXT *pContext, Thread *) { return IsSSFlagEnabled(pContext); } diff --git a/src/coreclr/debug/ee/loongarch64/primitives.cpp b/src/coreclr/debug/ee/loongarch64/primitives.cpp index 981809a4bac21a..206f2789cf014f 100644 --- a/src/coreclr/debug/ee/loongarch64/primitives.cpp +++ b/src/coreclr/debug/ee/loongarch64/primitives.cpp @@ -11,14 +11,14 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) CopyRegDisplay(pSrc, pDst, &tmp); } -void SetSSFlag(DT_CONTEXT *, Thread *pThread) +void SetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); pThread->EnableSingleStep(); } -void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) +void UnsetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); @@ -26,7 +26,7 @@ void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) } // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *, Thread *pThread) +bool IsSSFlagEnabled(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); diff --git a/src/coreclr/debug/ee/riscv64/primitives.cpp b/src/coreclr/debug/ee/riscv64/primitives.cpp index 65f4c586238f3f..0e9021a91ba3d2 100644 --- a/src/coreclr/debug/ee/riscv64/primitives.cpp +++ b/src/coreclr/debug/ee/riscv64/primitives.cpp @@ -13,14 +13,14 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) CopyRegDisplay(pSrc, pDst, &tmp); } -void SetSSFlag(DT_CONTEXT *, Thread *pThread) +void SetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); pThread->EnableSingleStep(); } -void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) +void UnsetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); @@ -28,7 +28,7 @@ void UnsetSSFlag(DT_CONTEXT *, Thread *pThread) } // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *, Thread *pThread) +bool IsSSFlagEnabled(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); diff --git a/src/coreclr/debug/inc/arm/primitives.h b/src/coreclr/debug/inc/arm/primitives.h index d057f8565efb1a..93e9fd115ef92d 100644 --- a/src/coreclr/debug/inc/arm/primitives.h +++ b/src/coreclr/debug/inc/arm/primitives.h @@ -167,13 +167,13 @@ inline void CORDbgSetInstruction(CORDB_ADDRESS_TYPE* address, class Thread; // Enable single stepping. -void SetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void SetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Disable single stepping -void UnsetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void UnsetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *pCtx, Thread *pThread); +bool IsSSFlagEnabled(T_CONTEXT *pCtx, Thread *pThread); #include "arm_primitives.h" #endif // PRIMITIVES_H_ diff --git a/src/coreclr/debug/inc/arm_primitives.h b/src/coreclr/debug/inc/arm_primitives.h index 1d91943441708f..0f322643df2587 100644 --- a/src/coreclr/debug/inc/arm_primitives.h +++ b/src/coreclr/debug/inc/arm_primitives.h @@ -88,13 +88,13 @@ inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE* address) class Thread; // Enable single stepping. -void SetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void SetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Disable single stepping -void UnsetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void UnsetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *pCtx, Thread *pThread); +bool IsSSFlagEnabled(T_CONTEXT *pCtx, Thread *pThread); inline bool PRDIsEqual(PRD_TYPE p1, PRD_TYPE p2) { diff --git a/src/coreclr/debug/inc/loongarch64/primitives.h b/src/coreclr/debug/inc/loongarch64/primitives.h index f6f95cc4d15141..90d1714052342d 100644 --- a/src/coreclr/debug/inc/loongarch64/primitives.h +++ b/src/coreclr/debug/inc/loongarch64/primitives.h @@ -219,13 +219,13 @@ inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE* address) class Thread; // Enable single stepping. -void SetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void SetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Disable single stepping -void UnsetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void UnsetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *pCtx, Thread *pThread); +bool IsSSFlagEnabled(T_CONTEXT *pCtx, Thread *pThread); inline bool PRDIsEqual(PRD_TYPE p1, PRD_TYPE p2) diff --git a/src/coreclr/debug/inc/riscv64/primitives.h b/src/coreclr/debug/inc/riscv64/primitives.h index a8800223d35ccf..f30477a4821e70 100644 --- a/src/coreclr/debug/inc/riscv64/primitives.h +++ b/src/coreclr/debug/inc/riscv64/primitives.h @@ -220,13 +220,13 @@ inline bool AddressIsBreakpoint(CORDB_ADDRESS_TYPE* address) class Thread; // Enable single stepping. -void SetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void SetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Disable single stepping -void UnsetSSFlag(DT_CONTEXT *pCtx, Thread *pThread); +void UnsetSSFlag(T_CONTEXT *pCtx, Thread *pThread); // Check if single stepping is enabled. -bool IsSSFlagEnabled(DT_CONTEXT *pCtx, Thread *pThread); +bool IsSSFlagEnabled(T_CONTEXT *pCtx, Thread *pThread); inline bool PRDIsEqual(PRD_TYPE p1, PRD_TYPE p2) From b85b41ab89d8059b189df0f3746e033437cce5b0 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 13:16:52 -0700 Subject: [PATCH 05/26] code review --- src/coreclr/debug/di/rsregsetcommon.cpp | 2 +- src/coreclr/debug/ee/controller.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/di/rsregsetcommon.cpp b/src/coreclr/debug/di/rsregsetcommon.cpp index 5a7fd605bd7fbe..25646efbd320ed 100644 --- a/src/coreclr/debug/di/rsregsetcommon.cpp +++ b/src/coreclr/debug/di/rsregsetcommon.cpp @@ -155,7 +155,7 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) // Overlay this frame's registers from the cached CONTEXT buffer, honoring the destination's // ContextFlags (the leaf's if copied above, otherwise the caller's incoming flags). - pDAC->CopyContext(context, contextSize, m_pContext, m_contextSize, 0); + IfFailThrow(pDAC->CopyContext(context, contextSize, m_pContext, m_contextSize, 0)); } EX_CATCH_HRESULT(hr); return hr; diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 6f08e1063ec452..9ede52b4679aff 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -8325,7 +8325,7 @@ void DebuggerStepper::PrepareForSendEvent(StackTraceTicket ticket) { // If we're at either a patch or SS, we'll have a context. CONTEXT *context = g_pEEInterface->GetThreadFilterContext(GetThread()); - if (context == NULL) + if (context != NULL) { void * pIP = CORDbgGetIP(context); From 057d5faa6505fbf161b073dd4b117b3bb03672d2 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 13:56:09 -0700 Subject: [PATCH 06/26] fix build --- src/coreclr/debug/ee/arm/primitives.cpp | 2 +- src/coreclr/pal/inc/pal.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/coreclr/debug/ee/arm/primitives.cpp b/src/coreclr/debug/ee/arm/primitives.cpp index 84e008b7585369..a8cd675c5884c7 100644 --- a/src/coreclr/debug/ee/arm/primitives.cpp +++ b/src/coreclr/debug/ee/arm/primitives.cpp @@ -13,7 +13,7 @@ void CopyREGDISPLAY(REGDISPLAY* pDst, REGDISPLAY* pSrc) CopyRegDisplay(pSrc, pDst, &tmp); } -void SetSSFlag(DT_CONTEXT *, Thread *pThread) +void SetSSFlag(T_CONTEXT *, Thread *pThread) { _ASSERTE(pThread != NULL); diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 970d29fc769d78..8840784c72f28f 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -870,19 +870,19 @@ typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA; typedef struct _CONTEXT { ULONG ContextFlags; - ULONG Dr0_PAL_Undefined; - ULONG Dr1_PAL_Undefined; - ULONG Dr2_PAL_Undefined; - ULONG Dr3_PAL_Undefined; - ULONG Dr6_PAL_Undefined; - ULONG Dr7_PAL_Undefined; + ULONG Dr0; // UNDEFINED + ULONG Dr1; // UNDEFINED + ULONG Dr2; // UNDEFINED + ULONG Dr3; // UNDEFINED + ULONG Dr6; // UNDEFINED + ULONG Dr7; // UNDEFINED FLOATING_SAVE_AREA FloatSave; - ULONG SegGs_PAL_Undefined; - ULONG SegFs_PAL_Undefined; - ULONG SegEs_PAL_Undefined; - ULONG SegDs_PAL_Undefined; + ULONG SegGs; // UNDEFINED + ULONG SegFs; // UNDEFINED + ULONG SegEs; // UNDEFINED + ULONG SegDs; // UNDEFINED ULONG Edi; ULONG Esi; From 2974b5721ed537b19bde70a9671c39723ade1120 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 16:47:08 -0700 Subject: [PATCH 07/26] fix crossdac --- src/coreclr/debug/di/process.cpp | 4 ++-- src/coreclr/debug/di/rsthread.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index c8e46b4c6f04c1..4293d7297bb630 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -5924,7 +5924,7 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, T_CONTEXT * BYTE * pCtxSource = (BYTE*) pCtx; -#if defined(CONTEXT_EXTENDED_REGISTERS) +#if defined(TARGET_X86) if ((pCtx->ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) { sizeToWrite = offsetof(T_CONTEXT, SegSs) + sizeof(pCtx->SegSs); @@ -12700,7 +12700,7 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven { LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: hijack complete will restore context...\n")); T_CONTEXT tempContext = { 0 }; -#if defined(CONTEXT_EXTENDED_REGISTERS) +#if defined(TARGET_X86) tempContext.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else tempContext.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index 138770b1e5c99c..17a49b7e05ca80 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -3463,7 +3463,7 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() // Save the thread's full context + CONTEXT_EXTENDED_REGISTERS // to avoid getting incomplete information and corrupt the thread context T_CONTEXT context; -#if defined(CONTEXT_EXTENDED_REGISTERS) +#if defined(TARGET_X86) context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else context.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; @@ -3476,7 +3476,7 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() DWORD error = GetLastError(); LOG((LF_CORDB, LL_ERROR, "CUT::SFCHFS: DbiGetThreadContext error=0x%x\n", error)); } -#if defined(CONTEXT_EXTENDED_REGISTERS) +#if defined(TARGET_X86) GetHijackCtx()->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; #else GetHijackCtx()->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; From aee5d91ac57e9540babb420d941687f5bbd3da8a Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 14 Jul 2026 11:37:15 -0700 Subject: [PATCH 08/26] sig --- .../Dbi/DacDbiImpl.cs | 8 ++++---- .../Dbi/IDacDbiInterface.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index e2076a882d2923..ae795f3761f9bb 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -5849,7 +5849,7 @@ public int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, return hr; } - public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* values) + public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* values) { int hr = HResults.S_OK; IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); @@ -5898,7 +5898,7 @@ public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs return hr; } - public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* pValues) + public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* pValues) { int hr = HResults.S_OK; try @@ -5929,9 +5929,9 @@ public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* reg #if DEBUG if (_legacy is not null) { - ulong[] valuesLocal = new ulong[nRegs]; + nuint[] valuesLocal = new nuint[nRegs]; int hrLocal; - fixed (ulong* pValuesLocal = valuesLocal) + fixed (nuint* pValuesLocal = valuesLocal) hrLocal = _legacy.ReadRegistersFromContext(ctxBuf, cb, regs, nRegs, pValuesLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 8ada9542281ef7..132be40da51c06 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -983,10 +983,10 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int GetTargetContextSize(ContextSizeFlags flags, uint* pSize); [PreserveSig] - int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* values); + int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* values); [PreserveSig] - int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, ulong* pValues); + int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* pValues); [PreserveSig] int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable); From 953481510bd2f3c1dc1d90bcfa3365d6cb104eac Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 14 Jul 2026 14:38:47 -0700 Subject: [PATCH 09/26] fix build --- .../Dbi/DacDbiImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index ae795f3761f9bb..30245653778c8e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -5919,7 +5919,7 @@ public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* reg { // Registers with no CONTEXT slot (float / SIMD) read as zero. string? name = MapToCdacName(arch, regs[i]); - pValues[i] = (name is not null && ctx.TryReadRegister(name, out TargetNUInt v)) ? v.Value : 0; + pValues[i] = (name is not null && ctx.TryReadRegister(name, out TargetNUInt v)) ? (nuint)v.Value : 0; } } catch (System.Exception ex) From 9aea595f703ebd0f1abf490ed081ba91ba22c075 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Jul 2026 12:48:38 -0700 Subject: [PATCH 10/26] code review --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 77 +++---- src/coreclr/debug/daccess/dacdbiimpl.h | 26 +-- .../debug/daccess/dacdbiimplstackwalk.cpp | 61 +++-- src/coreclr/debug/di/cordbregisterset.cpp | 10 +- src/coreclr/debug/di/process.cpp | 46 ++-- src/coreclr/debug/di/rspriv.h | 36 ++- src/coreclr/debug/di/rsregsetcommon.cpp | 34 ++- src/coreclr/debug/di/rsstackwalk.cpp | 42 ++-- src/coreclr/debug/di/rsthread.cpp | 110 +++++---- src/coreclr/debug/di/shimpriv.h | 9 +- src/coreclr/debug/di/shimstackwalk.cpp | 67 +++--- src/coreclr/debug/di/valuehome.cpp | 47 ++-- src/coreclr/debug/inc/dacdbiinterface.h | 51 ++--- src/coreclr/debug/inc/dacdbistructures.h | 7 + src/coreclr/inc/dacdbi.idl | 33 +-- .../Dbi/DacDbiImpl.cs | 215 ++++++++++-------- .../Dbi/IDacDbiInterface.cs | 31 ++- .../DacDbi/DacDbiStackWalkDumpTests.cs | 12 +- .../cdac/tests/UnitTests/DacDbiImplTests.cs | 23 +- 19 files changed, 552 insertions(+), 385 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index f962b81c73d862..1d256e08e8f236 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5428,17 +5428,20 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetDebuggerControlBlockAddress(OU } // DacDbi API: Get the context for a particular thread of the target process -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, BYTE * pContextBufferRaw) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer) { DD_ENTER_MAY_THROW + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; EX_TRY { - _ASSERTE(pContextBufferRaw != NULL); - - DT_CONTEXT * pContextBuffer = reinterpret_cast(pContextBufferRaw); + DT_CONTEXT * pContextBuffer = reinterpret_cast(contextBuffer.pContextBytes); Thread * pThread = vmThread.GetDacPtr(); @@ -5701,23 +5704,22 @@ static UINT_PTR * GetRegisterSlotFromContext(BYTE * ctxBuf, CorDebugRegister reg } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::WriteRegistersToContext( - IN OUT BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values) { DD_ENTER_MAY_THROW; - if (ctxBuf == NULL || (nRegs > 0 && (regs == NULL || values == NULL))) + if (contextBuffer.pContextBytes == NULL || (nRegs > 0 && (regs == NULL || values == NULL))) return E_INVALIDARG; - if (cb < sizeof(DT_CONTEXT)) + if (contextBuffer.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; for (ULONG32 i = 0; i < nRegs; i++) { // Registers with no CONTEXT slot (e.g. float / SIMD registers) are skipped. - UINT_PTR * pSlot = GetRegisterSlotFromContext(ctxBuf, regs[i]); + UINT_PTR * pSlot = GetRegisterSlotFromContext(contextBuffer.pContextBytes, regs[i]); if (pSlot != NULL) *pSlot = (UINT_PTR)values[i]; } @@ -5725,23 +5727,22 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::WriteRegistersToContext( } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadRegistersFromContext( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues) { DD_ENTER_MAY_THROW; - if (ctxBuf == NULL || (nRegs > 0 && (regs == NULL || pValues == NULL))) + if (contextBuffer.pContextBytes == NULL || (nRegs > 0 && (regs == NULL || pValues == NULL))) return E_INVALIDARG; - if (cb < sizeof(DT_CONTEXT)) + if (contextBuffer.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; for (ULONG32 i = 0; i < nRegs; i++) { // Registers with no CONTEXT slot (e.g. float / SIMD registers) read as zero. - UINT_PTR * pSlot = GetRegisterSlotFromContext(ctxBuf, regs[i]); + UINT_PTR * pSlot = GetRegisterSlotFromContext(contextBuffer.pContextBytes, regs[i]); pValues[i] = (pSlot != NULL) ? (TADDR)*pSlot : (TADDR)0; } return S_OK; @@ -5871,68 +5872,63 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetAvailableRegistersMask( } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ContextHasExtendedRegisters( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; - if (ctxBuf == NULL || pResult == NULL) + if (contextBuffer.pContextBytes == NULL || pResult == NULL) return E_INVALIDARG; - if (cb < sizeof(DT_CONTEXT)) + if (contextBuffer.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; *pResult = FALSE; #if defined(DT_CONTEXT_EXTENDED_REGISTERS) - DT_CONTEXT * pCtx = (DT_CONTEXT *)ctxBuf; + DT_CONTEXT * pCtx = (DT_CONTEXT *)contextBuffer.pContextBytes; *pResult = (pCtx->ContextFlags & DT_CONTEXT_EXTENDED_REGISTERS) == DT_CONTEXT_EXTENDED_REGISTERS; #endif return S_OK; } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CompareControlRegisters( - IN const BYTE * ctxBuf1, - IN ULONG32 cb1, - IN const BYTE * ctxBuf2, - IN ULONG32 cb2, + IN ContextBuffer contextBuffer1, + IN ContextBuffer contextBuffer2, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; - if (ctxBuf1 == NULL || ctxBuf2 == NULL || pResult == NULL) + if (contextBuffer1.pContextBytes == NULL || contextBuffer2.pContextBytes == NULL || pResult == NULL) return E_INVALIDARG; - if (cb1 < sizeof(DT_CONTEXT) || cb2 < sizeof(DT_CONTEXT)) + if (contextBuffer1.contextSize < sizeof(DT_CONTEXT) || contextBuffer2.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; *pResult = ::CompareControlRegisters( - reinterpret_cast(ctxBuf1), - reinterpret_cast(ctxBuf2)); + reinterpret_cast(contextBuffer1.pContextBytes), + reinterpret_cast(contextBuffer2.pContextBytes)); return S_OK; } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CopyContext( - IN OUT BYTE * dstCtxBuf, - IN ULONG32 cbDst, - IN const BYTE * srcCtxBuf, - IN ULONG32 cbSrc, + IN ContextBuffer destinationContext, + IN ContextBuffer sourceContext, IN ULONG32 flags) { DD_ENTER_MAY_THROW; - if (dstCtxBuf == NULL || srcCtxBuf == NULL) + if (destinationContext.pContextBytes == NULL || sourceContext.pContextBytes == NULL) return E_INVALIDARG; - if (cbDst < sizeof(DT_CONTEXT) || cbSrc < sizeof(DT_CONTEXT)) + if (destinationContext.contextSize < sizeof(DT_CONTEXT) || sourceContext.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; // flags != 0 stamps the destination's ContextFlags before the copy, so the // chunk-wise copy below pulls exactly the requested pieces from the source. // flags == 0 preserves the destination's existing ContextFlags. if (flags != 0) - reinterpret_cast(dstCtxBuf)->ContextFlags = flags; + reinterpret_cast(destinationContext.pContextBytes)->ContextFlags = flags; CORDbgCopyThreadContext( - reinterpret_cast(dstCtxBuf), - reinterpret_cast(srcCtxBuf)); + reinterpret_cast(destinationContext.pContextBytes), + reinterpret_cast(sourceContext.pContextBytes)); return S_OK; } @@ -6053,8 +6049,7 @@ namespace } HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN ULONG32 maxValues, OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], OUT ULONG32 * pValuesCount, @@ -6063,15 +6058,15 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( { DD_ENTER_MAY_THROW; - if (ctxBuf == NULL || values == NULL || pValuesCount == NULL || + if (contextBuffer.pContextBytes == NULL || values == NULL || pValuesCount == NULL || pFirstFloatReg == NULL || pFloatStackTop == NULL || maxValues == 0) { return E_INVALIDARG; } - if (cb < sizeof(DT_CONTEXT)) + if (contextBuffer.contextSize < sizeof(DT_CONTEXT)) return E_INVALIDARG; - DT_CONTEXT * pCtx = reinterpret_cast(ctxBuf); + DT_CONTEXT * pCtx = reinterpret_cast(contextBuffer.pContextBytes); *pValuesCount = 0; *pFirstFloatReg = -1; diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index d93e8628b96498..be0b99febf12bf 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -153,13 +153,12 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize); - HRESULT STDMETHODCALLTYPE WriteRegistersToContext(IN OUT BYTE * ctxBuf, IN ULONG32 cb, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values); - HRESULT STDMETHODCALLTYPE ReadRegistersFromContext(IN BYTE * ctxBuf, IN ULONG32 cb, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues); + HRESULT STDMETHODCALLTYPE WriteRegistersToContext(IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values); + HRESULT STDMETHODCALLTYPE ReadRegistersFromContext(IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues); HRESULT STDMETHODCALLTYPE GetAvailableRegistersMask(IN BOOL fActive, IN BOOL fQuickUnwind, IN ULONG32 regCount, OUT BYTE pAvailable[]); HRESULT STDMETHODCALLTYPE ConvertJitRegNumToCorDebugRegister(IN ULONG32 jitRegNum, OUT CorDebugRegister * pReg); HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN ULONG32 regCount, OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], OUT ULONG32 * pValuesCount, @@ -168,11 +167,11 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); - HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters(IN BYTE * ctxBuf, IN ULONG32 cb, OUT BOOL * pResult); + HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters(IN ContextBuffer contextBuffer, OUT BOOL * pResult); - HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN const BYTE * ctxBuf1, IN ULONG32 cb1, IN const BYTE * ctxBuf2, IN ULONG32 cb2, OUT BOOL * pResult); + HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN ContextBuffer contextBuffer1, IN ContextBuffer contextBuffer2, OUT BOOL * pResult); - HRESULT STDMETHODCALLTYPE CopyContext(IN OUT BYTE * dstCtxBuf, IN ULONG32 cbDst, IN const BYTE * srcCtxBuf, IN ULONG32 cbSrc, IN ULONG32 flags); + HRESULT STDMETHODCALLTYPE CopyContext(IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags); private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, @@ -693,24 +692,23 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT VMPTR_CONTEXT * pRetVal); // Create and return a stackwalker on the specified thread. - HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle); + HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT StackWalkHandle * ppSFIHandle); // Delete the stackwalk object HRESULT STDMETHODCALLTYPE DeleteStackWalk(StackWalkHandle ppSFIHandle); // Get the CONTEXT of the current frame at which the stackwalker is stopped. - HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext); + HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, ContextBuffer contextBuffer); void GetStackWalkCurrentContext(StackFrameIterator * pIter, DT_CONTEXT * pContext); // Set the stackwalker to the specified CONTEXT. - HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContext); + HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, ContextBuffer contextBuffer); // Unwind the stackwalker to the next frame. HRESULT STDMETHODCALLTYPE UnwindStackWalkFrame(StackWalkHandle pSFIHandle, OUT BOOL * pResult); - HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, - const BYTE * pContext); + HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer); // Retrieve information about the current frame from the stackwalker. HRESULT STDMETHODCALLTYPE GetStackWalkCurrentFrameInfo(StackWalkHandle pSFIHandle, OPTIONAL Debugger_STRData * pFrameData, OUT FrameType * pRetVal); @@ -731,10 +729,10 @@ class DacDbiInterfaceImpl : // Return TRUE if the specified CONTEXT is the CONTEXT of the leaf frame. // @dbgtodo filter CONTEXT - Currently we check for the filter CONTEXT first. - HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContext, OUT BOOL * pResult); + HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT BOOL * pResult); // DacDbi API: Get the context for a particular thread of the target process - HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, BYTE * pContextBuffer); + HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer); // Check if the given method is a DiagnosticHidden or an LCG method. HRESULT STDMETHODCALLTYPE IsDiagnosticsHiddenOrLCGMethod(VMPTR_MethodDesc vmMethodDesc, OUT DynamicMethodType * pRetVal); diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index 192d5dcfa0cac5..f7d46bb9d2400e 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -109,10 +109,20 @@ T_CONTEXT * GetContextBufferFromHandle(StackWalkHandle pSFIHandle) // Create and return a stackwalker on the specified thread. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateStackWalk(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT StackWalkHandle * ppSFIHandle) { DD_ENTER_MAY_THROW; + if (ppSFIHandle == NULL) + { + return E_INVALIDARG; + } + *ppSFIHandle = NULL; + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; EX_TRY { @@ -131,13 +141,13 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateStackWalk(VMPTR_Thread vmTh // initialize the CONTEXT. // SetStackWalk will initial the RegDisplay from this context. - IfFailThrow(GetContext(vmThread, pInternalContextBuffer)); + IfFailThrow(GetContext(vmThread, contextBuffer)); // initialize the stackwalker IfFailThrow(SetStackWalkCurrentContext(vmThread, *ppSFIHandle, SET_CONTEXT_FLAG_ACTIVE_FRAME, - pInternalContextBuffer)); + contextBuffer)); } EX_CATCH_HRESULT(hr); return hr; @@ -156,17 +166,22 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::DeleteStackWalk(StackWalkHandle p } // Get the CONTEXT of the current frame at which the stackwalker is stopped. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, ContextBuffer contextBuffer) { DD_ENTER_MAY_THROW; + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; EX_TRY { StackFrameIterator * pIter = GetIteratorFromHandle(pSFIHandle); - GetStackWalkCurrentContext(pIter, reinterpret_cast(pContext)); + GetStackWalkCurrentContext(pIter, reinterpret_cast(contextBuffer.pContextBytes)); } EX_CATCH_HRESULT(hr); return hr; @@ -189,22 +204,27 @@ void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackFrameIterator * pIter, // Set the stackwalker to the specified CONTEXT. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContextBuffer) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, ContextBuffer contextBuffer) { DD_ENTER_MAY_THROW; + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; EX_TRY { - DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); + DT_CONTEXT * pContext = reinterpret_cast(contextBuffer.pContextBytes); StackFrameIterator * pIter = GetIteratorFromHandle(pSFIHandle); REGDISPLAY * pRD = GetRegDisplayFromHandle(pSFIHandle); #if defined(_DEBUG) // The caller should have checked this already. - _ASSERTE(CheckContext(vmThread, pContextBuffer) == S_OK); + _ASSERTE(CheckContext(vmThread, contextBuffer) == S_OK); #endif // _DEBUG // DD can't keep pointers back into the RS address space. @@ -343,13 +363,16 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::UnwindStackWalkFrame(StackWalkHan // Check whether the specified CONTEXT is valid. The only check we perform right now is whether the // SP in the specified CONTEXT is in the stack range of the thread. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CheckContext(VMPTR_Thread vmThread, - const BYTE * pContextBuffer) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CheckContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer) { DD_ENTER_MAY_THROW; - _ASSERTE(pContextBuffer != NULL); - const DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + + const DT_CONTEXT * pContext = reinterpret_cast(contextBuffer.pContextBytes); // If the SP in the CONTEXT isn't valid, then there's no point in checking. if ((pContext->ContextFlags & CONTEXT_CONTROL) == 0) @@ -727,15 +750,25 @@ FramePointer DacDbiInterfaceImpl::GetFramePointerWorker(StackFrameIterator * pIt } // Return TRUE if the specified CONTEXT is the CONTEXT of the leaf frame. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContextBuffer, OUT BOOL * pResult) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsLeafFrame(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT BOOL * pResult) { DD_ENTER_MAY_THROW; + if (pResult == NULL) + { + return E_INVALIDARG; + } + *pResult = FALSE; + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < sizeof(DT_CONTEXT))) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; EX_TRY { - const DT_CONTEXT * pContext = reinterpret_cast(pContextBuffer); + const DT_CONTEXT * pContext = reinterpret_cast(contextBuffer.pContextBytes); DT_CONTEXT ctxLeaf; Thread * pThread = vmThread.GetDacPtr(); diff --git a/src/coreclr/debug/di/cordbregisterset.cpp b/src/coreclr/debug/di/cordbregisterset.cpp index 3e187186252743..58a496ca1b52a7 100644 --- a/src/coreclr/debug/di/cordbregisterset.cpp +++ b/src/coreclr/debug/di/cordbregisterset.cpp @@ -72,7 +72,7 @@ namespace // into two batches: GPR bits are read in a single ReadRegistersFromContext // call, and float bits are served from the thread's float cache. HRESULT FillRegisters(IDacDbiInterface * pDAC, - BYTE * pContext, ULONG32 contextSize, + ContextBuffer contextBuffer, CordbThread * pThread, const BYTE * requestMask, ULONG32 requestMaskCount, const BYTE * availMask, ULONG32 availMaskCount, @@ -123,7 +123,7 @@ namespace if (gprCount > 0) { - hr = pDAC->ReadRegistersFromContext(pContext, contextSize, gprRegs, gprCount, gprValues); + hr = pDAC->ReadRegistersFromContext(contextBuffer, gprRegs, gprCount, gprValues); if (FAILED(hr)) return hr; } @@ -206,7 +206,8 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, requestBytes[b / 8] |= (BYTE)(1 << (b % 8)); } - return FillRegisters(pDAC, m_pContext, m_contextSize, m_thread, + ContextBuffer contextBuffer = { m_pContext, m_contextSize }; + return FillRegisters(pDAC, contextBuffer, m_thread, requestBytes, (ULONG32)sizeof(requestBytes), availBytes, kAvailMaskBytes, regCount, regBuffer); } @@ -237,7 +238,8 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], if (FAILED(hr)) return hr; - return FillRegisters(pDAC, m_pContext, m_contextSize, m_thread, + ContextBuffer contextBuffer = { m_pContext, m_contextSize }; + return FillRegisters(pDAC, contextBuffer, m_thread, mask, maskCount, availBytes, kAvailMaskBytes, regCount, regBuffer); } diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index b4d24f1e5ee4a2..7dec255c7e536b 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -1458,10 +1458,6 @@ void CordbProcess::FreeDac() ULONG32 CordbProcess::GetTargetContextSize() { - if (!IsDacInitialized()) - { - return sizeof(T_CONTEXT); - } if (m_ctxSize == 0) { ULONG32 size = 0; @@ -5812,10 +5808,9 @@ HRESULT CordbProcess::IsOSSuspended(DWORD threadID, BOOL *pbSuspended) // // This routine reads a thread context from the process being debugged, taking into account the fact that the context -// record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate -// space for the extended registers. However, the CONTEXT struct that we compile with does have this space. +// record may be a different size than the one we compiled with. // -HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, BYTE * pCtx) +HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, ContextBuffer contextBuffer) { HRESULT hr = S_OK; @@ -5824,9 +5819,13 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, BYTE * pCtx) EX_TRY { - void *pRemoteContext = pContext.UnsafeGet(); ULONG32 fullContextSize = GetTargetContextSize(); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < fullContextSize)) + { + ThrowHR(E_INVALIDARG); + } + TargetBuffer tbFull(pRemoteContext, fullContextSize); // The context may have 2 parts: @@ -5840,15 +5839,15 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, BYTE * pCtx) // Read the minimum part. TargetBuffer tbMin = tbFull.SubBuffer(0, minContextSize); - SafeReadBuffer(tbMin, (BYTE*) pCtx); + SafeReadBuffer(tbMin, contextBuffer.pContextBytes); if (fullContextSize > minContextSize) { - void *pCurExtReg = (void*)((UINT_PTR)pCtx + minContextSize); + void *pCurExtReg = (void*)((UINT_PTR)contextBuffer.pContextBytes + minContextSize); TargetBuffer tbExtended = tbFull.SubBuffer(minContextSize); BOOL hasExtendedRegisters = FALSE; - IfFailThrow(GetDAC()->ContextHasExtendedRegisters(pCtx, fullContextSize, &hasExtendedRegisters)); + IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); if (hasExtendedRegisters) { @@ -5866,25 +5865,29 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, BYTE * pCtx) // // This routine writes a thread context to the process being debugged, taking into account the fact that the context -// record may be a different size than the one we compiled with. On systems < NT5, then OS doesn't usually allocate -// space for the extended registers. However, the CONTEXT struct that we compile with does have this space. +// record may be a different size than the one we compiled with. // -HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, const BYTE * pCtx) +HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuffer contextBuffer) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < GetTargetContextSize())) + { + return E_INVALIDARG; + } + HRESULT hr = S_OK; ULONG32 sizeToWrite; BOOL hasExtendedRegisters = FALSE; - IfFailThrow(GetDAC()->ContextHasExtendedRegisters(const_cast(pCtx), GetTargetContextSize(), &hasExtendedRegisters)); + IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); IfFailThrow(GetDAC()->GetTargetContextSize( hasExtendedRegisters ? IDacDbiInterface::kContextSizeExtendedRegisters : IDacDbiInterface::kContextSizeBase, &sizeToWrite)); IDacDbiInterface::TargetInfo targetInfo; BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); - BYTE * pCtxSource = (BYTE*) pCtx; + BYTE * pCtxSource = contextBuffer.pContextBytes; IfFailThrow(GetDAC()->GetTargetInfo(&targetInfo)); // 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that @@ -5992,9 +5995,13 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE } else { - BYTE * managedContext = NULL; + ContextBuffer managedContext = {}; IfFailThrow(thread->GetManagedContext(&managedContext)); - memcpy(context, managedContext, GetTargetContextSize()); + if (managedContext.contextSize > contextSize) + { + ThrowHR(E_INVALIDARG); + } + memcpy(context, managedContext.pContextBytes, managedContext.contextSize); } } EX_CATCH_HRESULT(hr) @@ -6079,7 +6086,8 @@ HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE hr = E_INVALIDARG; } - hr = thread->SetManagedContext(context, contextSize); + ContextBuffer contextBuffer = { context, contextSize }; + hr = thread->SetManagedContext(contextBuffer); } EX_CATCH { diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index 80deae052891e7..6cdeeb863209a9 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -3583,8 +3583,8 @@ class CordbProcess : void AddToLeftSideResourceCleanupList(CordbBase * pObject); // Routines to read and write thread context records between the processes safely. - HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, BYTE * pCtx); - HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, const BYTE * pCtx); + HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, ContextBuffer contextBuffer); + HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, ContextBuffer contextBuffer); HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, T_CONTEXT * pCtx); #ifdef FEATURE_INTEROP_DEBUGGING @@ -6126,8 +6126,8 @@ class CordbThread : public CordbBase, public ICorDebugThread, // // ////////////////////////////////////////////////////////////////////////// - HRESULT GetManagedContext(BYTE ** ppContext); - HRESULT SetManagedContext(BYTE * pContext, ULONG32 cbCtx); + HRESULT GetManagedContext(ContextBuffer * pContextBuffer); + HRESULT SetManagedContext(ContextBuffer contextBuffer); // API to retrieve the thread handle from the LS. void InternalGetHandle(HANDLE * phThread); @@ -6170,8 +6170,7 @@ class CordbThread : public CordbBase, public ICorDebugThread, BOOL IsThreadExceptionManaged(); // This is a private hook for the shim to create a CordbRegisterSet for a ShimChain. - void CreateCordbRegisterSet(const BYTE * pContext, - ULONG32 contextSize, + void CreateCordbRegisterSet(ContextBuffer contextBuffer, BOOL fActive, CorDebugChainReason reason, ICorDebugRegisterSet ** ppRegSet); @@ -6668,7 +6667,7 @@ class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUn CordbRuntimeUnwindableFrame(CordbThread * pThread, FramePointer fp, CordbAppDomain * pCurrentAppDomain, - BYTE * pContext); + ContextBuffer contextBuffer); virtual void Neuter(); @@ -6841,7 +6840,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public TADDR addrAmbientESP, CordbAppDomain * pCurrentAppDomain, CordbMiscFrame * pMisc = NULL, - BYTE * pContext = NULL); + ContextBuffer contextBuffer = {}); virtual ~CordbNativeFrame(); virtual void Neuter(); @@ -7052,8 +7051,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public ICorDebugRegisterSet2 { public: - CordbRegisterSet(const BYTE * pContextBuffer, - ULONG32 contextSize, + CordbRegisterSet(ContextBuffer contextBuffer, CordbThread * pThread, bool fActive, bool fQuickUnwind, @@ -7706,7 +7704,7 @@ class EnregisteredValueHome // set a remote enregistered location to a new value // Arguments: // input: pNewValue - buffer containing the new value along with its size - // pContext - context from which the value comes + // contextBuffer - context from which the value comes // fIsSigned - indicates whether the value is signed or not. The value provided may be smaller than // a register, in which case we'll need to extend it to a full register width. To do this // correctly, we need to know whether to sign extend or zero extend. Currently, only @@ -7716,7 +7714,7 @@ class EnregisteredValueHome // Note: Throws E_FAIL for invalid input or various HRESULTs from an // unsuccessful call to WriteProcessMemory virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) = 0; + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) = 0; // Gets an enregistered value and returns it to the caller // Arguments: @@ -7785,13 +7783,13 @@ class RegValueHome: public EnregisteredValueHome virtual RegValueHome * Clone() const { return new RegValueHome(*this); }; - void SetContextRegister(BYTE * pContext, + void SetContextRegister(ContextBuffer contextBuffer, CorDebugRegister regNum, SIZE_T newVal); // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -7860,7 +7858,7 @@ class RegRegValueHome: public RegValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -7917,7 +7915,7 @@ class RegAndMemBaseValueHome: public RegValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) = 0; + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) = 0; // Gets an enregistered value and returns it to the caller virtual @@ -7975,7 +7973,7 @@ class RegMemValueHome: public RegAndMemBaseValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -8025,7 +8023,7 @@ class MemRegValueHome: public RegAndMemBaseValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual @@ -8070,7 +8068,7 @@ class FloatRegValueHome: public EnregisteredValueHome // set the value of a remote enregistered value virtual - void SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned); + void SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned); // Gets an enregistered value and returns it to the caller virtual diff --git a/src/coreclr/debug/di/rsregsetcommon.cpp b/src/coreclr/debug/di/rsregsetcommon.cpp index 25646efbd320ed..7ed399f62946a8 100644 --- a/src/coreclr/debug/di/rsregsetcommon.cpp +++ b/src/coreclr/debug/di/rsregsetcommon.cpp @@ -19,19 +19,22 @@ CordbRegisterSet::CordbRegisterSet( - const BYTE * pContextBuffer, - ULONG32 contextSize, + ContextBuffer contextBuffer, CordbThread * pThread, bool fActive, bool fQuickUnwind, bool fTakeOwnershipOfContext /*= false*/) : CordbBase(pThread->GetProcess(), 0, enumCordbRegisterSet) { - _ASSERTE( pContextBuffer != NULL ); - _ASSERTE( pThread != NULL ); + _ASSERTE(pThread != NULL); + if ((contextBuffer.pContextBytes == NULL) || + (contextBuffer.contextSize < pThread->GetProcess()->GetTargetContextSize())) + { + ThrowHR(E_INVALIDARG); + } - m_pContext = const_cast(pContextBuffer); - m_contextSize = contextSize; + m_pContext = contextBuffer.pContextBytes; + m_contextSize = contextBuffer.contextSize; m_fOwnsContext = fTakeOwnershipOfContext; m_thread = pThread; m_active = fActive; @@ -131,31 +134,38 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) IDacDbiInterface * pDAC = GetProcess()->GetDAC(); ULONG32 targetContextSize = GetProcess()->GetTargetContextSize(); - BYTE * pLeafContext = NULL; + ContextBuffer leafContext = {}; if (m_active) { EX_TRY { // This may fail, but it is not a disastrous failure in this case. All we care is whether - // pLeafContext is updated to a non-NULL value. - m_thread->GetManagedContext( &pLeafContext); + // leafContext is updated to contain a non-NULL value. + m_thread->GetManagedContext(&leafContext); } EX_CATCH { } EX_END_CATCH - if (pLeafContext != NULL) + if (leafContext.pContextBytes != NULL) { + if (leafContext.contextSize < targetContextSize) + { + ThrowHR(E_INVALIDARG); + } + // Raw byte copy of the leaf context, which carries the leaf's ContextFlags into the // destination so the flag-sensitive overlay below is gated on those flags. - memcpy( context, pLeafContext, targetContextSize); + memcpy(context, leafContext.pContextBytes, targetContextSize); } } // Overlay this frame's registers from the cached CONTEXT buffer, honoring the destination's // ContextFlags (the leaf's if copied above, otherwise the caller's incoming flags). - IfFailThrow(pDAC->CopyContext(context, contextSize, m_pContext, m_contextSize, 0)); + ContextBuffer destinationContext = { context, contextSize }; + ContextBuffer sourceContext = { m_pContext, m_contextSize }; + IfFailThrow(pDAC->CopyContext(destinationContext, sourceContext, 0)); } EX_CATCH_HRESULT(hr); return hr; diff --git a/src/coreclr/debug/di/rsstackwalk.cpp b/src/coreclr/debug/di/rsstackwalk.cpp index 7afb47a77e6616..5645125afa3181 100644 --- a/src/coreclr/debug/di/rsstackwalk.cpp +++ b/src/coreclr/debug/di/rsstackwalk.cpp @@ -35,11 +35,13 @@ void CordbStackWalk::Init() m_lastSyncFlushCounter = pProcess->m_flushCounter; IDacDbiInterface * pDAC = pProcess->GetDAC(); - m_pContextBuffer = new BYTE[pProcess->GetTargetContextSize()]; + ULONG32 contextSize = pProcess->GetTargetContextSize(); + m_pContextBuffer = new BYTE[contextSize]; + ContextBuffer contextBuffer = { m_pContextBuffer, contextSize }; IfFailThrow(pDAC->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - m_pContextBuffer, - &m_pSFIHandle)); + contextBuffer, + &m_pSFIHandle)); // see the function header of code:CordbStackWalk::CheckForLegacyHijackCase CheckForLegacyHijackCase(); @@ -80,10 +82,11 @@ void CordbStackWalk::CheckForLegacyHijackCase() T_CONTEXT * pContext = reinterpret_cast(m_pContextBuffer.GetValue()); pContext->ContextFlags = CONTEXT_FULL; pUT->GetThreadContext(pContext); + ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, SET_CONTEXT_FLAG_ACTIVE_FRAME, - m_pContextBuffer)); + contextBuffer)); } } } @@ -206,9 +209,10 @@ void CordbStackWalk::RefreshIfNeeded() DeleteAll(); // create a new stackwalk handle + ContextBuffer contextBuffer = { m_pContextBuffer, pProcess->GetTargetContextSize() }; IfFailThrow(pProcess->GetDAC()->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - m_pContextBuffer, - &m_pSFIHandle)); + contextBuffer, + &m_pSFIHandle)); // advance the stackwalker to where we originally were SetContextWorker(m_cachedSetContextFlag, pProcess->GetTargetContextSize(), ctx); @@ -287,9 +291,9 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, // We always store the current CONTEXT, so just copy it into the buffer. // Stamp the requested contextFlags on the destination so the copy // pulls exactly those chunks from the source. - IfFailThrow(pDAC->CopyContext(pbContextBuf, contextBufSize, - m_pContextBuffer, GetProcess()->GetTargetContextSize(), - contextFlags)); + ContextBuffer destinationContext = { pbContextBuf, contextBufSize }; + ContextBuffer sourceContext = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; + IfFailThrow(pDAC->CopyContext(destinationContext, sourceContext, contextFlags)); } } } @@ -348,16 +352,19 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte NewArrayHolder tmpCtx(new BYTE[cbCtx]); memcpy(tmpCtx, m_pContextBuffer, cbCtx); // flags == 0: tmpCtx already carries the desired ContextFlags (copied above). - IfFailThrow(pDAC->CopyContext(tmpCtx, cbCtx, context, contextSize, 0)); - IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, tmpCtx)); + ContextBuffer temporaryContext = { tmpCtx, cbCtx }; + ContextBuffer sourceContext = { context, contextSize }; + IfFailThrow(pDAC->CopyContext(temporaryContext, sourceContext, 0)); + IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, temporaryContext)); memcpy(m_pContextBuffer, tmpCtx, cbCtx); m_cachedSetContextFlag = flag; + ContextBuffer currentContext = { m_pContextBuffer, cbCtx }; IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, flag, - m_pContextBuffer)); + currentContext)); } //--------------------------------------------------------------------------------------- @@ -383,7 +390,10 @@ BOOL CordbStackWalk::UnwindStackFrame() // Now that we have unwound, make sure we update the CONTEXT buffer to reflect the current stack frame. if (retVal) - IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, m_pContextBuffer)); + { + ContextBuffer contextBuffer = { m_pContextBuffer, pProcess->GetTargetContextSize() }; + IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, contextBuffer)); + } return retVal; } // CordbStackWalk::UnwindStackWalkFrame @@ -583,6 +593,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) // initialize the auxiliary info required for funclets CordbMiscFrame miscFrame(pJITFuncData); + ContextBuffer contextBuffer = { frameCtx, GetProcess()->GetTargetContextSize() }; // Create the native frame. CordbNativeFrame* pNativeFrame = new CordbNativeFrame(m_pCordbThread, @@ -592,7 +603,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) (TADDR)frameData.v.taAmbientESP, pCurrentAppDomain, &miscFrame, - frameCtx); + contextBuffer); pResultFrame.Assign(static_cast(pNativeFrame)); @@ -714,11 +725,12 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) // to the frame when we create it so we can properly resolve locals in that frame later. CordbAppDomain * pCurrentAppDomain = GetProcess()->GetAppDomain(); _ASSERTE(pCurrentAppDomain != NULL); + ContextBuffer contextBuffer = { frameCtx, GetProcess()->GetTargetContextSize() }; CordbRuntimeUnwindableFrame * pRuntimeFrame = new CordbRuntimeUnwindableFrame(m_pCordbThread, FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(frameData.fp)), pCurrentAppDomain, - frameCtx); + contextBuffer); pResultFrame.Assign(static_cast(pRuntimeFrame)); diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index d0afd8550901e4..1738f9cba88fe8 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -293,7 +293,7 @@ BOOL CordbThread::IsThreadExceptionManaged() // This is a private hook for the shim to create a CordbRegisterSet for a ShimChain. // // Arguments: -// * pContext - the CONTEXT to be converted; this must be the leaf CONTEXT of a chain +// * contextBuffer - the CONTEXT to be converted; this must be the leaf CONTEXT of a chain // * fLeaf - whether the chain is the leaf chain or not // * reason - the chain reason; this is needed for legacy reasons (see below) // * ppRegSet - out parameter; return the newly created ICDRegisterSet @@ -304,8 +304,7 @@ BOOL CordbThread::IsThreadExceptionManaged() // chain reason. // -void CordbThread::CreateCordbRegisterSet(const BYTE * pContext, - ULONG32 contextSize, +void CordbThread::CreateCordbRegisterSet(ContextBuffer contextBuffer, BOOL fLeaf, CorDebugChainReason reason, ICorDebugRegisterSet ** ppRegSet) @@ -319,15 +318,20 @@ void CordbThread::CreateCordbRegisterSet(const BYTE * pContext, PUBLIC_REENTRANT_API_ENTRY_FOR_SHIM(GetProcess()); IfFailThrow(EnsureThreadIsAlive()); + ULONG32 expectedContextSize = GetProcess()->GetTargetContextSize(); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < expectedContextSize)) + { + ThrowHR(E_INVALIDARG); + } // Allocate and populate a CONTEXT buffer that the CordbRegisterSet will own. // The caller passes the target's CONTEXT size (queried from the DAC). - NewArrayHolder pContextBuffer(new BYTE[contextSize]); - memcpy(pContextBuffer, pContext, contextSize); + NewArrayHolder pContextBuffer(new BYTE[expectedContextSize]); + memcpy(pContextBuffer, contextBuffer.pContextBytes, expectedContextSize); // create the CordbRegisterSet - RSInitHolder pRS(new CordbRegisterSet(pContextBuffer, - contextSize, + ContextBuffer registerContext = { pContextBuffer, expectedContextSize }; + RSInitHolder pRS(new CordbRegisterSet(registerContext, this, (fLeaf == TRUE), (reason == CHAIN_ENTER_MANAGED), @@ -1155,8 +1159,8 @@ HRESULT CordbThread::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters) IfFailThrow(pSW->GetContext(CONTEXT_FULL, contextSize, NULL, pContextBuffer)); // create the CordbRegisterSet - RSInitHolder pRS(new CordbRegisterSet(pContextBuffer, - contextSize, + ContextBuffer contextBuffer = { pContextBuffer, contextSize }; + RSInitHolder pRS(new CordbRegisterSet(contextBuffer, this, true, // active false, // !fQuickUnwind @@ -1435,14 +1439,14 @@ void CordbThread::LoadFloatState() IDacDbiInterface * pDAC = GetProcess()->GetDAC(); ULONG32 cbContext = GetProcess()->GetTargetContextSize(); NewArrayHolder contextBuf(new BYTE[cbContext]); - IfFailThrow(pDAC->GetContext(m_vmThreadToken, contextBuf)); + ContextBuffer contextBuffer = { contextBuf, cbContext }; + IfFailThrow(pDAC->GetContext(m_vmThreadToken, contextBuffer)); ULONG32 valuesCount = 0; int firstFloatReg = -1; ULONG32 floatStackTop = 0; IfFailThrow(pDAC->ReadFloatRegistersFromContext( - contextBuf, - cbContext, + contextBuffer, CORDB_MAX_FLOAT_REGISTERS, m_floatValues, &valuesCount, @@ -1540,17 +1544,18 @@ HRESULT CordbThread::SetIP(bool fCanSetIPOnly, // Get the context from a thread in managed code. // This thread should be stopped gracefully by the LS in managed code. -HRESULT CordbThread::GetManagedContext(BYTE ** ppContext) +HRESULT CordbThread::GetManagedContext(ContextBuffer * pContextBuffer) { FAIL_IF_NEUTERED(this); INTERNAL_SYNC_API_ENTRY(GetProcess()); - if (ppContext == NULL) + if (pContextBuffer == NULL) { ThrowHR(E_INVALIDARG); } - *ppContext = NULL; + pContextBuffer->pContextBytes = NULL; + pContextBuffer->contextSize = 0; ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); // Each CordbThread object allocates m_pContext only once, the first time @@ -1580,8 +1585,8 @@ HRESULT CordbThread::GetManagedContext(BYTE ** ppContext) // The thread we're examining IS handling an exception, So grab the CONTEXT of the exception, NOT the // currently executing thread's CONTEXT (which would be the context of the exception handler.) - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), - m_pContext.GetValue()); + ContextBuffer managedContext = { m_pContext.GetValue(), GetProcess()->GetTargetContextSize() }; + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), managedContext); IfFailThrow(hr); } @@ -1590,17 +1595,19 @@ HRESULT CordbThread::GetManagedContext(BYTE ** ppContext) } _ASSERTE(SUCCEEDED(hr)); - (*ppContext) = m_pContext; + pContextBuffer->pContextBytes = m_pContext; + pContextBuffer->contextSize = GetProcess()->GetTargetContextSize(); return hr; } -HRESULT CordbThread::SetManagedContext(BYTE * pContext, ULONG32 cbCtx) +HRESULT CordbThread::SetManagedContext(ContextBuffer contextBuffer) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); - if (pContext == NULL) + ULONG32 contextSize = GetProcess()->GetTargetContextSize(); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < contextSize)) { ThrowHR(E_INVALIDARG); } @@ -1623,16 +1630,15 @@ HRESULT CordbThread::SetManagedContext(BYTE * pContext, ULONG32 cbCtx) // // Note: we read the remote context and merge the new one in, then write it back. This ensures that we don't // write too much information into the remote process. - NewArrayHolder tempContext(new BYTE[GetProcess()->GetTargetContextSize()]); - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), tempContext); + NewArrayHolder tempContext(new BYTE[contextSize]); + ContextBuffer temporaryContext = { tempContext, contextSize }; + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), temporaryContext); IfFailThrow(hr); // flags == 0: tempContext already carries the target's ContextFlags (read above). - IfFailThrow(GetProcess()->GetDAC()->CopyContext( - tempContext.GetValue(), GetProcess()->GetTargetContextSize(), - pContext, cbCtx, 0)); + IfFailThrow(GetProcess()->GetDAC()->CopyContext(temporaryContext, contextBuffer, 0)); - hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), tempContext.GetValue()); + hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), temporaryContext); IfFailThrow(hr); // @todo - who's updating the regdisplay to guarantee that's in sync w/ our new context? @@ -1641,7 +1647,7 @@ HRESULT CordbThread::SetManagedContext(BYTE * pContext, ULONG32 cbCtx) _ASSERTE(SUCCEEDED(hr)); if (m_fContextFresh && (m_pContext != NULL)) { - memcpy(m_pContext, pContext, cbCtx); + memcpy(m_pContext, contextBuffer.pContextBytes, contextSize); } return hr; @@ -3269,8 +3275,9 @@ HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) // Read the context into a temp context then copy to the out param. T_CONTEXT tempContext = { 0 }; + ContextBuffer contextBuffer = { reinterpret_cast(&tempContext), sizeof(tempContext) }; - hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, reinterpret_cast(&tempContext)); + hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, contextBuffer); if (SUCCEEDED(hr)) CORDbgCopyThreadContext(pContext, &tempContext); @@ -4474,9 +4481,9 @@ HRESULT CordbFrame::ReadContextRegister(CorDebugRegister reg, TADDR * pValue) co return E_POINTER; IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + ContextBuffer contextBuffer = { const_cast(GetContext()), GetProcess()->GetTargetContextSize() }; return pDAC->ReadRegistersFromContext( - const_cast(GetContext()), - GetProcess()->GetTargetContextSize(), + contextBuffer, ®, 1, pValue); @@ -5091,12 +5098,17 @@ HRESULT CordbInternalFrame::IsCloserToLeaf(ICorDebugFrame * pFrameToCompare, CordbRuntimeUnwindableFrame::CordbRuntimeUnwindableFrame(CordbThread * pThread, FramePointer fp, CordbAppDomain * pCurrentAppDomain, - BYTE * pContext) + ContextBuffer contextBuffer) : CordbFrame(pThread, fp, 0, pCurrentAppDomain) { - ULONG32 contextSize = pThread->GetProcess()->GetTargetContextSize(); - m_pContextBuffer = new BYTE[contextSize]; - memcpy(m_pContextBuffer, pContext, contextSize); + ULONG32 expectedContextSize = pThread->GetProcess()->GetTargetContextSize(); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < expectedContextSize)) + { + ThrowHR(E_INVALIDARG); + } + + m_pContextBuffer = new BYTE[expectedContextSize]; + memcpy(m_pContextBuffer, contextBuffer.pContextBytes, expectedContextSize); } void CordbRuntimeUnwindableFrame::Neuter() @@ -5170,7 +5182,7 @@ CordbNativeFrame::CordbNativeFrame(CordbThread * pThread, TADDR taAmbientESP, CordbAppDomain * pCurrentAppDomain, CordbMiscFrame * pMisc /*= NULL*/, - BYTE * pContext /*= NULL*/) + ContextBuffer contextBuffer /*= {}*/) : CordbFrame(pThread, fp, ip, pCurrentAppDomain), m_JITILFrame(NULL), m_nativeCode(pNativeCode), // implicit InternalAddRef @@ -5179,10 +5191,14 @@ CordbNativeFrame::CordbNativeFrame(CordbThread * pThread, m_misc = *pMisc; // Only new CordbNativeFrames created by the new stackwalk contain a CONTEXT. - _ASSERTE(pContext != NULL); - ULONG32 contextSize = GetProcess()->GetTargetContextSize(); - m_pContextBuffer = new BYTE[contextSize]; - memcpy(m_pContextBuffer, pContext, contextSize); + ULONG32 expectedContextSize = GetProcess()->GetTargetContextSize(); + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < expectedContextSize)) + { + ThrowHR(E_INVALIDARG); + } + + m_pContextBuffer = new BYTE[expectedContextSize]; + memcpy(m_pContextBuffer, contextBuffer.pContextBytes, expectedContextSize); } /* @@ -5554,8 +5570,8 @@ HRESULT CordbNativeFrame::GetRegisterSet(ICorDebugRegisterSet **ppRegisters) EX_TRY { // allocate a new CordbRegisterSet object - RSInitHolder pRegisterSet(new CordbRegisterSet(m_pContextBuffer, - GetProcess()->GetTargetContextSize(), + ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; + RSInitHolder pRegisterSet(new CordbRegisterSet(contextBuffer, m_pThread, IsLeafFrame(), false)); @@ -6385,9 +6401,11 @@ bool CordbNativeFrame::IsLeafFrame() const // check if the leaf frame in the leaf chain is "this" BOOL fSameControlRegisters = FALSE; ULONG32 cbContext = GetProcess()->GetTargetContextSize(); + ContextBuffer thisContext = { const_cast(GetContext()), cbContext }; + ContextBuffer nativeFrameContext = { const_cast(pNFrame->GetContext()), cbContext }; IfFailThrow(GetProcess()->GetDAC()->CompareControlRegisters( - GetContext(), cbContext, - pNFrame->GetContext(), cbContext, + thisContext, + nativeFrameContext, &fSameControlRegisters)); if (fSameControlRegisters) { @@ -6406,7 +6424,11 @@ bool CordbNativeFrame::IsLeafFrame() const { IDacDbiInterface * pDAC = GetProcess()->GetDAC(); BOOL isLeaf; - IfFailThrow(pDAC->IsLeafFrame(m_pThread->m_vmThreadToken, m_pContextBuffer, &isLeaf)); + ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; + IfFailThrow(pDAC->IsLeafFrame( + m_pThread->m_vmThreadToken, + contextBuffer, + &isLeaf)); m_optfIsLeafFrame = (isLeaf == TRUE); } } diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index dfe88b71972087..293caca13f283b 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -792,7 +792,7 @@ class ShimStackWalk void Clear(); // Get a FramePointer to mark the root boundary of a chain. - FramePointer GetFramePointerForChain(const BYTE * pContext); + FramePointer GetFramePointerForChain(ContextBuffer contextBuffer); FramePointer GetFramePointerForChain(ICorDebugInternalFrame2 * pInternalFrame2); CorDebugInternalFrameType GetInternalFrameType(ICorDebugInternalFrame2 * pFrame2); @@ -803,14 +803,14 @@ class ShimStackWalk // Append a chain to the array. void AppendChainWorker(StackWalkInfo * pStackWalkInfo, - const BYTE * pLeafContext, + ContextBuffer contextBuffer, FramePointer fpRoot, CorDebugChainReason chainReason, BOOL fIsManagedChain); void AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWalkInfo); // Save information on the ChainInfo regarding the current chain. - void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, BYTE * pContext); + void SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, ContextBuffer contextBuffer); // Check what we are process next, a internal frame or a stack frame. BOOL CheckInternalFrame(ICorDebugFrame * pNextStackFrame, @@ -858,7 +858,7 @@ class ShimChain : public ICorDebugChain { public: ShimChain(ShimStackWalk * pSW, - const BYTE * pContext, + ContextBuffer contextBuffer, FramePointer fpRoot, UINT32 chainIndex, UINT32 frameStartIndex, @@ -1065,4 +1065,3 @@ class ShimFrameEnum : public ICorDebugFrameEnum #endif // SHIMPRIV_H - diff --git a/src/coreclr/debug/di/shimstackwalk.cpp b/src/coreclr/debug/di/shimstackwalk.cpp index bea50835f30566..8d2e6bdcf0241e 100644 --- a/src/coreclr/debug/di/shimstackwalk.cpp +++ b/src/coreclr/debug/di/shimstackwalk.cpp @@ -25,15 +25,13 @@ static const ULONG32 MAX_MASK_COUNT = (REGISTER_AMD64_MAX + 7) >> 3; namespace { TADDR ReadCtxReg(CordbThread * pThread, - const BYTE * pCtx, - ULONG32 ctxSize, + ContextBuffer contextBuffer, CorDebugRegister reg) { TADDR value = 0; IDacDbiInterface * pDAC = pThread->GetProcess()->GetDAC(); IfFailThrow(pDAC->ReadRegistersFromContext( - const_cast(pCtx), - ctxSize, + contextBuffer, ®, 1, &value)); @@ -380,7 +378,8 @@ void ShimStackWalk::Populate() { // If we have hit any managed stack frame, then we may need to send // an enter-managed chain later. Save the CONTEXT now. - SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafManagedContext()); + ContextBuffer contextBuffer = { chainInfo.GetLeafManagedContext(), chainInfo.m_contextSize }; + SaveChainContext(pSW, &chainInfo, contextBuffer); chainInfo.m_fNeedEnterManagedChain = true; } @@ -435,7 +434,8 @@ void ShimStackWalk::Populate() // we have exhausted all the stack frames. // We need to save the CONTEXT to start tracking an unmanaged chain. - SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafNativeContext()); + ContextBuffer contextBuffer = { chainInfo.GetLeafNativeContext(), chainInfo.m_contextSize }; + SaveChainContext(pSW, &chainInfo, contextBuffer); chainInfo.m_fLeafNativeContextIsValid = true; // begin tracking UM chain if we're supposed to @@ -978,10 +978,10 @@ void ShimStackWalk::GetCalleeForFrame(ICorDebugFrame * pFrame, ICorDebugFrame ** } } -FramePointer ShimStackWalk::GetFramePointerForChain(const BYTE * pContext) +FramePointer ShimStackWalk::GetFramePointerForChain(ContextBuffer contextBuffer) { CordbThread * pThread = static_cast(m_pThread.GetValue()); - TADDR sp = ReadCtxReg(pThread, pContext, GetContextSize(), REGISTER_STACK_POINTER); + TADDR sp = ReadCtxReg(pThread, contextBuffer, REGISTER_STACK_POINTER); return FramePointer::MakeFramePointer(reinterpret_cast(sp)); } @@ -1076,14 +1076,14 @@ void ShimStackWalk::AppendFrame(ICorDebugInternalFrame2 * pInternalFrame2, Stack // void ShimStackWalk::AppendChainWorker(StackWalkInfo * pStackWalkInfo, - const BYTE * pLeafContext, + ContextBuffer contextBuffer, FramePointer fpRoot, CorDebugChainReason chainReason, BOOL fIsManagedChain) { // first, create the chain NewHolder pChain(new ShimChain(this, - pLeafContext, + contextBuffer, fpRoot, pStackWalkInfo->m_cChain, pStackWalkInfo->m_firstFrameInChain, @@ -1145,9 +1145,9 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // We need to send an extra enter-managed chain. _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); CordbThread * pThread = static_cast(m_pThread.GetValue()); + ContextBuffer nativeContext = { pChainInfo->GetLeafNativeContext(), GetContextSize() }; BYTE * sp = reinterpret_cast( - ReadCtxReg(pThread, pChainInfo->GetLeafNativeContext(), GetContextSize(), - REGISTER_STACK_POINTER)); + ReadCtxReg(pThread, nativeContext, REGISTER_STACK_POINTER)); #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) // Dev11 324806: on ARM we use the caller's SP for a frame's ending delimiter so we cannot // subtract 4 bytes from the chain's ending delimiter else the frame might never be in range. @@ -1156,8 +1156,9 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa #endif FramePointer fp = FramePointer::MakeFramePointer(sp); + ContextBuffer managedContext = { pChainInfo->GetLeafManagedContext(), pChainInfo->m_contextSize }; AppendChainWorker(pStackWalkInfo, - pChainInfo->GetLeafManagedContext(), + managedContext, fp, CHAIN_ENTER_MANAGED, TRUE); @@ -1169,8 +1170,9 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa } // Add the actual chain. + ContextBuffer chainContext = { const_cast(pChainContext), pChainInfo->m_contextSize }; AppendChainWorker(pStackWalkInfo, - pChainContext, + chainContext, pChainInfo->m_rootFP, pChainInfo->m_reason, fManagedChain); @@ -1186,18 +1188,23 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // Arguments: // * pSW - the ICDStackWalk for the current stackwalk // * pChainInfo - the ChainInfo keeping track of the current chain -// * pContext - the destination CONTEXT +// * contextBuffer - the destination CONTEXT // -void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, BYTE * pContext) +void ShimStackWalk::SaveChainContext(ICorDebugStackWalk * pSW, ChainInfo * pChainInfo, ContextBuffer contextBuffer) { + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < GetContextSize())) + { + ThrowHR(E_INVALIDARG); + } + HRESULT hr = pSW->GetContext(CONTEXT_FULL, - GetContextSize(), + contextBuffer.contextSize, NULL, - pContext); + contextBuffer.pContextBytes); IfFailThrow(hr); - pChainInfo->m_rootFP = GetFramePointerForChain(pContext); + pChainInfo->m_rootFP = GetFramePointerForChain(contextBuffer); } // ---------------------------------------------------------------------------- @@ -1259,8 +1266,9 @@ BOOL ShimStackWalk::CheckInternalFrame(ICorDebugFrame * pNextStackFrame, // Get the SP from the CONTEXT. This is the caller SP. CordbThread * pThread = static_cast(m_pThread.GetValue()); + ContextBuffer contextBuffer = { ctx, ctxSize }; CORDB_ADDRESS sp = PTR_TO_CORDB_ADDRESS( - ReadCtxReg(pThread, ctx, ctxSize, REGISTER_STACK_POINTER)); + ReadCtxReg(pThread, contextBuffer, REGISTER_STACK_POINTER)); // get the frame address CORDB_ADDRESS frameAddr = 0; @@ -1459,7 +1467,8 @@ void ShimStackWalk::TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackW { // check whether we get any stack range _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); - FramePointer fpLeaf = GetFramePointerForChain(pChainInfo->GetLeafNativeContext()); + ContextBuffer contextBuffer = { pChainInfo->GetLeafNativeContext(), pChainInfo->m_contextSize }; + FramePointer fpLeaf = GetFramePointerForChain(contextBuffer); // Don't bother creating an unmanaged chain if the stack range is empty. if (fpLeaf != pChainInfo->m_rootFP) @@ -1603,7 +1612,7 @@ BOOL ShimStackWalk::StackWalkInfo::HasConvertedFrame() ShimChain::ShimChain(ShimStackWalk * pSW, - const BYTE * pContext, + ContextBuffer contextBuffer, FramePointer fpRoot, UINT32 chainIndex, UINT32 frameStartIndex, @@ -1623,9 +1632,14 @@ ShimChain::ShimChain(ShimStackWalk * pSW, m_fIsNeutered(FALSE), m_pShimLock(pShimLock) { + if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < m_contextSize)) + { + ThrowHR(E_INVALIDARG); + } + // Own a copy of the leaf CONTEXT as an opaque target-sized byte buffer. m_pContext = new BYTE[m_contextSize]; - memcpy(m_pContext, pContext, m_contextSize); + memcpy(m_pContext, contextBuffer.pContextBytes, m_contextSize); } ShimChain::~ShimChain() @@ -1712,8 +1726,9 @@ HRESULT ShimChain::GetStackRange(CORDB_ADDRESS * pStart, CORDB_ADDRESS * pEnd) if (pStart) { CordbThread * pThread = static_cast(m_pStackWalk->GetThread()); + ContextBuffer contextBuffer = { m_pContext, m_contextSize }; *pStart = PTR_TO_CORDB_ADDRESS( - ReadCtxReg(pThread, m_pContext, m_contextSize, REGISTER_STACK_POINTER)); + ReadCtxReg(pThread, contextBuffer, REGISTER_STACK_POINTER)); } // Return the rootmost end of the stack range. It is represented by the frame pointer of the chain. @@ -1866,8 +1881,8 @@ HRESULT ShimChain::GetRegisterSet(ICorDebugRegisterSet ** ppRegisters) // This is a private hook for calling back into the RS. Alternatively, we could have created a // ShimRegisterSet, but that's too much work for now. - pThread->CreateCordbRegisterSet(m_pContext, - m_contextSize, + ContextBuffer contextBuffer = { m_pContext, m_contextSize }; + pThread->CreateCordbRegisterSet(contextBuffer, (m_chainIndex == 0), m_chainReason, ppRegisters); diff --git a/src/coreclr/debug/di/valuehome.cpp b/src/coreclr/debug/di/valuehome.cpp index 1d7e53a3b7f422..496e34acfebe44 100644 --- a/src/coreclr/debug/di/valuehome.cpp +++ b/src/coreclr/debug/di/valuehome.cpp @@ -39,18 +39,21 @@ void RegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // Arguments: // updates a register in a given context buffer using the DAC. // Arguments: -// input: pContext - context buffer in which the register is to be updated +// input: contextBuffer - context buffer in which the register is to be updated // regnum - enumeration constant indicating which register is to be updated // newVal - the new value for the register contents // output: no out parameters, but the new value will be written to the context buffer -void RegValueHome::SetContextRegister(BYTE * pContext, +void RegValueHome::SetContextRegister(ContextBuffer contextBuffer, CorDebugRegister regNum, SIZE_T newVal) { IDacDbiInterface * pDAC = m_pFrame->GetProcess()->GetDAC(); TADDR value = (TADDR)newVal; - ULONG32 cbCtx = m_pFrame->GetProcess()->GetTargetContextSize(); - HRESULT hr = pDAC->WriteRegistersToContext(pContext, cbCtx, ®Num, 1, &value); + HRESULT hr = pDAC->WriteRegistersToContext( + contextBuffer, + ®Num, + 1, + &value); if (FAILED(hr)) { _ASSERTE(!"Invalid register number!"); @@ -61,7 +64,7 @@ void RegValueHome::SetContextRegister(BYTE * pContext, // RegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see code:EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) +void RegValueHome::SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) { SIZE_T extendedVal = 0; @@ -107,7 +110,7 @@ void RegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, b } } - SetContextRegister(pContext, m_reg1Info.m_kRegNumber, extendedVal); // throws + SetContextRegister(contextBuffer, m_reg1Info.m_kRegNumber, extendedVal); // throws } // RegValueHome::SetEnregisteredValue // RegValueHome::GetEnregisteredValue @@ -146,7 +149,7 @@ void RegRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // RegRegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) +void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) { _ASSERTE(newValue.Size() == 8); _ASSERTE(REG_SIZE == sizeof(void*)); @@ -160,8 +163,8 @@ void RegRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext // Update the proper registers. SetContextRegister writes through to the // active CONTEXT - which is the only source of truth now that REGDISPLAY is gone. - SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws - SetContextRegister(pContext, m_reg2Info.m_kRegNumber, lowPart); // throws + SetContextRegister(contextBuffer, m_reg1Info.m_kRegNumber, highPart); // throws + SetContextRegister(contextBuffer, m_reg2Info.m_kRegNumber, lowPart); // throws } // RegRegValueHome::SetEnregisteredValue // RegRegValueHome::GetEnregisteredValue @@ -201,7 +204,7 @@ void RegMemValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // RegMemValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) +void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) { _ASSERTE(newValue.Size() == REG_SIZE >> 1); // make sure we have bytes for two registers _ASSERTE(REG_SIZE == sizeof(void*)); @@ -214,7 +217,7 @@ void RegMemValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); // Update the proper registers. - SetContextRegister(pContext, m_reg1Info.m_kRegNumber, highPart); // throws + SetContextRegister(contextBuffer, m_reg1Info.m_kRegNumber, highPart); // throws _ASSERTE(REG_SIZE == sizeof(lowPart)); HRESULT hr = m_pFrame->GetProcess()->SafeReadStruct(m_memAddr, &lowPart); @@ -263,7 +266,7 @@ void MemRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // MemRegValueHome::SetEnregisteredValue // set a remote enregistered location to a new value (see EnregisteredValueHome::SetEnregisteredValue // for full header comment) -void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext, bool fIsSigned) +void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, ContextBuffer contextBuffer, bool fIsSigned) { _ASSERTE(newValue.Size() == REG_SIZE << 1); // make sure we have bytes for two registers _ASSERTE(REG_SIZE == sizeof(void *)); @@ -276,7 +279,7 @@ void MemRegValueHome::SetEnregisteredValue(MemoryRange newValue, BYTE * pContext memcpy(&highPart, (BYTE *)newValue.StartAddress() + REG_SIZE, REG_SIZE); // Update the proper registers. - SetContextRegister(pContext, m_reg1Info.m_kRegNumber, lowPart); // throws + SetContextRegister(contextBuffer, m_reg1Info.m_kRegNumber, lowPart); // throws _ASSERTE(REG_SIZE == sizeof(highPart)); HRESULT hr = m_pFrame->GetProcess()->SafeWriteStruct(m_memAddr, &highPart); @@ -322,7 +325,7 @@ void FloatRegValueHome::CopyToIPCEType(RemoteAddress * pRegAddr) // FloatValueHome::SetEnregisteredValue // set a remote enregistered location to a new value. void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, - BYTE * pContext, + ContextBuffer contextBuffer, bool fIsSigned) { _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); @@ -574,12 +577,12 @@ void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) ULONG32 cbCtx = frame->GetProcess()->GetTargetContextSize(); // Get the thread's context so we can update it. - BYTE * cTemp = NULL; + ContextBuffer contextBuffer = {}; HRESULT hr = S_OK; EX_TRY { // This may throw, in which case we want to return our own HRESULT. - hr = frame->m_pThread->GetManagedContext(&cTemp); + hr = frame->m_pThread->GetManagedContext(&contextBuffer); } EX_CATCH_HRESULT(hr); if (FAILED(hr)) @@ -587,18 +590,23 @@ void RegisterValueHome::SetEnregisteredValue(MemoryRange src, bool fIsSigned) // If we failed to get the context, then we must not be in a leaf frame. ThrowHR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME); } + if (contextBuffer.contextSize < cbCtx) + { + ThrowHR(E_INVALIDARG); + } // Work on a local copy so failures in the chain below don't corrupt the // thread's cached context. The subclass mutates this buffer to apply the // new register value, and SetManagedContext then ships it to the LS and // updates the cache. NewArrayHolder ctxBuf(new BYTE[cbCtx]); - memcpy(ctxBuf, cTemp, cbCtx); + memcpy(ctxBuf, contextBuffer.pContextBytes, cbCtx); + ContextBuffer updatedContext = { ctxBuf, cbCtx }; - m_pRemoteRegAddr->SetEnregisteredValue(src, ctxBuf, fIsSigned); + m_pRemoteRegAddr->SetEnregisteredValue(src, updatedContext, fIsSigned); // Set the thread's modified context. - IfFailThrow(frame->m_pThread->SetManagedContext(ctxBuf, cbCtx)); + IfFailThrow(frame->m_pThread->SetManagedContext(updatedContext)); } // RegisterValueHome::SetEnregisteredValue @@ -858,4 +866,3 @@ RefValueHome::RefValueHome(CordbProcess * pProcess, } // RefValueHome::RefValueHome - diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 77972e396e013a..6ff0d9aee57abc 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -1076,7 +1076,7 @@ IDacDbiInterface : public IUnknown // // Arguments: // vmThread - the specified thread - // pInternalContextBuffer - a CONTEXT buffer for the stackwalker to work with + // contextBuffer - a CONTEXT buffer for the stackwalker to work with // ppSFIHandle - out parameter; return a handle to the stackwalker // // Notes: @@ -1084,7 +1084,7 @@ IDacDbiInterface : public IUnknown // This is a special case that violates the 'no state' tenant. // - virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, BYTE * pInternalContextBuffer, OUT StackWalkHandle * ppSFIHandle) = 0; + virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT StackWalkHandle * ppSFIHandle) = 0; // Delete the stackwalk object created from CreateStackWalk. virtual HRESULT STDMETHODCALLTYPE DeleteStackWalk(StackWalkHandle ppSFIHandle) = 0; @@ -1094,10 +1094,10 @@ IDacDbiInterface : public IUnknown // // Arguments: // pSFIHandle - the handle to the stackwalker - // pContext - OUT: the CONTEXT to be filled out. The context control flags are ignored. + // contextBuffer - OUT: the CONTEXT to be filled out. The context control flags are ignored. // - virtual HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, BYTE * pContext) = 0; + virtual HRESULT STDMETHODCALLTYPE GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, ContextBuffer contextBuffer) = 0; // // Set the stackwalker to the given CONTEXT. The CorDebugSetContextFlag indicates whether @@ -1108,10 +1108,10 @@ IDacDbiInterface : public IUnknown // vmThread - the current thread // pSFIHandle - the handle to the stackwalker // flag - flag to indicate whether the specified CONTEXT is "active" - // pContext - the specified CONTEXT. This may make correctional adjustments to the context's IP. + // contextBuffer - the specified CONTEXT. This may make correctional adjustments to the context's IP. // - virtual HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, BYTE * pContext) = 0; + virtual HRESULT STDMETHODCALLTYPE SetStackWalkCurrentContext(VMPTR_Thread vmThread, StackWalkHandle pSFIHandle, CorDebugSetContextFlag flag, ContextBuffer contextBuffer) = 0; // // Unwind the stackwalker to the next frame. The next frame could be any actual stack frame, @@ -1134,14 +1134,13 @@ IDacDbiInterface : public IUnknown // // Arguments: // vmThread - the specified thread - // pContext - the CONTEXT to be checked + // contextBuffer - the CONTEXT to be checked // // Return Value: // S_OK on success; otherwise, an appropriate failure HRESULT. // - virtual HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, - const BYTE * pContext) = 0; + virtual HRESULT STDMETHODCALLTYPE CheckContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer) = 0; // // Fill in the Debugger_STRData structure with information about the current frame @@ -1222,7 +1221,7 @@ IDacDbiInterface : public IUnknown // // Arguments: // vmThread - the specified thread - // pContext - the CONTEXT to check + // contextBuffer - the CONTEXT to check // pResult - [out] TRUE if the specified CONTEXT is the leaf CONTEXT. // // Return Value: @@ -1233,15 +1232,15 @@ IDacDbiInterface : public IUnknown // This will be deprecated in V3. // - virtual HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, const BYTE * pContext, OUT BOOL * pResult) = 0; + virtual HRESULT STDMETHODCALLTYPE IsLeafFrame(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT BOOL * pResult) = 0; // Get the context for a particular thread of the target process. // Arguments: // input: vmThread - the thread for which the context is required - // output: pContextBuffer - the address of the CONTEXT to be initialized. - // The memory for this belongs to the caller. It must not be NULL. + // output: contextBuffer - the CONTEXT buffer to be initialized. + // The memory for this belongs to the caller. // Note: returns an appropriate failure HRESULT on error - virtual HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, BYTE * pContextBuffer) = 0; + virtual HRESULT STDMETHODCALLTYPE GetContext(VMPTR_Thread vmThread, ContextBuffer contextBuffer) = 0; typedef enum { @@ -2217,15 +2216,13 @@ IDacDbiInterface : public IUnknown virtual HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize) = 0; virtual HRESULT STDMETHODCALLTYPE WriteRegistersToContext( - IN OUT BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values) = 0; virtual HRESULT STDMETHODCALLTYPE ReadRegistersFromContext( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues) = 0; @@ -2241,8 +2238,7 @@ IDacDbiInterface : public IUnknown OUT CorDebugRegister * pReg) = 0; virtual HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, IN ULONG32 regCount, OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], OUT ULONG32 * pValuesCount, @@ -2277,15 +2273,12 @@ IDacDbiInterface : public IUnknown virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; virtual HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters( - IN BYTE * ctxBuf, - IN ULONG32 cb, + IN ContextBuffer contextBuffer, OUT BOOL * pResult) = 0; virtual HRESULT STDMETHODCALLTYPE CompareControlRegisters( - IN const BYTE * ctxBuf1, - IN ULONG32 cb1, - IN const BYTE * ctxBuf2, - IN ULONG32 cb2, + IN ContextBuffer contextBuffer1, + IN ContextBuffer contextBuffer2, OUT BOOL * pResult) = 0; // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both @@ -2293,10 +2286,8 @@ IDacDbiInterface : public IUnknown // copy pulls exactly the requested chunks from the source; flags == 0 // preserves the destination's existing ContextFlags. virtual HRESULT STDMETHODCALLTYPE CopyContext( - IN OUT BYTE * dstCtxBuf, - IN ULONG32 cbDst, - IN const BYTE * srcCtxBuf, - IN ULONG32 cbSrc, + IN ContextBuffer destinationContext, + IN ContextBuffer sourceContext, IN ULONG32 flags) = 0; // The following tag tells the DD-marshalling tool to stop scanning. diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index fe36d1995daf39..ed0e31bf8988de 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -160,6 +160,13 @@ struct MSLAYOUT TargetBuffer ULONG cbSize; }; +// Describes an opaque target CONTEXT buffer in the host. +struct MSLAYOUT ContextBuffer +{ + BYTE * pContextBytes; + ULONG32 contextSize; +}; + // Module properties, retrieved by DAC. struct MSLAYOUT ModuleInfo { diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index cfb59befd85c08..93b495da8a8397 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -37,7 +37,7 @@ struct DacSharedReJitInfo; cpp_quote("#if 0") // FramePointer - wrapper around a single pointer (LPVOID m_sp in native code) -// Passed by value in IsMatchingParentFrame, GetFramePointer, and the internal frame callback. +// Passed by value in IsMatchingParentFrame and the internal frame callback. typedef struct { UINT_PTR m_sp; } FramePointer; // AsyncLocalData - struct passed by pointer to FP_ASYNC_LOCAL_CALLBACK. @@ -76,6 +76,11 @@ typedef int mdMethodDef; // Context types typedef int T_CONTEXT; typedef int EXCEPTION_RECORD; +typedef struct +{ + BYTE * pContextBytes; + ULONG32 contextSize; +} ContextBuffer; // Metadata interface typedef int IMDInternalImport; @@ -273,19 +278,18 @@ interface IDacDbiInterface : IUnknown // Context and Stack Walking HRESULT GetManagedStoppedContext([in] VMPTR_Thread vmThread, [out] VMPTR_CONTEXT * pRetVal); - HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in, out] BYTE * pInternalContextBuffer, [out] StackWalkHandle * ppSFIHandle); + HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in] ContextBuffer contextBuffer, [out] StackWalkHandle * ppSFIHandle); HRESULT DeleteStackWalk([in] StackWalkHandle ppSFIHandle); - HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [out] BYTE * pContext); - HRESULT SetStackWalkCurrentContext([in] VMPTR_Thread vmThread, [in] StackWalkHandle pSFIHandle, [in] CorDebugSetContextFlag flag, [in] BYTE * pContext); + HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [in] ContextBuffer contextBuffer); + HRESULT SetStackWalkCurrentContext([in] VMPTR_Thread vmThread, [in] StackWalkHandle pSFIHandle, [in] CorDebugSetContextFlag flag, [in] ContextBuffer contextBuffer); HRESULT UnwindStackWalkFrame([in] StackWalkHandle pSFIHandle, [out] BOOL * pResult); - HRESULT CheckContext([in] VMPTR_Thread vmThread, [in] const BYTE * pContext); + HRESULT CheckContext([in] VMPTR_Thread vmThread, [in] ContextBuffer contextBuffer); HRESULT GetStackWalkCurrentFrameInfo([in] StackWalkHandle pSFIHandle, [out] struct Debugger_STRData * pFrameData, [out] FrameType * pRetVal); HRESULT GetCountOfInternalFrames([in] VMPTR_Thread vmThread, [out] ULONG32 * pRetVal); HRESULT EnumerateInternalFrames([in] VMPTR_Thread vmThread, [in] FP_INTERNAL_FRAME_ENUMERATION_CALLBACK fpCallback, [in] CALLBACK_DATA pUserData); HRESULT GetStackParameterSize([in] CORDB_ADDRESS controlPC, [out] ULONG32 * pRetVal); - HRESULT GetFramePointer([in] StackWalkHandle pSFIHandle, [out] FramePointer * pRetVal); - HRESULT IsLeafFrame([in] VMPTR_Thread vmThread, [in] const BYTE * pContext, [out] BOOL * pResult); - HRESULT GetContext([in] VMPTR_Thread vmThread, [out] BYTE * pContextBuffer); + HRESULT IsLeafFrame([in] VMPTR_Thread vmThread, [in] ContextBuffer contextBuffer, [out] BOOL * pResult); + HRESULT GetContext([in] VMPTR_Thread vmThread, [in] ContextBuffer contextBuffer); // Method HRESULT IsDiagnosticsHiddenOrLCGMethod([in] VMPTR_MethodDesc vmMethodDesc, [out] DynamicMethodType * pRetVal); @@ -446,8 +450,8 @@ interface IDacDbiInterface : IUnknown HRESULT GetTargetContextSize([in] int flags, [out] ULONG32 * pSize); // CONTEXT register accessors. - HRESULT WriteRegistersToContext([in, out] BYTE * ctxBuf, [in] ULONG32 cb, [in] const int * regs, [in] ULONG32 nRegs, [in] const TADDR * values); - HRESULT ReadRegistersFromContext([in] BYTE * ctxBuf, [in] ULONG32 cb, [in] const int * regs, [in] ULONG32 nRegs, [out] TADDR * pValues); + HRESULT WriteRegistersToContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [in] const TADDR * values); + HRESULT ReadRegistersFromContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [out] TADDR * pValues); // Returns the full availability bitmask for the target architecture in // CorDebugRegister bit positions, including both integer (GPR) and @@ -471,8 +475,7 @@ interface IDacDbiInterface : IUnknown // pFloatStackTop - x87 top-of-stack depth on x86 (so DBI can preserve // its stack-relative dispatch); 0 on every other arch HRESULT ReadFloatRegistersFromContext( - [in] BYTE * ctxBuf, - [in] ULONG32 cb, + [in] ContextBuffer contextBuffer, [in] ULONG32 regCount, [out] DOUBLE values[32], [out] ULONG32 * pValuesCount, @@ -482,13 +485,13 @@ interface IDacDbiInterface : IUnknown // Returns the target's processor architecture and OS family. HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); - HRESULT ContextHasExtendedRegisters([in] BYTE * ctxBuf, [in] ULONG32 cb, [out] BOOL * pResult); + HRESULT ContextHasExtendedRegisters([in] ContextBuffer contextBuffer, [out] BOOL * pResult); - HRESULT CompareControlRegisters([in] const BYTE * ctxBuf1, [in] ULONG32 cb1, [in] const BYTE * ctxBuf2, [in] ULONG32 cb2, [out] BOOL * pResult); + HRESULT CompareControlRegisters([in] ContextBuffer contextBuffer1, [in] ContextBuffer contextBuffer2, [out] BOOL * pResult); // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both // contexts. flags != 0 first stamps dstCtxBuf's ContextFlags so the copy // pulls exactly the requested chunks from the source; flags == 0 preserves // the destination's existing ContextFlags. - HRESULT CopyContext([in, out] BYTE * dstCtxBuf, [in] ULONG32 cbDst, [in] const BYTE * srcCtxBuf, [in] ULONG32 cbSrc, [in] ULONG32 flags); + HRESULT CopyContext([in] ContextBuffer destinationContext, [in] ContextBuffer sourceContext, [in] ULONG32 flags); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index c5c0984dc9c384..a3d1aff887945b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -1534,10 +1534,13 @@ public int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal) return hr; } - private void SeedHandleFromNativeContext(StackWalkHandleData handleData, byte* pContext, bool isFirst) + private void SeedHandleFromNativeContext(StackWalkHandleData handleData, ContextBuffer contextBuffer, bool isFirst) { - uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; - byte[] contextBuf = new Span(pContext, (int)contextSize).ToArray(); + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.pContextBytes is null || contextBuffer.contextSize < expectedContextSize) + throw new ArgumentException("The context buffer is invalid.", nameof(contextBuffer)); + + byte[] contextBuf = new Span(contextBuffer.pContextBytes, (int)expectedContextSize).ToArray(); handleData.Reset(contextBuf, isFirst); } @@ -1576,13 +1579,16 @@ private string DescribeContextDiff(ReadOnlySpan cdac, ReadOnlySpan l } #endif - public int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* ppSFIHandle) + public int CreateStackWalk(ulong vmThread, ContextBuffer contextBuffer, nuint* ppSFIHandle) { if (ppSFIHandle is null) return HResults.E_POINTER; - if (pInternalContextBuffer == null) - return HResults.E_POINTER; *ppSFIHandle = 0; + if (contextBuffer.pContextBytes == null) + return HResults.E_POINTER; + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.contextSize < expectedContextSize) + return HResults.E_INVALIDARG; int hr = HResults.S_OK; StackWalkHandleData? handleData = null; @@ -1592,10 +1598,10 @@ public int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* uint allFlags = ctx.AllContextFlags; ThreadData threadData = _target.Contracts.Thread.GetThreadData(new TargetPointer(vmThread)); byte[] seedContext = _target.Contracts.StackWalk.GetContext(threadData, ThreadContextSource.Debugger, allFlags); - seedContext.AsSpan().CopyTo(new Span(pInternalContextBuffer, seedContext.Length)); + seedContext.AsSpan().CopyTo(new Span(contextBuffer.pContextBytes, (int)expectedContextSize)); handleData = new StackWalkHandleData(_target.Contracts.StackWalk, threadData); - SeedHandleFromNativeContext(handleData, pInternalContextBuffer, isFirst: true); + SeedHandleFromNativeContext(handleData, contextBuffer, isFirst: true); *ppSFIHandle = handleData.GetHandle(); } catch (System.Exception ex) @@ -1605,20 +1611,20 @@ public int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* // Mirror the create onto the legacy DBI if (_legacy is not null && LegacyFallbackHelper.CanFallback()) { - uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; nuint legacyHandle = 0; - byte* pLocal = (byte*)NativeMemory.AlignedAlloc(contextSize, 16); + byte* pLocal = (byte*)NativeMemory.AlignedAlloc(expectedContextSize, 16); try { - new Span(pLocal, (int)contextSize).Clear(); - int hrLocal = _legacy.CreateStackWalk(vmThread, pLocal, &legacyHandle); + new Span(pLocal, (int)expectedContextSize).Clear(); + ContextBuffer legacyContext = new() { pContextBytes = pLocal, contextSize = expectedContextSize }; + int hrLocal = _legacy.CreateStackWalk(vmThread, legacyContext, &legacyHandle); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK && hrLocal == HResults.S_OK) { #if DEBUG - ReadOnlySpan cdacBytes = new(pInternalContextBuffer, (int)contextSize); - ReadOnlySpan legacyBytes = new(pLocal, (int)contextSize); + ReadOnlySpan cdacBytes = new(contextBuffer.pContextBytes, (int)expectedContextSize); + ReadOnlySpan legacyBytes = new(pLocal, (int)expectedContextSize); if (!cdacBytes.SequenceEqual(legacyBytes)) Debug.Fail(DescribeContextDiff(cdacBytes, legacyBytes)); #endif @@ -1666,16 +1672,18 @@ public int DeleteStackWalk(nuint ppSFIHandle) return hr; } - public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) + public int GetStackWalkCurrentContext(nuint pSFIHandle, ContextBuffer contextBuffer) { if (pSFIHandle == 0) return HResults.E_INVALIDARG; - if (pContext == null) + if (contextBuffer.pContextBytes == null) return HResults.E_POINTER; int hr = HResults.S_OK; nuint legacyHandle = 0; - uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.contextSize < expectedContextSize) + return HResults.E_INVALIDARG; try { GCHandle gcHandle = GCHandle.FromIntPtr((nint)pSFIHandle); @@ -1698,7 +1706,7 @@ public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) context = stripped.GetBytes(); } - context.AsSpan().CopyTo(new Span(pContext, context.Length)); + context.AsSpan().CopyTo(new Span(contextBuffer.pContextBytes, (int)expectedContextSize)); } else { @@ -1712,16 +1720,17 @@ public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) #if DEBUG if (_legacy is not null && legacyHandle != 0) { - byte* pLocal = (byte*)NativeMemory.AlignedAlloc(contextSize, 16); + byte* pLocal = (byte*)NativeMemory.AlignedAlloc(expectedContextSize, 16); try { - new Span(pLocal, (int)contextSize).Clear(); - int hrLocal = _legacy.GetStackWalkCurrentContext(legacyHandle, pLocal); + new Span(pLocal, (int)expectedContextSize).Clear(); + ContextBuffer legacyContext = new() { pContextBytes = pLocal, contextSize = expectedContextSize }; + int hrLocal = _legacy.GetStackWalkCurrentContext(legacyHandle, legacyContext); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) { - ReadOnlySpan cdacBytes = new(pContext, (int)contextSize); - ReadOnlySpan legacyBytes = new(pLocal, (int)contextSize); + ReadOnlySpan cdacBytes = new(contextBuffer.pContextBytes, (int)expectedContextSize); + ReadOnlySpan legacyBytes = new(pLocal, (int)expectedContextSize); if (!cdacBytes.SequenceEqual(legacyBytes)) Debug.Fail(DescribeContextDiff(cdacBytes, legacyBytes)); } @@ -1735,12 +1744,14 @@ public int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext) return hr; } - public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, byte* pContext) + public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, ContextBuffer contextBuffer) { if (pSFIHandle == 0) return HResults.E_INVALIDARG; - if (pContext == null) + if (contextBuffer.pContextBytes == null) return HResults.E_POINTER; + if (contextBuffer.contextSize < IPlatformAgnosticContext.GetContextForPlatform(_target).Size) + return HResults.E_INVALIDARG; int hr = HResults.S_OK; nuint legacyHandle = 0; @@ -1751,7 +1762,7 @@ public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag throw new ArgumentException("Invalid stack walk handle", nameof(pSFIHandle)); legacyHandle = handleData.LegacyHandle; - SeedHandleFromNativeContext(handleData, pContext, isFirst: flag == (int)CorDebugSetContextFlags.SET_CONTEXT_FLAG_ACTIVE_FRAME); + SeedHandleFromNativeContext(handleData, contextBuffer, isFirst: flag == (int)CorDebugSetContextFlags.SET_CONTEXT_FLAG_ACTIVE_FRAME); } catch (System.Exception ex) { @@ -1760,7 +1771,7 @@ public int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag // Mirror to legacy DBI in all builds so the legacy walker tracks the cDAC walker if (_legacy is not null && LegacyFallbackHelper.CanFallback() && legacyHandle != 0) { - int hrLocal = _legacy.SetStackWalkCurrentContext(vmThread, legacyHandle, flag, pContext); + int hrLocal = _legacy.SetStackWalkCurrentContext(vmThread, legacyHandle, flag, contextBuffer); Debug.ValidateHResult(hr, hrLocal); } return hr; @@ -1818,13 +1829,20 @@ public int UnwindStackWalkFrame(nuint pSFIHandle, Interop.BOOL* pResult) return hr; } - public int CheckContext(ulong vmThread, byte* pContext) + public int CheckContext(ulong vmThread, ContextBuffer contextBuffer) { + if (contextBuffer.pContextBytes == null) + return HResults.E_POINTER; + + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.contextSize < expectedContextSize) + return HResults.E_INVALIDARG; + int hr = HResults.S_OK; try { IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - ctx.FillFromBuffer(new Span(pContext, (int)ctx.Size)); + ctx.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)ctx.Size)); if ((ctx.RawContextFlags & ctx.ContextControlFlags) != 0) { @@ -1843,7 +1861,7 @@ public int CheckContext(ulong vmThread, byte* pContext) #if DEBUG if (_legacy is not null) { - int hrLocal = _legacy.CheckContext(vmThread, pContext); + int hrLocal = _legacy.CheckContext(vmThread, contextBuffer); Debug.ValidateHResult(hr, hrLocal); } #endif @@ -2079,9 +2097,16 @@ private static nuint TryGetLegacyHandle(nuint pSFIHandle) } } - public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) + public int IsLeafFrame(ulong vmThread, ContextBuffer contextBuffer, Interop.BOOL* pResult) { + if (contextBuffer.pContextBytes == null || pResult == null) + return HResults.E_POINTER; + *pResult = Interop.BOOL.FALSE; + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.contextSize < expectedContextSize) + return HResults.E_INVALIDARG; + int hr = HResults.S_OK; try { @@ -2093,7 +2118,7 @@ public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) // Read the given context from the native buffer. IPlatformAgnosticContext givenCtx = IPlatformAgnosticContext.GetContextForPlatform(_target); - givenCtx.FillFromBuffer(new Span(pContext, leafContext.Length)); + givenCtx.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)expectedContextSize)); *pResult = givenCtx.StackPointer == leafCtx.StackPointer && givenCtx.InstructionPointer == leafCtx.InstructionPointer @@ -2107,7 +2132,7 @@ public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) if (_legacy is not null) { Interop.BOOL resultLocal; - int hrLocal = _legacy.IsLeafFrame(vmThread, pContext, &resultLocal); + int hrLocal = _legacy.IsLeafFrame(vmThread, contextBuffer, &resultLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); @@ -2116,8 +2141,15 @@ public int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult) return hr; } - public int GetContext(ulong vmThread, byte* pContextBuffer) + public int GetContext(ulong vmThread, ContextBuffer contextBuffer) { + if (contextBuffer.pContextBytes == null) + return HResults.E_POINTER; + + uint expectedContextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; + if (contextBuffer.contextSize < expectedContextSize) + return HResults.E_INVALIDARG; + int hr = HResults.S_OK; try { @@ -2125,7 +2157,7 @@ public int GetContext(ulong vmThread, byte* pContextBuffer) ThreadData threadData = _target.Contracts.Thread.GetThreadData(new TargetPointer(vmThread)); byte[] context = _target.Contracts.StackWalk.GetContext(threadData, ThreadContextSource.Debugger, allFlags); - context.AsSpan().CopyTo(new Span(pContextBuffer, context.Length)); + context.AsSpan().CopyTo(new Span(contextBuffer.pContextBytes, (int)expectedContextSize)); } catch (System.Exception ex) { @@ -2134,18 +2166,18 @@ public int GetContext(ulong vmThread, byte* pContextBuffer) #if DEBUG if (_legacy is not null) { - uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(_target).Size; - byte[] localContextBuf = new byte[contextSize]; + byte[] localContextBuf = new byte[expectedContextSize]; fixed (byte* pLocal = localContextBuf) { - int hrLocal = _legacy.GetContext(vmThread, pLocal); + ContextBuffer legacyContext = new() { pContextBytes = pLocal, contextSize = expectedContextSize }; + int hrLocal = _legacy.GetContext(vmThread, legacyContext); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) { IPlatformAgnosticContext contextStruct = IPlatformAgnosticContext.GetContextForPlatform(_target); IPlatformAgnosticContext localContextStruct = IPlatformAgnosticContext.GetContextForPlatform(_target); - contextStruct.FillFromBuffer(new Span(pContextBuffer, (int)contextSize)); + contextStruct.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)expectedContextSize)); localContextStruct.FillFromBuffer(localContextBuf); Debug.Assert(contextStruct.Equals(localContextStruct)); @@ -5835,19 +5867,19 @@ public int GetTargetInfo(TargetInfo* pTargetInfo) return hr; } - public int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pResult) + public int ContextHasExtendedRegisters(ContextBuffer contextBuffer, Interop.BOOL* pResult) { int hr = HResults.S_OK; try { - if (ctxBuf is null) - throw new ArgumentNullException(nameof(ctxBuf)); + if (contextBuffer.pContextBytes is null) + throw new ArgumentNullException(nameof(contextBuffer)); if (pResult is null) throw new ArgumentNullException(nameof(pResult)); IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - if (cb < ctx.Size) - throw new ArgumentException("Context buffer too small", nameof(cb)); + if (contextBuffer.contextSize < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); if (ctx.ExtendedRegistersFlag == 0) { @@ -5855,7 +5887,7 @@ public int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pRes } else { - ctx.FillFromBuffer(new Span(ctxBuf, (int)cb)); + ctx.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)ctx.Size)); bool hasExtended = (ctx.RawContextFlags & ctx.ExtendedRegistersFlag) == ctx.ExtendedRegistersFlag; *pResult = hasExtended ? Interop.BOOL.TRUE : Interop.BOOL.FALSE; } @@ -5868,7 +5900,7 @@ public int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pRes if (_legacy is not null) { Interop.BOOL resultLocal; - int hrLocal = _legacy.ContextHasExtendedRegisters(ctxBuf, cb, &resultLocal); + int hrLocal = _legacy.ContextHasExtendedRegisters(contextBuffer, &resultLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); @@ -5877,23 +5909,23 @@ public int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pRes return hr; } - public int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint cb2, Interop.BOOL* pResult) + public int CompareControlRegisters(ContextBuffer contextBuffer1, ContextBuffer contextBuffer2, Interop.BOOL* pResult) { int hr = HResults.S_OK; try { - if (ctxBuf1 is null || ctxBuf2 is null) - throw new ArgumentNullException(ctxBuf1 is null ? nameof(ctxBuf1) : nameof(ctxBuf2)); + if (contextBuffer1.pContextBytes is null || contextBuffer2.pContextBytes is null) + throw new ArgumentNullException(contextBuffer1.pContextBytes is null ? nameof(contextBuffer1) : nameof(contextBuffer2)); if (pResult is null) throw new ArgumentNullException(nameof(pResult)); IPlatformAgnosticContext ctx1 = IPlatformAgnosticContext.GetContextForPlatform(_target); IPlatformAgnosticContext ctx2 = IPlatformAgnosticContext.GetContextForPlatform(_target); - if (cb1 < ctx1.Size || cb2 < ctx2.Size) + if (contextBuffer1.contextSize < ctx1.Size || contextBuffer2.contextSize < ctx2.Size) throw new ArgumentException("Context buffer too small"); - ctx1.FillFromBuffer(new Span(ctxBuf1, (int)cb1)); - ctx2.FillFromBuffer(new Span(ctxBuf2, (int)cb2)); + ctx1.FillFromBuffer(new Span(contextBuffer1.pContextBytes, (int)ctx1.Size)); + ctx2.FillFromBuffer(new Span(contextBuffer2.pContextBytes, (int)ctx2.Size)); *pResult = ctx1.StackPointer == ctx2.StackPointer && ctx1.InstructionPointer == ctx2.InstructionPointer @@ -5907,7 +5939,7 @@ public int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint if (_legacy is not null) { Interop.BOOL resultLocal; - int hrLocal = _legacy.CompareControlRegisters(ctxBuf1, cb1, ctxBuf2, cb2, &resultLocal); + int hrLocal = _legacy.CompareControlRegisters(contextBuffer1, contextBuffer2, &resultLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}"); @@ -5916,25 +5948,27 @@ public int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint return hr; } - public int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, uint flags) + public int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags) { int hr = HResults.S_OK; + IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); #if DEBUG // Capture the untouched destination image so the legacy cross-check below can // replay the same copy from an identical starting state. - byte[]? originalDst = (dstCtxBuf is not null && cbDst > 0) ? new ReadOnlySpan(dstCtxBuf, (int)cbDst).ToArray() : null; + byte[]? originalDst = (destinationContext.pContextBytes is not null && destinationContext.contextSize >= ctx.Size) + ? new ReadOnlySpan(destinationContext.pContextBytes, (int)ctx.Size).ToArray() + : null; #endif try { - if (dstCtxBuf is null || srcCtxBuf is null) - throw new ArgumentNullException(dstCtxBuf is null ? nameof(dstCtxBuf) : nameof(srcCtxBuf)); + if (destinationContext.pContextBytes is null || sourceContext.pContextBytes is null) + throw new ArgumentNullException(destinationContext.pContextBytes is null ? nameof(destinationContext) : nameof(sourceContext)); - IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - if (cbDst < ctx.Size || cbSrc < ctx.Size) + if (destinationContext.contextSize < ctx.Size || sourceContext.contextSize < ctx.Size) throw new ArgumentException("Context buffer too small"); - Span dst = new Span(dstCtxBuf, (int)cbDst); - Span src = new Span(srcCtxBuf, (int)cbSrc); + Span dst = new Span(destinationContext.pContextBytes, (int)ctx.Size); + Span src = new Span(sourceContext.pContextBytes, (int)ctx.Size); IPlatformAgnosticContext dstCtx = IPlatformAgnosticContext.GetContextForPlatform(_target); dstCtx.FillFromBuffer(dst); @@ -5971,18 +6005,20 @@ public int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, hr = ex.HResult; } #if DEBUG - if (_legacy is not null && originalDst is not null) + if (_legacy is not null && originalDst is not null && + sourceContext.pContextBytes is not null && sourceContext.contextSize >= ctx.Size) { - IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); byte[] scratchDst = (byte[])originalDst.Clone(); - byte[] scratchSrc = new ReadOnlySpan(srcCtxBuf, (int)cbSrc).ToArray(); + byte[] scratchSrc = new ReadOnlySpan(sourceContext.pContextBytes, (int)ctx.Size).ToArray(); fixed (byte* pScratchDst = scratchDst) fixed (byte* pScratchSrc = scratchSrc) { - int hrLocal = _legacy.CopyContext(pScratchDst, cbDst, pScratchSrc, cbSrc, flags); + ContextBuffer scratchDestination = new() { pContextBytes = pScratchDst, contextSize = ctx.Size }; + ContextBuffer scratchSource = new() { pContextBytes = pScratchSrc, contextSize = ctx.Size }; + int hrLocal = _legacy.CopyContext(scratchDestination, scratchSource, flags); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) - Debug.Assert(new ReadOnlySpan(dstCtxBuf, (int)ctx.Size).SequenceEqual(scratchDst.AsSpan(0, (int)ctx.Size)), + Debug.Assert(new ReadOnlySpan(destinationContext.pContextBytes, (int)ctx.Size).SequenceEqual(scratchDst.AsSpan(0, (int)ctx.Size)), "cDAC and DAC produced different copied contexts"); } } @@ -5990,20 +6026,20 @@ public int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, return hr; } - public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* values) + public int WriteRegistersToContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* values) { int hr = HResults.S_OK; IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); try { - if (ctxBuf is null) - throw new ArgumentNullException(nameof(ctxBuf)); + if (contextBuffer.pContextBytes is null) + throw new ArgumentNullException(nameof(contextBuffer)); if (nRegs > 0 && (regs is null || values is null)) throw new ArgumentNullException(regs is null ? nameof(regs) : nameof(values)); - if (cb < ctx.Size) - throw new ArgumentException("Context buffer too small", nameof(cb)); + if (contextBuffer.contextSize < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); - Span bufSpan = new Span(ctxBuf, (int)cb); + Span bufSpan = new Span(contextBuffer.pContextBytes, (int)ctx.Size); ctx.FillFromBuffer(bufSpan); RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); @@ -6022,16 +6058,17 @@ public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs hr = ex.HResult; } #if DEBUG - if (_legacy is not null) + if (_legacy is not null && contextBuffer.pContextBytes is not null && contextBuffer.contextSize >= ctx.Size) { byte[] scratch = new byte[ctx.Size]; - new ReadOnlySpan(ctxBuf, (int)ctx.Size).CopyTo(scratch); + new ReadOnlySpan(contextBuffer.pContextBytes, (int)ctx.Size).CopyTo(scratch); fixed (byte* pScratch = scratch) { - int hrLocal = _legacy.WriteRegistersToContext(pScratch, cb, regs, nRegs, values); + ContextBuffer scratchContext = new() { pContextBytes = pScratch, contextSize = ctx.Size }; + int hrLocal = _legacy.WriteRegistersToContext(scratchContext, regs, nRegs, values); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) - Debug.Assert(new ReadOnlySpan(ctxBuf, (int)ctx.Size).SequenceEqual(scratch), + Debug.Assert(new ReadOnlySpan(contextBuffer.pContextBytes, (int)ctx.Size).SequenceEqual(scratch), "cDAC and DAC produced different mutated contexts"); } } @@ -6039,21 +6076,21 @@ public int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs return hr; } - public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* pValues) + public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* pValues) { int hr = HResults.S_OK; try { - if (ctxBuf is null) - throw new ArgumentNullException(nameof(ctxBuf)); + if (contextBuffer.pContextBytes is null) + throw new ArgumentNullException(nameof(contextBuffer)); if (nRegs > 0 && (regs is null || pValues is null)) throw new ArgumentNullException(regs is null ? nameof(regs) : nameof(pValues)); IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - if (cb < ctx.Size) - throw new ArgumentException("Context buffer too small", nameof(cb)); + if (contextBuffer.contextSize < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); - ctx.FillFromBuffer(new Span(ctxBuf, (int)cb)); + ctx.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)ctx.Size)); RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); for (uint i = 0; i < nRegs; i++) @@ -6073,7 +6110,7 @@ public int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* reg nuint[] valuesLocal = new nuint[nRegs]; int hrLocal; fixed (nuint* pValuesLocal = valuesLocal) - hrLocal = _legacy.ReadRegistersFromContext(ctxBuf, cb, regs, nRegs, pValuesLocal); + hrLocal = _legacy.ReadRegistersFromContext(contextBuffer, regs, nRegs, pValuesLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) { @@ -6154,22 +6191,22 @@ public int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* return hr; } - public int ReadFloatRegistersFromContext(byte* ctxBuf, uint cb, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop) + public int ReadFloatRegistersFromContext(ContextBuffer contextBuffer, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop) { int hr = HResults.S_OK; try { - if (ctxBuf is null || values is null || pValuesCount is null || + if (contextBuffer.pContextBytes is null || values is null || pValuesCount is null || pFirstFloatReg is null || pFloatStackTop is null || maxValues == 0) { throw new ArgumentException("Invalid argument to ReadFloatRegistersFromContext"); } IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - if (cb < ctx.Size) - throw new ArgumentException("Context buffer too small", nameof(cb)); + if (contextBuffer.contextSize < ctx.Size) + throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); - ReadOnlySpan buf = new ReadOnlySpan(ctxBuf, (int)cb); + ReadOnlySpan buf = new ReadOnlySpan(contextBuffer.pContextBytes, (int)ctx.Size); *pValuesCount = 0; *pFirstFloatReg = -1; @@ -6287,7 +6324,7 @@ static double ReadSlot64(ReadOnlySpan buf, int offset) uint floatStackTopLocal; int hrLocal; fixed (double* pValuesLocal = valuesLocal) - hrLocal = _legacy.ReadFloatRegistersFromContext(ctxBuf, cb, maxValues, pValuesLocal, + hrLocal = _legacy.ReadFloatRegistersFromContext(contextBuffer, maxValues, pValuesLocal, &valuesCountLocal, &firstFloatRegLocal, &floatStackTopLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index d117e765fa7ffa..4c0a7b28dab094 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -15,6 +15,13 @@ public struct COR_TYPEID public ulong token2; } +[StructLayout(LayoutKind.Sequential)] +public unsafe struct ContextBuffer +{ + public byte* pContextBytes; + public uint contextSize; +} + [StructLayout(LayoutKind.Sequential)] public struct FieldData { @@ -805,22 +812,22 @@ public unsafe partial interface IDacDbiInterface int GetManagedStoppedContext(ulong vmThread, ulong* pRetVal); [PreserveSig] - int CreateStackWalk(ulong vmThread, byte* pInternalContextBuffer, nuint* ppSFIHandle); + int CreateStackWalk(ulong vmThread, ContextBuffer contextBuffer, nuint* ppSFIHandle); [PreserveSig] int DeleteStackWalk(nuint ppSFIHandle); [PreserveSig] - int GetStackWalkCurrentContext(nuint pSFIHandle, byte* pContext); + int GetStackWalkCurrentContext(nuint pSFIHandle, ContextBuffer contextBuffer); [PreserveSig] - int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, byte* pContext); + int SetStackWalkCurrentContext(ulong vmThread, nuint pSFIHandle, int flag, ContextBuffer contextBuffer); [PreserveSig] int UnwindStackWalkFrame(nuint pSFIHandle, Interop.BOOL* pResult); [PreserveSig] - int CheckContext(ulong vmThread, byte* pContext); + int CheckContext(ulong vmThread, ContextBuffer contextBuffer); [PreserveSig] int GetStackWalkCurrentFrameInfo(nuint pSFIHandle, nint pFrameData, int* pRetVal); @@ -835,10 +842,10 @@ public unsafe partial interface IDacDbiInterface int GetStackParameterSize(ulong controlPC, uint* pRetVal); [PreserveSig] - int IsLeafFrame(ulong vmThread, byte* pContext, Interop.BOOL* pResult); + int IsLeafFrame(ulong vmThread, ContextBuffer contextBuffer, Interop.BOOL* pResult); [PreserveSig] - int GetContext(ulong vmThread, byte* pContextBuffer); + int GetContext(ulong vmThread, ContextBuffer contextBuffer); [PreserveSig] int IsDiagnosticsHiddenOrLCGMethod(ulong vmMethodDesc, int* pRetVal); @@ -1066,10 +1073,10 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int GetTargetContextSize(ContextSizeFlags flags, uint* pSize); [PreserveSig] - int WriteRegistersToContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* values); + int WriteRegistersToContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* values); [PreserveSig] - int ReadRegistersFromContext(byte* ctxBuf, uint cb, CorDebugRegister* regs, uint nRegs, nuint* pValues); + int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* pValues); [PreserveSig] int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable); @@ -1078,17 +1085,17 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* pReg); [PreserveSig] - int ReadFloatRegistersFromContext(byte* ctxBuf, uint cb, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop); + int ReadFloatRegistersFromContext(ContextBuffer contextBuffer, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop); [PreserveSig] int GetTargetInfo(TargetInfo* pTargetInfo); [PreserveSig] - int ContextHasExtendedRegisters(byte* ctxBuf, uint cb, Interop.BOOL* pResult); + int ContextHasExtendedRegisters(ContextBuffer contextBuffer, Interop.BOOL* pResult); [PreserveSig] - int CompareControlRegisters(byte* ctxBuf1, uint cb1, byte* ctxBuf2, uint cb2, Interop.BOOL* pResult); + int CompareControlRegisters(ContextBuffer contextBuffer1, ContextBuffer contextBuffer2, Interop.BOOL* pResult); [PreserveSig] - int CopyContext(byte* dstCtxBuf, uint cbDst, byte* srcCtxBuf, uint cbSrc, uint flags); + int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags); } diff --git a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs index 3b932d54ba7894..622d042c59eeb4 100644 --- a/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs +++ b/src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiStackWalkDumpTests.cs @@ -35,7 +35,8 @@ public unsafe void GetContext_Succeeds_ForCrashingThread(TestConfiguration confi fixed (byte* pContext = contextBuffer) { - int hr = dbi.GetContext(crashingThread.ThreadAddress, pContext); + ContextBuffer buffer = new() { pContextBytes = pContext, contextSize = contextSize }; + int hr = dbi.GetContext(crashingThread.ThreadAddress, buffer); Assert.Equal(System.HResults.S_OK, hr); } @@ -58,7 +59,8 @@ public unsafe void GetContext_MatchesContractGetContext(TestConfiguration config byte[] dbiContextBuffer = new byte[contextSize]; fixed (byte* pContext = dbiContextBuffer) { - int hr = dbi.GetContext(crashingThread.ThreadAddress, pContext); + ContextBuffer buffer = new() { pContextBytes = pContext, contextSize = contextSize }; + int hr = dbi.GetContext(crashingThread.ThreadAddress, buffer); Assert.Equal(System.HResults.S_OK, hr); } @@ -90,7 +92,8 @@ public unsafe void IsLeafFrame_TrueForLeafContext(TestConfiguration config) Interop.BOOL result; fixed (byte* pContext = leafContext) { - int hr = dbi.IsLeafFrame(crashingThread.ThreadAddress, pContext, &result); + ContextBuffer contextBuffer = new() { pContextBytes = pContext, contextSize = (uint)leafContext.Length }; + int hr = dbi.IsLeafFrame(crashingThread.ThreadAddress, contextBuffer, &result); Assert.Equal(System.HResults.S_OK, hr); } @@ -130,7 +133,8 @@ public unsafe void IsLeafFrame_FalseForNonLeafContext(TestConfiguration config) Interop.BOOL result; fixed (byte* pContext = nonLeafContext) { - int hr = dbi.IsLeafFrame(crashingThread.ThreadAddress, pContext, &result); + ContextBuffer contextBuffer = new() { pContextBytes = pContext, contextSize = (uint)nonLeafContext.Length }; + int hr = dbi.IsLeafFrame(crashingThread.ThreadAddress, contextBuffer, &result); Assert.Equal(System.HResults.S_OK, hr); } diff --git a/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs b/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs index 6f43407568e358..50642cfb6cc01b 100644 --- a/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs @@ -846,11 +846,29 @@ public void CheckContext_WithControlFlag_ValidatesSpRange(MockTarget.Architectur fixed (byte* pCtx = bytes) { - int hr = dacDbi.CheckContext(ThreadAddr, pCtx); + ContextBuffer contextBuffer = new() { pContextBytes = pCtx, contextSize = (uint)bytes.Length }; + int hr = dacDbi.CheckContext(ThreadAddr, contextBuffer); Assert.Equal(expectedHr, hr); } } + [Theory] + [MemberData(nameof(TargetArchitectures))] + public void CheckContext_UndersizedBuffer_ReturnsInvalidArgument(MockTarget.Architecture arch, string targetArch) + { + const ulong ThreadAddr = 0x1000; + var (dacDbi, target) = CreateCheckContextDacDbi(arch, targetArch, ThreadAddr, stackBase: 0x8000, stackLimit: 0x4000); + uint contextSize = IPlatformAgnosticContext.GetContextForPlatform(target).Size; + byte[] bytes = new byte[(int)contextSize - 1]; + + fixed (byte* pCtx = bytes) + { + ContextBuffer contextBuffer = new() { pContextBytes = pCtx, contextSize = (uint)bytes.Length }; + int hr = dacDbi.CheckContext(ThreadAddr, contextBuffer); + Assert.Equal(System.HResults.E_INVALIDARG, hr); + } + } + [Theory] [MemberData(nameof(TargetArchitectures))] public void CheckContext_NoControlFlag_SkipsSpCheck(MockTarget.Architecture arch, string targetArch) @@ -872,7 +890,8 @@ public void CheckContext_NoControlFlag_SkipsSpCheck(MockTarget.Architecture arch fixed (byte* pCtx = bytes) { - int hr = dacDbi.CheckContext(ThreadAddr, pCtx); + ContextBuffer contextBuffer = new() { pContextBytes = pCtx, contextSize = (uint)bytes.Length }; + int hr = dacDbi.CheckContext(ThreadAddr, contextBuffer); Assert.Equal(System.HResults.S_OK, hr); } From 6a5e27c9d9338b04f897c08d0e30b27584bb6331 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Jul 2026 13:57:57 -0700 Subject: [PATCH 11/26] ccr --- src/coreclr/debug/di/process.cpp | 54 ++++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 7dec255c7e536b..fe0f214f973307 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -5877,35 +5877,35 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuff return E_INVALIDARG; } - HRESULT hr = S_OK; - ULONG32 sizeToWrite; - BOOL hasExtendedRegisters = FALSE; - IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); - IfFailThrow(GetDAC()->GetTargetContextSize( - hasExtendedRegisters ? IDacDbiInterface::kContextSizeExtendedRegisters : IDacDbiInterface::kContextSizeBase, - &sizeToWrite)); - IDacDbiInterface::TargetInfo targetInfo; - - BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); - BYTE * pCtxSource = contextBuffer.pContextBytes; - IfFailThrow(GetDAC()->GetTargetInfo(&targetInfo)); - -// 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that -// kernel to usermode transitions don't have to allocate a CONTEXT and do a separate sub rsp -// to allocate stack spill space for the arguments. This means that writing to P1Home - P6Home -// will overwrite the arguments of some function higher on the stack, very bad. Conceptually you -// can think of these members as not being part of the context, ie they don't represent something -// which gets saved or restored on context switches. They are just space we shouldn't overwrite. -// See issue 630276 for more details. - if (targetInfo.arch == IDacDbiInterface::kArchAMD64) - { - pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 - pCtxSource += offsetof(CONTEXT, ContextFlags); - sizeToWrite -= offsetof(CONTEXT, ContextFlags); - } - EX_TRY { + HRESULT hr = S_OK; + ULONG32 sizeToWrite; + BOOL hasExtendedRegisters = FALSE; + IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); + IfFailThrow(GetDAC()->GetTargetContextSize( + hasExtendedRegisters ? IDacDbiInterface::kContextSizeExtendedRegisters : IDacDbiInterface::kContextSizeBase, + &sizeToWrite)); + IDacDbiInterface::TargetInfo targetInfo; + + BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); + BYTE * pCtxSource = contextBuffer.pContextBytes; + IfFailThrow(GetDAC()->GetTargetInfo(&targetInfo)); + + // 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that + // kernel to usermode transitions don't have to allocate a CONTEXT and do a separate sub rsp + // to allocate stack spill space for the arguments. This means that writing to P1Home - P6Home + // will overwrite the arguments of some function higher on the stack, very bad. Conceptually you + // can think of these members as not being part of the context, ie they don't represent something + // which gets saved or restored on context switches. They are just space we shouldn't overwrite. + // See issue 630276 for more details. + if (targetInfo.arch == IDacDbiInterface::kArchAMD64) + { + pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 + pCtxSource += offsetof(CONTEXT, ContextFlags); + sizeToWrite -= offsetof(CONTEXT, ContextFlags); + } + // Write the context. TargetBuffer tb(pRemoteContext, sizeToWrite); SafeWriteBuffer(tb, (const BYTE*) pCtxSource); From a4d9bb8876288fc0aecc2db40c0061c9c4daa5ad Mon Sep 17 00:00:00 2001 From: rcj1 Date: Fri, 17 Jul 2026 14:02:59 -0700 Subject: [PATCH 12/26] code review --- src/coreclr/debug/di/process.cpp | 4 +++- .../Dbi/IDacDbiInterface.cs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index fe0f214f973307..01a340cf57c6b8 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -1454,6 +1454,8 @@ void CordbProcess::FreeDac() LOG((LF_CORDB, LL_INFO1000, "Unloading DAC\n")); m_hDacModule.Free(); } + + m_ctxSize = 0; } ULONG32 CordbProcess::GetTargetContextSize() @@ -5899,7 +5901,7 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuff // can think of these members as not being part of the context, ie they don't represent something // which gets saved or restored on context switches. They are just space we shouldn't overwrite. // See issue 630276 for more details. - if (targetInfo.arch == IDacDbiInterface::kArchAMD64) + if (targetInfo.os == IDacDbiInterface::kOSWindows && targetInfo.arch == IDacDbiInterface::kArchAMD64) { pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 pCtxSource += offsetof(CONTEXT, ContextFlags); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 4c0a7b28dab094..b3d356c340c644 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -500,7 +500,7 @@ public enum CorDebugSetContextFlags SET_CONTEXT_FLAG_UNWIND_FRAME = 0x2, } -public enum TargetArchitecture +public enum TargetArchitecture : int { Unknown = 0, X86, @@ -512,7 +512,7 @@ public enum TargetArchitecture Wasm, } -public enum TargetOperatingSystem +public enum TargetOperatingSystem : int { Unknown = 0, Windows, From 9ba5f9106103d17b9a2213bbeaa8e36118686452 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Sat, 18 Jul 2026 12:54:47 -0700 Subject: [PATCH 13/26] Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> code review --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 336 +++++++++++------- src/coreclr/debug/daccess/dacdbiimpl.h | 18 +- .../debug/daccess/dacdbiimplstackwalk.cpp | 12 +- src/coreclr/debug/di/cordbregisterset.cpp | 127 ++----- src/coreclr/debug/di/process.cpp | 49 +-- src/coreclr/debug/di/rspriv.h | 46 +-- src/coreclr/debug/di/rsregsetcommon.cpp | 16 +- src/coreclr/debug/di/rsstackwalk.cpp | 30 +- src/coreclr/debug/di/rsthread.cpp | 222 +++++------- src/coreclr/debug/di/shimlocaldatatarget.cpp | 2 +- src/coreclr/debug/di/shimpriv.h | 4 +- src/coreclr/debug/di/shimstackwalk.cpp | 21 +- src/coreclr/debug/di/valuehome.cpp | 14 +- src/coreclr/debug/ee/controller.cpp | 4 +- src/coreclr/debug/ee/debugger.cpp | 2 +- src/coreclr/debug/inc/common.h | 7 +- src/coreclr/debug/inc/dacdbiinterface.h | 49 +-- src/coreclr/debug/inc/dacdbistructures.h | 6 +- src/coreclr/debug/inc/dbgipcevents.h | 14 +- src/coreclr/debug/shared/amd64/primitives.cpp | 8 +- src/coreclr/debug/shared/arm/primitives.cpp | 8 +- src/coreclr/debug/shared/arm64/primitives.cpp | 8 +- src/coreclr/debug/shared/i386/primitives.cpp | 19 +- .../debug/shared/loongarch64/primitives.cpp | 8 +- .../debug/shared/riscv64/primitives.cpp | 8 +- src/coreclr/inc/dacdbi.idl | 29 +- .../StackWalk/Context/AMD64Context.cs | 10 + .../StackWalk/Context/ARM64Context.cs | 10 + .../Contracts/StackWalk/Context/ARMContext.cs | 10 + .../StackWalk/Context/ContextHolder.cs | 2 + .../StackWalk/Context}/FloatConversion.cs | 60 +++- .../Context/IPlatformAgnosticContext.cs | 2 + .../StackWalk/Context/IPlatformContext.cs | 5 + .../StackWalk/Context/LoongArch64Context.cs | 10 + .../StackWalk/Context/RISCV64Context.cs | 10 + .../StackWalk/Context/SimdRegisterAccess.cs | 46 +++ .../Contracts/StackWalk/Context/X86Context.cs | 56 +++ .../Dbi/DacDbiImpl.cs | 263 +++++--------- .../Dbi/IDacDbiInterface.cs | 54 +-- 39 files changed, 818 insertions(+), 787 deletions(-) rename src/native/managed/cdac/{Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers => Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context}/FloatConversion.cs (60%) create mode 100644 src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/SimdRegisterAccess.cs diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 22679644979880..972e1d03de9055 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5027,7 +5027,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::Hijack(VMPTR_Thread vmThread, ULO } // Return the filter CONTEXT on the LS. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Thread vmThread, OUT VMPTR_CONTEXT * pRetVal) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Thread vmThread, OUT CORDB_ADDRESS * pRetVal) { DD_ENTER_MAY_THROW; @@ -5035,13 +5035,13 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Th EX_TRY { - VMPTR_CONTEXT vmContext = VMPTR_CONTEXT::NullPtr(); + CORDB_ADDRESS contextAddr = (CORDB_ADDRESS)NULL; Thread * pThread = vmThread.GetDacPtr(); if (pThread->GetInteropDebuggingHijacked()) { _ASSERTE(!ISREDIRECTEDTHREAD(pThread)); - vmContext = VMPTR_CONTEXT::NullPtr(); + contextAddr = (CORDB_ADDRESS)NULL; } else { @@ -5049,7 +5049,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Th if (pLSContext != NULL) { _ASSERTE(!ISREDIRECTEDTHREAD(pThread)); - vmContext.SetHostPtr(pLSContext); + contextAddr = (CORDB_ADDRESS)PTR_HOST_TO_TADDR(pLSContext); } else if (ISREDIRECTEDTHREAD(pThread)) { @@ -5058,12 +5058,12 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetManagedStoppedContext(VMPTR_Th if (pLSContext != NULL) { - vmContext.SetHostPtr(pLSContext); + contextAddr = (CORDB_ADDRESS)PTR_HOST_TO_TADDR(pLSContext); } } } - *pRetVal = vmContext; + *pRetVal = contextAddr; } EX_CATCH_HRESULT(hr); return hr; @@ -5514,70 +5514,27 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, return hr; } -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetContextSize(ULONG32 contextFlags, OUT ULONG32 * pSize) { DD_ENTER_MAY_THROW; if (pSize == NULL) return E_INVALIDARG; - switch (flags) - { - case kContextSizeBase: #if defined(DT_CONTEXT_EXTENDED_REGISTERS) + if ((contextFlags & DT_CONTEXT_EXTENDED_REGISTERS) != DT_CONTEXT_EXTENDED_REGISTERS) + { *pSize = offsetof(DT_CONTEXT, ExtendedRegisters); -#else - *pSize = sizeof(DT_CONTEXT); + } + else #endif - break; - - case kContextSizeExtendedRegisters: + { *pSize = sizeof(DT_CONTEXT); - break; - - default: - return E_INVALIDARG; } return S_OK; } -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetInfo(OUT TargetInfo * pTargetInfo) -{ - DD_ENTER_MAY_THROW; - - if (pTargetInfo == NULL) - return E_INVALIDARG; - -#if defined(TARGET_X86) - pTargetInfo->arch = kArchX86; -#elif defined(TARGET_AMD64) - pTargetInfo->arch = kArchAMD64; -#elif defined(TARGET_ARM) - pTargetInfo->arch = kArchArm; -#elif defined(TARGET_ARM64) - pTargetInfo->arch = kArchArm64; -#elif defined(TARGET_LOONGARCH64) - pTargetInfo->arch = kArchLoongArch64; -#elif defined(TARGET_RISCV64) - pTargetInfo->arch = kArchRiscV64; -#elif defined(TARGET_WASM) - pTargetInfo->arch = kArchWasm; -#else - pTargetInfo->arch = kArchUnknown; -#endif - -#if defined(TARGET_UNIX) - pTargetInfo->os = kOSUnix; -#elif defined(TARGET_WINDOWS) - pTargetInfo->os = kOSWindows; -#else - pTargetInfo->os = kOSUnknown; -#endif - - return S_OK; -} - static UINT_PTR * GetRegisterSlotFromContext(BYTE * ctxBuf, CorDebugRegister reg) { DT_CONTEXT * pCtx = (DT_CONTEXT *)ctxBuf; @@ -5718,11 +5675,16 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::WriteRegistersToContext( return S_OK; } +namespace +{ + bool TryReadFloatRegisterFromContext(BYTE * ctxBuf, CorDebugRegister reg, DOUBLE * pValue); +} + HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadRegistersFromContext( IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, - OUT TADDR * pValues) + OUT CORDB_REGISTER * pValues) { DD_ENTER_MAY_THROW; @@ -5733,9 +5695,18 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadRegistersFromContext( for (ULONG32 i = 0; i < nRegs; i++) { - // Registers with no CONTEXT slot (e.g. float / SIMD registers) read as zero. UINT_PTR * pSlot = GetRegisterSlotFromContext(contextBuffer.pContextBytes, regs[i]); - pValues[i] = (pSlot != NULL) ? (TADDR)*pSlot : (TADDR)0; + if (pSlot != NULL) + { + pValues[i] = (CORDB_REGISTER)(UINT_PTR)*pSlot; + continue; + } + + DOUBLE floatValue = 0.0; + if (TryReadFloatRegisterFromContext(contextBuffer.pContextBytes, regs[i], &floatValue)) + memcpy(&pValues[i], &floatValue, sizeof(CORDB_REGISTER)); + else + pValues[i] = (CORDB_REGISTER)0; } return S_OK; } @@ -5909,18 +5880,30 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CopyContext( if (destinationContext.pContextBytes == NULL || sourceContext.pContextBytes == NULL) return E_INVALIDARG; - if (destinationContext.contextSize < sizeof(DT_CONTEXT) || sourceContext.contextSize < sizeof(DT_CONTEXT)) + + // The chunk-wise copy below only touches the CONTEXT regions selected by the + // ContextFlags. + if (!CheckContextSizeForBuffer(sourceContext.contextSize, sourceContext.pContextBytes)) return E_INVALIDARG; - // flags != 0 stamps the destination's ContextFlags before the copy, so the - // chunk-wise copy below pulls exactly the requested pieces from the source. - // flags == 0 preserves the destination's existing ContextFlags. if (flags != 0) + { + // flags != 0 stamps the destination's ContextFlags before the copy, so the + // chunk-wise copy pulls exactly the requested pieces from the source. + if (!CheckContextSizeForFlags(destinationContext.contextSize, flags)) + return E_INVALIDARG; reinterpret_cast(destinationContext.pContextBytes)->ContextFlags = flags; + } + else + { + // flags == 0 preserves the destination's existing ContextFlags. + if (!CheckContextSizeForBuffer(destinationContext.contextSize, destinationContext.pContextBytes)) + return E_INVALIDARG; + } CORDbgCopyThreadContext( - reinterpret_cast(destinationContext.pContextBytes), - reinterpret_cast(sourceContext.pContextBytes)); + destinationContext.pContextBytes, destinationContext.contextSize, + sourceContext.pContextBytes, sourceContext.contextSize); return S_OK; } @@ -6032,26 +6015,137 @@ namespace return BitsToDouble(sign | result); } - double Reinterpret64ToDouble(const BYTE * slot) + UINT64 DoubleToBits(double d) { - double d; - memcpy(&d, slot, sizeof(double)); - return d; + UINT64 bits; + memcpy(&bits, &d, sizeof(UINT64)); + return bits; + } + + void X87DoubleToExtended(double value, BYTE * slot10) + { + UINT64 bits = DoubleToBits(value); + UINT64 sign = (bits >> 63) & 1; + UINT32 exp = (UINT32)((bits >> 52) & 0x7FF); + UINT64 frac = bits & ((1ULL << 52) - 1); + + UINT64 mant; // 64-bit significand with explicit integer bit at 63 + UINT16 signExp; // sign (bit 15) + 15-bit biased exponent + + if (exp == 0x7FF) + { + // Infinity or NaN: max exponent, integer bit set. Preserve the NaN + // payload (shifted into the extended fraction) and force it quiet. + mant = (1ULL << 63) | (frac << 11); + if (frac != 0) + mant |= (1ULL << 62); // quiet bit + signExp = (UINT16)((sign << 15) | 0x7FFF); + } + else if (exp == 0 && frac == 0) + { + // Signed zero. + mant = 0; + signExp = (UINT16)(sign << 15); + } + else if (exp == 0) + { + // Binary64 subnormal: normalize into the wider extended exponent range. + // value = frac * 2^(-1074); shift the leading fraction bit up to bit 63. + int leadingZeros = 0; + UINT64 m = frac; + while ((m & (1ULL << 51)) == 0) + { + m <<= 1; + leadingZeros++; + } + mant = m << 12; // integer bit lands at 63 + int e = -1023 - leadingZeros + 16383; // rebias to extended + signExp = (UINT16)((sign << 15) | (UINT32)(e & 0x7FFF)); + } + else + { + // Normal: prepend the implicit integer bit, align to bit 63, rebias. + mant = ((1ULL << 52) | frac) << 11; + int e = (int)exp - 1023 + 16383; + signExp = (UINT16)((sign << 15) | (UINT32)(e & 0x7FFF)); + } + + memcpy(slot10, &mant, sizeof(UINT64)); + memcpy(slot10 + 8, &signExp, sizeof(UINT16)); + } + + // Read a single floating-point / SIMD register from a target CONTEXT buffer. + bool TryReadFloatRegisterFromContext(BYTE * ctxBuf, CorDebugRegister reg, DOUBLE * pValue) + { + DT_CONTEXT * pCtx = (DT_CONTEXT *)ctxBuf; + +#if defined(TARGET_X86) + if ((int)reg < REGISTER_X86_FPSTACK_0 || (int)reg > REGISTER_X86_FPSTACK_7) + return false; + + const DT_FLOATING_SAVE_AREA * pFp = &pCtx->FloatSave; + ULONG32 rawTop = (pFp->StatusWord >> 11) & 0x7; + ULONG32 floatStackTop = 7 - rawTop; + ULONG32 logical = (ULONG32)((int)reg - REGISTER_X86_FPSTACK_0); + + // The availability mask exposes all 8 FPSTACK registers even when the + // live stack is shallower; those out-of-depth slots read 0. + if (logical > floatStackTop) + { + *pValue = 0.0; + return true; + } + + // REGISTER_X86_FPSTACK_0 names the bottom of the logical stack, so a + // logical index counts up from the bottom: ST(i) with i = top - logical. + ULONG32 physIdx = (rawTop + (floatStackTop - logical)) & 0x7; + *pValue = X87ExtendedToDouble((const BYTE *)pFp->RegisterArea + physIdx * 10); + return true; +#elif defined(TARGET_AMD64) + if ((int)reg < REGISTER_AMD64_XMM0 || (int)reg > REGISTER_AMD64_XMM0 + 15) + return false; + memcpy(pValue, (const BYTE *)&pCtx->Xmm0 + (ULONG32)((int)reg - REGISTER_AMD64_XMM0) * 16, sizeof(DOUBLE)); + return true; +#elif defined(TARGET_ARM64) + if ((int)reg < REGISTER_ARM64_V0 || (int)reg > REGISTER_ARM64_V0 + 31) + return false; + memcpy(pValue, (const BYTE *)&pCtx->V + (ULONG32)((int)reg - REGISTER_ARM64_V0) * 16, sizeof(DOUBLE)); + return true; +#elif defined(TARGET_LOONGARCH64) + if ((int)reg < REGISTER_LOONGARCH64_F0 || (int)reg > REGISTER_LOONGARCH64_F0 + 31) + return false; + memcpy(pValue, (const BYTE *)&pCtx->F + (ULONG32)((int)reg - REGISTER_LOONGARCH64_F0) * 32, sizeof(DOUBLE)); + return true; +#elif defined(TARGET_RISCV64) + if ((int)reg < REGISTER_RISCV64_F0 || (int)reg > REGISTER_RISCV64_F0 + 31) + return false; + memcpy(pValue, (const BYTE *)&pCtx->F + (ULONG32)((int)reg - REGISTER_RISCV64_F0) * 8, sizeof(DOUBLE)); + return true; +#elif defined(TARGET_ARM) + if ((int)reg < REGISTER_ARM_D0 || (int)reg > REGISTER_ARM_D0 + 31) + return false; + memcpy(pValue, (const BYTE *)&pCtx->D + (ULONG32)((int)reg - REGISTER_ARM_D0) * 8, sizeof(DOUBLE)); + return true; +#else + UNREFERENCED_PARAMETER(pCtx); + UNREFERENCED_PARAMETER(reg); + UNREFERENCED_PARAMETER(pValue); + return false; +#endif } } -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( +// Write a single floating-point / SIMD register into a target CONTEXT buffer. +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::WriteFloatRegisterToContext( IN ContextBuffer contextBuffer, - IN ULONG32 maxValues, - OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], - OUT ULONG32 * pValuesCount, - OUT int * pFirstFloatReg, - OUT ULONG32 * pFloatStackTop) + IN CorDebugRegister reg, + IN const BYTE * pValue, + IN ULONG32 valueSize) { DD_ENTER_MAY_THROW; - if (contextBuffer.pContextBytes == NULL || values == NULL || pValuesCount == NULL || - pFirstFloatReg == NULL || pFloatStackTop == NULL || maxValues == 0) + if (contextBuffer.pContextBytes == NULL || pValue == NULL || + (valueSize != sizeof(float) && valueSize != sizeof(double))) { return E_INVALIDARG; } @@ -6060,69 +6154,49 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ReadFloatRegistersFromContext( DT_CONTEXT * pCtx = reinterpret_cast(contextBuffer.pContextBytes); - *pValuesCount = 0; - *pFirstFloatReg = -1; - *pFloatStackTop = 0; - memset(values, 0, sizeof(DOUBLE) * maxValues); - #if defined(TARGET_X86) - const DT_FLOATING_SAVE_AREA * pFp = &pCtx->FloatSave; - ULONG32 rawTop = (pFp->StatusWord >> 11) & 0x7; - ULONG32 floatStackTop = 7 - rawTop; - *pFloatStackTop = floatStackTop; - *pFirstFloatReg = REGISTER_X86_FPSTACK_0; + if ((int)reg < REGISTER_X86_FPSTACK_0 || (int)reg > REGISTER_X86_FPSTACK_7) + return E_INVALIDARG; - ULONG32 count = floatStackTop + 1; - if (count > maxValues) - count = maxValues; - *pValuesCount = count; + DT_FLOATING_SAVE_AREA * pFp = &pCtx->FloatSave; + ULONG32 rawTop = (pFp->StatusWord >> 11) & 0x7; + ULONG32 floatStackTop = 7 - rawTop; + ULONG32 logical = (ULONG32)((int)reg - REGISTER_X86_FPSTACK_0); + if (logical > floatStackTop) + return E_INVALIDARG; - const BYTE * regArea = (const BYTE *)pFp->RegisterArea; - for (ULONG32 i = 0; i < count; i++) - { - ULONG32 physIdx = (rawTop + i) & 0x7; - values[i] = X87ExtendedToDouble(regArea + physIdx * 10); - } + // REGISTER_X86_FPSTACK_0 names the bottom of the logical stack: ST(i) with + // i = top - logical. Map to the physical RegisterArea slot and re-encode. + ULONG32 physIdx = (rawTop + (floatStackTop - logical)) & 0x7; + BYTE * slot = (BYTE *)pFp->RegisterArea + physIdx * 10; + double d = (valueSize == sizeof(float)) ? (double)(*(const float *)pValue) + : *(const double *)pValue; + X87DoubleToExtended(d, slot); #elif defined(TARGET_AMD64) - const BYTE * base = (const BYTE *)&pCtx->Xmm0; - ULONG32 count = 16; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = REGISTER_AMD64_XMM0; - for (ULONG32 i = 0; i < count; i++) - values[i] = Reinterpret64ToDouble(base + i * 16); + if ((int)reg < REGISTER_AMD64_XMM0 || (int)reg > REGISTER_AMD64_XMM0 + 15) + return E_INVALIDARG; + memcpy((BYTE *)&pCtx->Xmm0 + (ULONG32)((int)reg - REGISTER_AMD64_XMM0) * 16, pValue, valueSize); #elif defined(TARGET_ARM64) - const BYTE * base = (const BYTE *)&pCtx->V; - ULONG32 count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = REGISTER_ARM64_V0; - for (ULONG32 i = 0; i < count; i++) - values[i] = Reinterpret64ToDouble(base + i * 16); -#elif defined(TARGET_ARM) - const BYTE * base = (const BYTE *)&pCtx->D; - ULONG32 count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - for (ULONG32 i = 0; i < count; i++) - values[i] = Reinterpret64ToDouble(base + i * 8); + if ((int)reg < REGISTER_ARM64_V0 || (int)reg > REGISTER_ARM64_V0 + 31) + return E_INVALIDARG; + memcpy((BYTE *)&pCtx->V + (ULONG32)((int)reg - REGISTER_ARM64_V0) * 16, pValue, valueSize); #elif defined(TARGET_LOONGARCH64) - const BYTE * base = (const BYTE *)&pCtx->F; - ULONG32 count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = REGISTER_LOONGARCH64_F0; - for (ULONG32 i = 0; i < count; i++) - values[i] = Reinterpret64ToDouble(base + i * 32); + if ((int)reg < REGISTER_LOONGARCH64_F0 || (int)reg > REGISTER_LOONGARCH64_F0 + 31) + return E_INVALIDARG; + memcpy((BYTE *)&pCtx->F + (ULONG32)((int)reg - REGISTER_LOONGARCH64_F0) * 32, pValue, valueSize); #elif defined(TARGET_RISCV64) - const BYTE * base = (const BYTE *)&pCtx->F; - ULONG32 count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = REGISTER_RISCV64_F0; - for (ULONG32 i = 0; i < count; i++) - values[i] = Reinterpret64ToDouble(base + i * 8); + if ((int)reg < REGISTER_RISCV64_F0 || (int)reg > REGISTER_RISCV64_F0 + 31) + return E_INVALIDARG; + memcpy((BYTE *)&pCtx->F + (ULONG32)((int)reg - REGISTER_RISCV64_F0) * 8, pValue, valueSize); +#elif defined(TARGET_ARM) + if ((int)reg < REGISTER_ARM_D0 || (int)reg > REGISTER_ARM_D0 + 31) + return E_INVALIDARG; + memcpy((BYTE *)&pCtx->D + (ULONG32)((int)reg - REGISTER_ARM_D0) * 8, pValue, valueSize); #else + UNREFERENCED_PARAMETER(pCtx); + UNREFERENCED_PARAMETER(reg); + UNREFERENCED_PARAMETER(pValue); + UNREFERENCED_PARAMETER(valueSize); return E_NOTIMPL; #endif diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index be0b99febf12bf..99d727b3e9ec8e 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -151,21 +151,17 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE EnumerateAsyncLocals(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeAddr, UINT32 state, FP_ASYNC_LOCAL_CALLBACK fpCallback, CALLBACK_DATA pUserData); HRESULT STDMETHODCALLTYPE GetGenericArgTokenIndex(VMPTR_MethodDesc vmMethod, OUT UINT32* pIndex); - HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize); + HRESULT STDMETHODCALLTYPE GetTargetContextSize(ULONG32 contextFlags, OUT ULONG32 * pSize); HRESULT STDMETHODCALLTYPE WriteRegistersToContext(IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, IN const TADDR * values); - HRESULT STDMETHODCALLTYPE ReadRegistersFromContext(IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT TADDR * pValues); + HRESULT STDMETHODCALLTYPE ReadRegistersFromContext(IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, OUT CORDB_REGISTER * pValues); HRESULT STDMETHODCALLTYPE GetAvailableRegistersMask(IN BOOL fActive, IN BOOL fQuickUnwind, IN ULONG32 regCount, OUT BYTE pAvailable[]); HRESULT STDMETHODCALLTYPE ConvertJitRegNumToCorDebugRegister(IN ULONG32 jitRegNum, OUT CorDebugRegister * pReg); - HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( + HRESULT STDMETHODCALLTYPE WriteFloatRegisterToContext( IN ContextBuffer contextBuffer, - IN ULONG32 regCount, - OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], - OUT ULONG32 * pValuesCount, - OUT int * pFirstFloatReg, - OUT ULONG32 * pFloatStackTop); - - HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); + IN CorDebugRegister reg, + IN const BYTE * pValue, + IN ULONG32 valueSize); HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters(IN ContextBuffer contextBuffer, OUT BOOL * pResult); @@ -689,7 +685,7 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE Hijack(VMPTR_Thread vmThread, ULONG32 dwThreadId, const EXCEPTION_RECORD * pRecord, T_CONTEXT * pOriginalContext, ULONG32 cbSizeContext, EHijackReason::EHijackReason reason, void * pUserData, CORDB_ADDRESS * pRemoteContextAddr); // Return the filter CONTEXT on the LS. - HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT VMPTR_CONTEXT * pRetVal); + HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT CORDB_ADDRESS * pRetVal); // Create and return a stackwalker on the specified thread. HRESULT STDMETHODCALLTYPE CreateStackWalk(VMPTR_Thread vmThread, ContextBuffer contextBuffer, OUT StackWalkHandle * ppSFIHandle); diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index f7d46bb9d2400e..66ab549439fc6c 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -579,9 +579,9 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thr Frame * pFrame = pThread->GetFrame(); AppDomain * pAppDomain = AppDomain::GetCurrentDomain(); - // cStubFrame entries have no DT_CONTEXT buffer; leave ctx as NULL so consumers + // cStubFrame entries have no DT_CONTEXT buffer; leave ctx empty so consumers // (and the cDAC cross-check, which sets ctx = 0) don't observe a garbage value. - frameData.ctx = NULL; + frameData.ctx = {}; frameData.eType = Debugger_STRData::cStubFrame; while (pFrame != FRAME_TOP) @@ -812,8 +812,8 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, { pFrameData->eType = Debugger_STRData::cRuntimeNativeFrame; - _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx)); + _ASSERTE(pFrameData->ctx.pContextBytes != NULL); + GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx.pContextBytes)); } else if (ft == kManagedStackFrame) { @@ -843,8 +843,8 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, pFrameData->eType = Debugger_STRData::cMethodFrame; - _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx)); + _ASSERTE(pFrameData->ctx.pContextBytes != NULL); + GetStackWalkCurrentContext(pIter, reinterpret_cast(pFrameData->ctx.pContextBytes)); // // initialize the fields in Debugger_STRData::v diff --git a/src/coreclr/debug/di/cordbregisterset.cpp b/src/coreclr/debug/di/cordbregisterset.cpp index 58a496ca1b52a7..a06f6956e9fda3 100644 --- a/src/coreclr/debug/di/cordbregisterset.cpp +++ b/src/coreclr/debug/di/cordbregisterset.cpp @@ -10,17 +10,11 @@ // single byte-form DDI: IDacDbiInterface::GetAvailableRegistersMask. The DAC // owns the per-arch policy that gates float visibility (active-only on // x86 / amd64, suppressed on arm, always on for arm64 / loongarch64 / -// riscv64), so this file no longer reasons about it. +// riscv64). // -// GPR register VALUES come from the cached target CONTEXT byte buffer -// (m_pContext) via a single batched IDacDbiInterface::ReadRegistersFromContext -// call. Float / SIMD register VALUES come from the thread's float cache -// (IDacDbiInterface::ReadFloatRegistersFromContext, loaded up front so the -// requested bits can be partitioned into a GPR batch and a float batch). -// -// The single remaining per-arch wart here is the x87 stack-relative slot -// inversion on x86 (REGISTER_X86_FPSTACK_N points to a stack-relative -// position, not a physical slot). +// Register VALUES (both GPR and float / SIMD) come from the single target +// CONTEXT byte buffer (m_contextBuffer) via one batched +// IDacDbiInterface::ReadRegistersFromContext call. // //***************************************************************************** #include "stdafx.h" @@ -28,34 +22,13 @@ namespace { - // Read the float-state cache, loading it on demand. Returns S_OK if the - // cache is populated (or there's nothing to do); failure HRESULT if - // LoadFloatState failed. - HRESULT EnsureFloatStateLoaded(CordbThread * pThread) - { - if (pThread->m_fFloatStateValid) - return S_OK; - - HRESULT hr = S_OK; - EX_TRY - { - pThread->LoadFloatState(); - } - EX_CATCH_HRESULT(hr); - if (FAILED(hr)) - return hr; - - LOG((LF_CORDB, LL_INFO1000, "CRS::GR: Loaded float state\n")); - return S_OK; - } - // Buffer size for the byte-form availability mask. arm64 needs 9 bytes // (REGISTER_ARM64_V31 is bit 64); 16 bytes covers every arch with room // to spare without forcing dynamic allocation. constexpr ULONG32 kAvailMaskBytes = 16; // Upper bound on distinct register bit positions (kAvailMaskBytes * 8), - // used to size the batched GPR request/value arrays on the stack. + // used to size the batched request array on the stack. constexpr ULONG32 kMaxRegisters = kAvailMaskBytes * 8; inline bool MaskBitSet(const BYTE * mask, ULONG32 maskCount, int bit) @@ -68,93 +41,39 @@ namespace // Shared GetRegisters core. Validates that every bit set in the caller's // request is also set in the available mask (E_INVALIDARG otherwise), then - // fills regBuffer in ascending bit order. The requested bits are partitioned - // into two batches: GPR bits are read in a single ReadRegistersFromContext - // call, and float bits are served from the thread's float cache. + // fills regBuffer in ascending bit order by reading the target CONTEXT. HRESULT FillRegisters(IDacDbiInterface * pDAC, ContextBuffer contextBuffer, - CordbThread * pThread, const BYTE * requestMask, ULONG32 requestMaskCount, const BYTE * availMask, ULONG32 availMaskCount, ULONG32 regCount, CORDB_REGISTER regBuffer[]) { - // Validate request is a subset of available. + // Validate the request is a subset of the available registers. for (ULONG32 b = 0; b < requestMaskCount * 8; b++) { - if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) - continue; - if (!MaskBitSet(availMask, availMaskCount, (int)b)) + if (MaskBitSet(requestMask, requestMaskCount, (int)b) && + !MaskBitSet(availMask, availMaskCount, (int)b)) + { return E_INVALIDARG; + } } - // Load the float cache up front so its register range can classify the - // requested bits into GPR and float batches. - HRESULT hr = EnsureFloatStateLoaded(pThread); - bool areFloatsValid = !!SUCCEEDED(hr); - - int firstFloat = -1; - int lastFloat = -1; - if (pThread->m_floatValuesCount > 0 && pThread->m_firstFloatReg >= 0 && areFloatsValid) - { - firstFloat = pThread->m_firstFloatReg; - lastFloat = firstFloat + (int)pThread->m_floatValuesCount - 1; - } - - auto IsFloatBit = [firstFloat, lastFloat](int b) - { - return firstFloat >= 0 && b >= firstFloat && b <= lastFloat; - }; - - // First pass: collect the GPR register ids (ascending bit order) for the - // batched read. - CorDebugRegister gprRegs[kMaxRegisters]; - TADDR gprValues[kMaxRegisters]; - ULONG32 gprCount = 0; - for (ULONG32 b = 0; b < requestMaskCount * 8; b++) + // Collect the requested register ids (ascending bit order), bounded by + // the caller's buffer, then read them all from the context at once. + CorDebugRegister requestedRegs[kMaxRegisters]; + ULONG32 requestedCount = 0; + for (ULONG32 b = 0; b < requestMaskCount * 8 && requestedCount < regCount; b++) { if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) continue; - if (IsFloatBit((int)b)) - continue; - if (gprCount >= kMaxRegisters) + if (requestedCount >= kMaxRegisters) return E_FAIL; - gprRegs[gprCount++] = (CorDebugRegister)b; + requestedRegs[requestedCount++] = (CorDebugRegister)b; } - if (gprCount > 0) - { - hr = pDAC->ReadRegistersFromContext(contextBuffer, gprRegs, gprCount, gprValues); - if (FAILED(hr)) - return hr; - } - - // Second pass: fill regBuffer in ascending bit order, consuming from the - // GPR batch and the float cache. - UINT iRegister = 0; - ULONG32 gprIdx = 0; - for (ULONG32 b = 0; b < requestMaskCount * 8 && iRegister < regCount; b++) - { - if (!MaskBitSet(requestMask, requestMaskCount, (int)b)) - continue; - - if (IsFloatBit((int)b)) - { - ULONG32 idx = (ULONG32)((int)b - firstFloat); -#if defined(TARGET_X86) - // x86 storage is pop-physical order: m_floatValues[0] = ST(0) - // = top of stack. REGISTER_X86_FPSTACK_0 is the logical name - // of the BOTTOM of the stack, so flip. - idx = (ULONG32)(pThread->m_floatStackTop - ((int)b - REGISTER_X86_FPSTACK_0)); -#endif - memcpy(®Buffer[iRegister++], &pThread->m_floatValues[idx], sizeof(CORDB_REGISTER)); - } - else - { - regBuffer[iRegister++] = (CORDB_REGISTER)gprValues[gprIdx++]; - } - } + if (requestedCount > 0) + return pDAC->ReadRegistersFromContext(contextBuffer, requestedRegs, requestedCount, regBuffer); - _ASSERTE(iRegister <= regCount); return S_OK; } } // anonymous namespace @@ -206,8 +125,7 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG64 mask, ULONG32 regCount, requestBytes[b / 8] |= (BYTE)(1 << (b % 8)); } - ContextBuffer contextBuffer = { m_pContext, m_contextSize }; - return FillRegisters(pDAC, contextBuffer, m_thread, + return FillRegisters(pDAC, m_contextBuffer, requestBytes, (ULONG32)sizeof(requestBytes), availBytes, kAvailMaskBytes, regCount, regBuffer); } @@ -238,8 +156,7 @@ HRESULT CordbRegisterSet::GetRegisters(ULONG32 maskCount, BYTE mask[], if (FAILED(hr)) return hr; - ContextBuffer contextBuffer = { m_pContext, m_contextSize }; - return FillRegisters(pDAC, contextBuffer, m_thread, + return FillRegisters(pDAC, m_contextBuffer, mask, maskCount, availBytes, kAvailMaskBytes, regCount, regBuffer); } diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 01a340cf57c6b8..16de37d13a72eb 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -1463,7 +1463,7 @@ ULONG32 CordbProcess::GetTargetContextSize() if (m_ctxSize == 0) { ULONG32 size = 0; - IfFailThrow(GetDAC()->GetTargetContextSize(IDacDbiInterface::kContextSizeExtendedRegisters, &size)); + IfFailThrow(GetDAC()->GetTargetContextSize(DT_CONTEXT_ALL, &size)); m_ctxSize = size; } return m_ctxSize; @@ -5812,7 +5812,7 @@ HRESULT CordbProcess::IsOSSuspended(DWORD threadID, BOOL *pbSuspended) // This routine reads a thread context from the process being debugged, taking into account the fact that the context // record may be a different size than the one we compiled with. // -HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, ContextBuffer contextBuffer) +HRESULT CordbProcess::SafeReadThreadContext(CORDB_ADDRESS remoteContextAddr, ContextBuffer contextBuffer) { HRESULT hr = S_OK; @@ -5821,14 +5821,13 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, ContextBuffe EX_TRY { - void *pRemoteContext = pContext.UnsafeGet(); ULONG32 fullContextSize = GetTargetContextSize(); if ((contextBuffer.pContextBytes == NULL) || (contextBuffer.contextSize < fullContextSize)) { ThrowHR(E_INVALIDARG); } - TargetBuffer tbFull(pRemoteContext, fullContextSize); + TargetBuffer tbFull(remoteContextAddr, fullContextSize); // The context may have 2 parts: // 1. Base register, which are always present. @@ -5837,7 +5836,7 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, ContextBuffe // At a minimum we have room for a whole context up to the extended registers. ULONG32 minContextSize; - IfFailThrow(GetDAC()->GetTargetContextSize(IDacDbiInterface::kContextSizeBase, &minContextSize)); + IfFailThrow(GetDAC()->GetTargetContextSize(DT_CONTEXT_FULL, &minContextSize)); // Read the minimum part. TargetBuffer tbMin = tbFull.SubBuffer(0, minContextSize); @@ -5869,7 +5868,7 @@ HRESULT CordbProcess::SafeReadThreadContext(LSPTR_CONTEXT pContext, ContextBuffe // This routine writes a thread context to the process being debugged, taking into account the fact that the context // record may be a different size than the one we compiled with. // -HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuffer contextBuffer) +HRESULT CordbProcess::SafeWriteThreadContext(CORDB_ADDRESS remoteContextAddr, ContextBuffer contextBuffer) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); @@ -5879,20 +5878,18 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuff return E_INVALIDARG; } + HRESULT hr = S_OK; EX_TRY { - HRESULT hr = S_OK; ULONG32 sizeToWrite; BOOL hasExtendedRegisters = FALSE; IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); IfFailThrow(GetDAC()->GetTargetContextSize( - hasExtendedRegisters ? IDacDbiInterface::kContextSizeExtendedRegisters : IDacDbiInterface::kContextSizeBase, + hasExtendedRegisters ? DT_CONTEXT_ALL : DT_CONTEXT_FULL, &sizeToWrite)); - IDacDbiInterface::TargetInfo targetInfo; - BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); + CORDB_ADDRESS pRemoteContext = remoteContextAddr; BYTE * pCtxSource = contextBuffer.pContextBytes; - IfFailThrow(GetDAC()->GetTargetInfo(&targetInfo)); // 64 bit windows puts space for the first 6 stack parameters in the CONTEXT structure so that // kernel to usermode transitions don't have to allocate a CONTEXT and do a separate sub rsp @@ -5901,12 +5898,11 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuff // can think of these members as not being part of the context, ie they don't represent something // which gets saved or restored on context switches. They are just space we shouldn't overwrite. // See issue 630276 for more details. - if (targetInfo.os == IDacDbiInterface::kOSWindows && targetInfo.arch == IDacDbiInterface::kArchAMD64) - { - pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 - pCtxSource += offsetof(CONTEXT, ContextFlags); - sizeToWrite -= offsetof(CONTEXT, ContextFlags); - } +#if defined TARGET_AMD64 + pRemoteContext += offsetof(CONTEXT, ContextFlags); // immediately follows the 6 parameters P1-P6 + pCtxSource += offsetof(CONTEXT, ContextFlags); + sizeToWrite -= offsetof(CONTEXT, ContextFlags); +#endif // Write the context. TargetBuffer tb(pRemoteContext, sizeToWrite); @@ -5917,7 +5913,7 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, ContextBuff return hr; } -HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, T_CONTEXT * pCtx) +HRESULT CordbProcess::SafeWriteThreadContext(CORDB_ADDRESS remoteContextAddr, T_CONTEXT * pCtx) { INTERNAL_API_ENTRY(this); FAIL_IF_NEUTERED(this); @@ -5925,7 +5921,6 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, T_CONTEXT * HRESULT hr = S_OK; DWORD sizeToWrite = sizeof(T_CONTEXT); - BYTE * pRemoteContext = (BYTE*) pContext.UnsafeGet(); BYTE * pCtxSource = (BYTE*) pCtx; @@ -5938,7 +5933,7 @@ HRESULT CordbProcess::SafeWriteThreadContext(LSPTR_CONTEXT pContext, T_CONTEXT * EX_TRY { - TargetBuffer tb(pRemoteContext, sizeToWrite); + TargetBuffer tb(remoteContextAddr, sizeToWrite); SafeWriteBuffer(tb, (const BYTE*) pCtxSource); } EX_CATCH_HRESULT(hr); @@ -5970,6 +5965,12 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE return E_INVALIDARG; } + if (contextSize < sizeof(T_CONTEXT)) + { + LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID)); + return E_INVALIDARG; + } + return ut->GetThreadContext(reinterpret_cast(context)); #else return E_NOTIMPL; @@ -6046,6 +6047,12 @@ HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE return E_INVALIDARG; } + if (contextSize < sizeof(T_CONTEXT)) + { + LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, context size is invalid.\n", threadID)); + return E_INVALIDARG; + } + hr = ut->SetThreadContext(reinterpret_cast(context)); // Update the register set for the leaf-unmanaged chain so that it's consistent w/ the context. @@ -12793,7 +12800,7 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven _ASSERTE(fcd.pLeftSideContext != NULL); LOG((LF_CORDB, LL_INFO10000, "W32ET::W32EL: updating LS context at 0x%p\n", fcd.pLeftSideContext)); // write the new context over the old one on the LS - SafeWriteThreadContext(fcd.pLeftSideContext, &tempContext); + SafeWriteThreadContext(fcd.pLeftSideContext.UnsafeGetAddr(), &tempContext); } // Write the new Fcd data to the LS diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index 33fdf3f36d5c29..614de00725cb4b 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -3583,9 +3583,9 @@ class CordbProcess : void AddToLeftSideResourceCleanupList(CordbBase * pObject); // Routines to read and write thread context records between the processes safely. - HRESULT SafeReadThreadContext(LSPTR_CONTEXT pRemoteContext, ContextBuffer contextBuffer); - HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, ContextBuffer contextBuffer); - HRESULT SafeWriteThreadContext(LSPTR_CONTEXT pRemoteContext, T_CONTEXT * pCtx); + HRESULT SafeReadThreadContext(CORDB_ADDRESS remoteContextAddr, ContextBuffer contextBuffer); + HRESULT SafeWriteThreadContext(CORDB_ADDRESS remoteContextAddr, ContextBuffer contextBuffer); + HRESULT SafeWriteThreadContext(CORDB_ADDRESS remoteContextAddr, T_CONTEXT * pCtx); #ifdef FEATURE_INTEROP_DEBUGGING // Record a win32 event for debugging purposes. @@ -6081,9 +6081,6 @@ class CordbThread : public CordbBase, public ICorDebugThread, void MarkStackFramesDirty(); - void LoadFloatState(); - - HRESULT SetIP( bool fCanSetIPOnly, CordbNativeCode * pNativeCode, SIZE_T offset, @@ -6193,7 +6190,7 @@ class CordbThread : public CordbBase, public ICorDebugThread, // (breakpoint / single-step exception) or hijacked w/ a redirected frame because // another thread synced the LS. // This context is used by the RS to set enregistered vars. - VMPTR_CONTEXT m_vmLeftSideContext; + CORDB_ADDRESS m_vmLeftSideContext; // indicates whether m_pContext is up-to-date bool m_fContextFresh; @@ -6225,12 +6222,6 @@ class CordbThread : public CordbBase, public ICorDebugThread, // Instead, we mark m_fFramesFresh in CleanupStack() and clear the cache only when it is used next time. CDynArray m_stackFrames; - bool m_fFloatStateValid; - unsigned int m_floatStackTop; - int m_firstFloatReg; - ULONG32 m_floatValuesCount; - double m_floatValues[CORDB_MAX_FLOAT_REGISTERS]; - private: // True for the window after an Exception callback, but before it's been continued. // We dispatch two exception events in a row (ICDManagedCallback::Exception and ICDManagedCallback2::Exception), @@ -6362,6 +6353,8 @@ class CordbStackWalk : public CordbBase, public ICorDebugStackWalk // unwind the frame and update m_context with the new context BOOL UnwindStackFrame(); + ContextBuffer GetContextBuffer() const { return { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; } + // the thread on which this CordbStackWalk is created CordbThread * m_pCordbThread; @@ -6467,11 +6460,15 @@ class CordbFrame : public CordbBase, public ICorDebugFrame // This is basically a complicated cast function. We are casting from an ICorDebugFrame to a CordbFrame. static CordbFrame* GetCordbFrameFromInterface(ICorDebugFrame *pFrame); - virtual const BYTE * GetContext() const { return NULL; } + virtual const ContextBuffer GetContext() const { return ContextBuffer{}; } // Reads an integer register from this frame's CONTEXT buffer via the DAC. HRESULT ReadContextRegister(CorDebugRegister reg, TADDR * pValue) const; + // Reads a floating-point / SIMD register's scalar value (as a double bit + // pattern) from this frame's CONTEXT buffer via the DAC. + HRESULT ReadFloatContextRegister(CorDebugRegister reg, double * pValue) const; + public: // this represents the IL offset for a CordbJITILFrame, the native offset for a CordbNativeFrame, // and 0 for a CordbInternalFrame @@ -6749,7 +6746,7 @@ class CordbRuntimeUnwindableFrame : public CordbFrame, public ICorDebugRuntimeUn return NULL; } - virtual const BYTE * GetContext() const; + virtual const ContextBuffer GetContext() const; private: NewArrayHolder m_pContextBuffer; @@ -6951,7 +6948,7 @@ class CordbNativeFrame : public CordbFrame, public ICorDebugNativeFrame, public CordbFunction * GetFunction(); CordbNativeCode * GetNativeCode(); - virtual const BYTE * GetContext() const; + virtual const ContextBuffer GetContext() const; // Given the native variable information of a variable, return its value. // This function assumes that the value is either in a register or on the stack @@ -7164,8 +7161,7 @@ class CordbRegisterSet : public CordbBase, public ICorDebugRegisterSet, public I } protected: - BYTE *m_pContext; - ULONG32 m_contextSize; + ContextBuffer m_contextBuffer; CordbThread *m_thread; bool m_active; // true if we're the leafmost register set. bool m_quickUnwind; @@ -8123,11 +8119,14 @@ class FloatRegValueHome: public EnregisteredValueHome // Arguments: // input: pFrame - frame to which the value belongs // index - index into the floating point stack where the value resides + // regNum - CorDebugRegister naming the fp / SIMD register // output: no out parameters, but the instance has been initialized FloatRegValueHome(const CordbNativeFrame * pFrame, - DWORD index): + DWORD index, + CorDebugRegister regNum): EnregisteredValueHome(pFrame), - m_floatIndex(index) + m_floatIndex(index), + m_regNum(regNum) {}; // copy constructor @@ -8137,7 +8136,8 @@ class FloatRegValueHome: public EnregisteredValueHome // output: no out parameters, but the instance has been initialized FloatRegValueHome(const FloatRegValueHome * pRemoteRegAddr): EnregisteredValueHome(pRemoteRegAddr->m_pFrame), - m_floatIndex(pRemoteRegAddr->m_floatIndex) + m_floatIndex(pRemoteRegAddr->m_floatIndex), + m_regNum(pRemoteRegAddr->m_regNum) {}; // make a copy of this instance of FloatRegValueHome @@ -8164,6 +8164,10 @@ class FloatRegValueHome: public EnregisteredValueHome protected: // index into the FP registers for the register in which the floating point value resides const DWORD m_floatIndex; + + // CorDebugRegister naming the fp / SIMD register, used to write the value + // back into the target CONTEXT via the DAC. + const CorDebugRegister m_regNum; }; // class FloatRegValueHome // ---------------------------------------------------------------------------- diff --git a/src/coreclr/debug/di/rsregsetcommon.cpp b/src/coreclr/debug/di/rsregsetcommon.cpp index 7ed399f62946a8..d779f07c5ba3af 100644 --- a/src/coreclr/debug/di/rsregsetcommon.cpp +++ b/src/coreclr/debug/di/rsregsetcommon.cpp @@ -7,7 +7,7 @@ // Common cross-platform behavior of reg sets. The ICorDebugRegisterSet / // ICorDebugRegisterSet2 surface is implemented in CordbRegisterSet.cpp using the // ReadRegistersFromContext / WriteRegistersToContext / GetAvailableRegistersMask -// DDIs; float / SIMD register VALUES come from ReadFloatRegistersFromContext. +// DDIs, which cover both integer (GPR) and floating-point / SIMD registers. // //***************************************************************************** #include "stdafx.h" @@ -33,8 +33,7 @@ CordbRegisterSet::CordbRegisterSet( ThrowHR(E_INVALIDARG); } - m_pContext = contextBuffer.pContextBytes; - m_contextSize = contextBuffer.contextSize; + m_contextBuffer = contextBuffer; m_fOwnsContext = fTakeOwnershipOfContext; m_thread = pThread; m_active = fActive; @@ -56,10 +55,10 @@ void CordbRegisterSet::Neuter() if (m_fOwnsContext) { - delete[] m_pContext; + delete[] m_contextBuffer.pContextBytes; } - m_pContext = NULL; - m_contextSize = 0; + m_contextBuffer.pContextBytes = NULL; + m_contextBuffer.contextSize = 0; CordbBase::Neuter(); } @@ -124,7 +123,7 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) EX_TRY { _ASSERTE( m_thread != NULL ); - if( contextSize < m_contextSize) + if( contextSize < GetProcess()->GetTargetContextSize()) { ThrowHR(E_INVALIDARG); } @@ -164,8 +163,7 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) // Overlay this frame's registers from the cached CONTEXT buffer, honoring the destination's // ContextFlags (the leaf's if copied above, otherwise the caller's incoming flags). ContextBuffer destinationContext = { context, contextSize }; - ContextBuffer sourceContext = { m_pContext, m_contextSize }; - IfFailThrow(pDAC->CopyContext(destinationContext, sourceContext, 0)); + IfFailThrow(pDAC->CopyContext(destinationContext, m_contextBuffer, 0)); } EX_CATCH_HRESULT(hr); return hr; diff --git a/src/coreclr/debug/di/rsstackwalk.cpp b/src/coreclr/debug/di/rsstackwalk.cpp index 5645125afa3181..e23c57f0d7b30e 100644 --- a/src/coreclr/debug/di/rsstackwalk.cpp +++ b/src/coreclr/debug/di/rsstackwalk.cpp @@ -37,10 +37,9 @@ void CordbStackWalk::Init() IDacDbiInterface * pDAC = pProcess->GetDAC(); ULONG32 contextSize = pProcess->GetTargetContextSize(); m_pContextBuffer = new BYTE[contextSize]; - ContextBuffer contextBuffer = { m_pContextBuffer, contextSize }; IfFailThrow(pDAC->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - contextBuffer, + GetContextBuffer(), &m_pSFIHandle)); // see the function header of code:CordbStackWalk::CheckForLegacyHijackCase @@ -79,14 +78,17 @@ void CordbStackWalk::CheckForLegacyHijackCase() { // The GetThreadContext function hides the effects of hijacking and returns the unhijacked context IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + if (GetProcess()->GetTargetContextSize() < sizeof(T_CONTEXT)) + { + ThrowHR(E_FAIL); + } T_CONTEXT * pContext = reinterpret_cast(m_pContextBuffer.GetValue()); pContext->ContextFlags = CONTEXT_FULL; pUT->GetThreadContext(pContext); - ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, SET_CONTEXT_FLAG_ACTIVE_FRAME, - contextBuffer)); + GetContextBuffer())); } } } @@ -209,9 +211,8 @@ void CordbStackWalk::RefreshIfNeeded() DeleteAll(); // create a new stackwalk handle - ContextBuffer contextBuffer = { m_pContextBuffer, pProcess->GetTargetContextSize() }; IfFailThrow(pProcess->GetDAC()->CreateStackWalk(m_pCordbThread->m_vmThreadToken, - contextBuffer, + GetContextBuffer(), &m_pSFIHandle)); // advance the stackwalker to where we originally were @@ -252,7 +253,7 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, // set the required size for the CONTEXT buffer if (pContextSize != NULL) { - *pContextSize = GetProcess()->GetTargetContextSize(); + *pContextSize = ContextSizeForFlags(contextFlags); } // If all the user wants to know is the CONTEXT size, then we are done. @@ -264,7 +265,7 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, } // check the size of the incoming buffer - if (contextBufSize < GetProcess()->GetTargetContextSize()) + if (contextBufSize < ContextSizeForFlags(contextFlags)) { ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } @@ -292,8 +293,7 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, // Stamp the requested contextFlags on the destination so the copy // pulls exactly those chunks from the source. ContextBuffer destinationContext = { pbContextBuf, contextBufSize }; - ContextBuffer sourceContext = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; - IfFailThrow(pDAC->CopyContext(destinationContext, sourceContext, contextFlags)); + IfFailThrow(pDAC->CopyContext(destinationContext, GetContextBuffer(), contextFlags)); } } } @@ -341,7 +341,7 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte ThrowHR(E_INVALIDARG); } - if (contextSize < GetProcess()->GetTargetContextSize()) + if (!CheckContextSizeForBuffer(contextSize, context)) { ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } @@ -360,11 +360,10 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte memcpy(m_pContextBuffer, tmpCtx, cbCtx); m_cachedSetContextFlag = flag; - ContextBuffer currentContext = { m_pContextBuffer, cbCtx }; IfFailThrow(pDAC->SetStackWalkCurrentContext(m_pCordbThread->m_vmThreadToken, m_pSFIHandle, flag, - currentContext)); + GetContextBuffer())); } //--------------------------------------------------------------------------------------- @@ -391,8 +390,7 @@ BOOL CordbStackWalk::UnwindStackFrame() // Now that we have unwound, make sure we update the CONTEXT buffer to reflect the current stack frame. if (retVal) { - ContextBuffer contextBuffer = { m_pContextBuffer, pProcess->GetTargetContextSize() }; - IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, contextBuffer)); + IfFailThrow(pDAC->GetStackWalkCurrentContext(m_pSFIHandle, GetContextBuffer())); } return retVal; @@ -506,7 +504,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) // see the comment on Debugger_STRData in dbgipcevents.h for the protocol. NewArrayHolder frameCtx(new BYTE[GetProcess()->GetTargetContextSize()]); ZeroMemory(frameCtx, GetProcess()->GetTargetContextSize()); - frameData.ctx = frameCtx; + frameData.ctx = { frameCtx, GetProcess()->GetTargetContextSize() }; IDacDbiInterface::FrameType ft = IDacDbiInterface::kInvalid; diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index bfdc3a92361e5e..e2dbf43ebbac94 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -77,10 +77,6 @@ CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) : m_pAppDomain(NULL), m_debugState(THREAD_RUN), m_fFramesFresh(false), - m_fFloatStateValid(false), - m_floatStackTop(0), - m_firstFloatReg(-1), - m_floatValuesCount(0), m_fException(false), m_EnCRemapFunctionIP(0), m_userState(kInvalidUserState), @@ -103,7 +99,7 @@ CordbThread::CordbThread(CordbProcess * pProcess, VMPTR_Thread vmThread) : // Unique ID should never be 0. _ASSERTE(m_dwUniqueID != 0); - m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); + m_vmLeftSideContext = (CORDB_ADDRESS)NULL; m_vmExcepObjHandle = VMPTR_OBJECTHANDLE::NullPtr(); // Set AppDomain @@ -1301,7 +1297,7 @@ void CordbThread::CleanupStack() m_RefreshStackNeuterList.NeuterAndClear(GetProcess()); m_fContextFresh = false; // invalidate the cached active CONTEXT - m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); // set the LS pointer to the active CONTEXT to NULL + m_vmLeftSideContext = (CORDB_ADDRESS)NULL; // set the LS pointer to the active CONTEXT to NULL m_fFramesFresh = false; // invalidate the cached stack trace (frames & chains) m_userState = kInvalidUserState; // clear the cached user state @@ -1320,9 +1316,6 @@ void CordbThread::MarkStackFramesDirty() _ASSERTE(GetProcess()->ThreadHoldsProcessLock()); - // invalidate the cached floating point state - m_fFloatStateValid = false; - // This flag is only true between the window when we get an exception callback and // when we call continue. Since this function is only called when we continue, we // need to reset this flag here. Note that in the case of an outstanding funceval, @@ -1335,7 +1328,7 @@ void CordbThread::MarkStackFramesDirty() m_EnCRemapFunctionIP = 0; m_fContextFresh = false; // invalidate the cached active CONTEXT - m_vmLeftSideContext = VMPTR_CONTEXT::NullPtr(); // set the LS pointer to the active CONTEXT to NULL + m_vmLeftSideContext = (CORDB_ADDRESS)NULL; // set the LS pointer to the active CONTEXT to NULL m_fFramesFresh = false; // invalidate the cached stack trace (frames & chains) m_userState = kInvalidUserState; // clear the cached user state @@ -1424,42 +1417,6 @@ HRESULT CordbThread::FindFrame(ICorDebugFrame ** ppFrame, FramePointer fp) -// CordbThread::LoadFloatState -// -// Initializes the float state members of this instance of CordbThread by -// fetching the thread's CONTEXT and decoding its floating-point register area -// through IDacDbiInterface::ReadFloatRegistersFromContext. -// -// Note: Throws -void CordbThread::LoadFloatState() -{ - THROW_IF_NEUTERED(this); - INTERNAL_SYNC_API_ENTRY(GetProcess()); - - IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - ULONG32 cbContext = GetProcess()->GetTargetContextSize(); - NewArrayHolder contextBuf(new BYTE[cbContext]); - ContextBuffer contextBuffer = { contextBuf, cbContext }; - IfFailThrow(pDAC->GetContext(m_vmThreadToken, contextBuffer)); - - ULONG32 valuesCount = 0; - int firstFloatReg = -1; - ULONG32 floatStackTop = 0; - IfFailThrow(pDAC->ReadFloatRegistersFromContext( - contextBuffer, - CORDB_MAX_FLOAT_REGISTERS, - m_floatValues, - &valuesCount, - &firstFloatReg, - &floatStackTop)); - - m_floatValuesCount = valuesCount; - m_firstFloatReg = firstFloatReg; - m_floatStackTop = floatStackTop; - m_fFloatStateValid = true; -} // CordbThread::LoadFloatState - - const bool SetIP_fCanSetIPOnly = TRUE; const bool SetIP_fSetIP = FALSE; @@ -1574,7 +1531,7 @@ HRESULT CordbThread::GetManagedContext(ContextBuffer * pContextBuffer) IDacDbiInterface * pDAC = GetProcess()->GetDAC(); IfFailThrow(pDAC->GetManagedStoppedContext(m_vmThreadToken, &m_vmLeftSideContext)); - if (m_vmLeftSideContext.IsNull()) + if (m_vmLeftSideContext == (CORDB_ADDRESS)NULL) { // We don't have a context in managed code. ThrowHR(CORDBG_E_CONTEXT_UNVAILABLE); @@ -1586,7 +1543,7 @@ HRESULT CordbThread::GetManagedContext(ContextBuffer * pContextBuffer) // The thread we're examining IS handling an exception, So grab the CONTEXT of the exception, NOT the // currently executing thread's CONTEXT (which would be the context of the exception handler.) ContextBuffer managedContext = { m_pContext.GetValue(), GetProcess()->GetTargetContextSize() }; - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), managedContext); + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext, managedContext); IfFailThrow(hr); } @@ -1619,7 +1576,7 @@ HRESULT CordbThread::SetManagedContext(ContextBuffer contextBuffer) IDacDbiInterface * pDAC = GetProcess()->GetDAC(); IfFailThrow(pDAC->GetManagedStoppedContext(m_vmThreadToken, &m_vmLeftSideContext)); - if (m_vmLeftSideContext.IsNull()) + if (m_vmLeftSideContext == (CORDB_ADDRESS)NULL) { ThrowHR(CORDBG_E_CONTEXT_UNVAILABLE); } @@ -1632,13 +1589,13 @@ HRESULT CordbThread::SetManagedContext(ContextBuffer contextBuffer) // write too much information into the remote process. NewArrayHolder tempContext(new BYTE[contextSize]); ContextBuffer temporaryContext = { tempContext, contextSize }; - hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext.ToLsPtr(), temporaryContext); + hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext, temporaryContext); IfFailThrow(hr); // flags == 0: tempContext already carries the target's ContextFlags (read above). IfFailThrow(GetProcess()->GetDAC()->CopyContext(temporaryContext, contextBuffer, 0)); - hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext.ToLsPtr(), temporaryContext); + hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext, temporaryContext); IfFailThrow(hr); // @todo - who's updating the regdisplay to guarantee that's in sync w/ our new context? @@ -3265,7 +3222,8 @@ HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) IsContextSet(), IsGenericHijacked(), IsBlockingForSync(), IsRaiseExceptionHijacked())); LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: hijackCtx is:\n")); LogContext(GetHijackCtx()); - CORDbgCopyThreadContext(pContext, GetHijackCtx()); + CORDbgCopyThreadContext(reinterpret_cast(pContext), sizeof(T_CONTEXT), + reinterpret_cast(GetHijackCtx()), sizeof(T_CONTEXT)); } // use the LS for M2UHandoff else if (IsFirstChanceHijacked() && !IsBlockingForSync()) @@ -3277,10 +3235,11 @@ HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) T_CONTEXT tempContext = { 0 }; ContextBuffer contextBuffer = { reinterpret_cast(&tempContext), sizeof(tempContext) }; - hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext, contextBuffer); + hr = GetProcess()->SafeReadThreadContext(m_pLeftSideContext.UnsafeGetAddr(), contextBuffer); if (SUCCEEDED(hr)) - CORDbgCopyThreadContext(pContext, &tempContext); + CORDbgCopyThreadContext(reinterpret_cast(pContext), sizeof(T_CONTEXT), + reinterpret_cast(&tempContext), sizeof(tempContext)); } // no hijack in place so just call straight through else @@ -3332,7 +3291,8 @@ HRESULT CordbUnmanagedThread::SetThreadContext(T_CONTEXT* pContext) LOG((LF_CORDB, LL_INFO10000, "CUT::STC: setting context from RaiseException hijack.\n")); } SetState(CUTS_HasContextSet); - CORDbgCopyThreadContext(GetHijackCtx(), pContext); + CORDbgCopyThreadContext(reinterpret_cast(GetHijackCtx()), sizeof(T_CONTEXT), + reinterpret_cast(pContext), sizeof(T_CONTEXT)); } else { @@ -3488,7 +3448,8 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() #else GetHijackCtx()->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT; #endif - CORDbgCopyThreadContext(GetHijackCtx(), &context); + CORDbgCopyThreadContext(reinterpret_cast(GetHijackCtx()), sizeof(T_CONTEXT), + reinterpret_cast(&context), sizeof(context)); LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Hijacking for sync. Original context is:\n", this)); LogContext(GetHijackCtx()); @@ -4481,12 +4442,34 @@ HRESULT CordbFrame::ReadContextRegister(CorDebugRegister reg, TADDR * pValue) co return E_POINTER; IDacDbiInterface * pDAC = GetProcess()->GetDAC(); - ContextBuffer contextBuffer = { const_cast(GetContext()), GetProcess()->GetTargetContextSize() }; - return pDAC->ReadRegistersFromContext( - contextBuffer, + CORDB_REGISTER value = 0; + HRESULT hr = pDAC->ReadRegistersFromContext( + GetContext(), ®, 1, - pValue); + &value); + if (SUCCEEDED(hr)) + *pValue = (TADDR)value; + return hr; +} + +// Reads a floating-point / SIMD register's scalar value (as a double bit +// pattern) from this frame's CONTEXT buffer via the DAC. +HRESULT CordbFrame::ReadFloatContextRegister(CorDebugRegister reg, double * pValue) const +{ + if (pValue == NULL) + return E_POINTER; + + IDacDbiInterface * pDAC = GetProcess()->GetDAC(); + CORDB_REGISTER value = 0; + HRESULT hr = pDAC->ReadRegistersFromContext( + GetContext(), + ®, + 1, + &value); + if (SUCCEEDED(hr)) + memcpy(pValue, &value, sizeof(double)); + return hr; } //--------------------------------------------------------------------------------------- @@ -5148,9 +5131,9 @@ HRESULT CordbRuntimeUnwindableFrame::QueryInterface(REFIID id, void ** ppInterfa // Return a pointer to the CONTEXT. // -const BYTE * CordbRuntimeUnwindableFrame::GetContext() const +const ContextBuffer CordbRuntimeUnwindableFrame::GetContext() const { - return m_pContextBuffer; + return { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; } @@ -5315,9 +5298,9 @@ HRESULT CordbNativeFrame::GetCode(ICorDebugCode **ppCode) // Return a pointer to the CONTEXT. // -const BYTE * CordbNativeFrame::GetContext() const +const ContextBuffer CordbNativeFrame::GetContext() const { - return m_pContextBuffer; + return ContextBuffer{ m_pContextBuffer, GetProcess()->GetTargetContextSize() }; } //--------------------------------------------------------------------------------------- @@ -5570,8 +5553,7 @@ HRESULT CordbNativeFrame::GetRegisterSet(ICorDebugRegisterSet **ppRegisters) EX_TRY { // allocate a new CordbRegisterSet object - ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; - RSInitHolder pRegisterSet(new CordbRegisterSet(contextBuffer, + RSInitHolder pRegisterSet(new CordbRegisterSet(GetContext(), m_pThread, IsLeafFrame(), false)); @@ -6264,6 +6246,8 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, (et != ELEMENT_TYPE_R8)) return E_INVALIDARG; + CorDebugRegister regNum = (CorDebugRegister)index; + #if defined(TARGET_AMD64) if (!((index >= REGISTER_AMD64_XMM0) && (index <= REGISTER_AMD64_XMM15))) @@ -6293,61 +6277,35 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); - - // Make sure the thread's floating point stack state is loaded - // over from the left side. - // - CordbThread *pThread = m_pThread; - EX_TRY { - if (!pThread->m_fFloatStateValid) - { - pThread->LoadFloatState(); - } - } - EX_CATCH_HRESULT(hr); - if (SUCCEEDED(hr)) - { -#if !defined(TARGET_64BIT) - // This is needed on x86 because we are dealing with a stack. - index = pThread->m_floatStackTop - index; -#endif - - if (index >= (sizeof(pThread->m_floatValues) / - sizeof(pThread->m_floatValues[0]))) - return E_INVALIDARG; + // Read the register's scalar value from this frame's context. The DAC + // performs the arch-specific float / SIMD and x87 stack decoding. + double floatValue = 0.0; + IfFailThrow(ReadFloatContextRegister(regNum, &floatValue)); #ifdef TARGET_X86 // A workaround (sort of) to get around the difference in format between // a float value and a double value. We can't simply cast a double pointer to // a float pointer. Instead, we have to cast the double itself to a float. if (pType->m_elementType == ELEMENT_TYPE_R4) - *(float *)&(pThread->m_floatValues[index]) = (float)pThread->m_floatValues[index]; + *(float *)&floatValue = (float)floatValue; #endif - ICorDebugValue* pValue; - - EX_TRY - { - // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to - // the new instance of CordbValue. - EnregisteredValueHomeHolder pRemoteReg(new FloatRegValueHome(this, index)); - EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr(); - - CordbValue::CreateValueByType(GetCurrentAppDomain(), - pType, - false, - EMPTY_BUFFER, - MemoryRange(&(pThread->m_floatValues[index]), sizeof(double)), - pRegHolder, - &pValue); // throws - - *ppValue = pValue; - } - EX_CATCH_HRESULT(hr); + // Provide the register info as we create the value. CreateValueByType will transfer ownership of this to + // the new instance of CordbValue. + EnregisteredValueHomeHolder pRemoteReg(new FloatRegValueHome(this, index, regNum)); + EnregisteredValueHomeHolder * pRegHolder = pRemoteReg.GetAddr(); + CordbValue::CreateValueByType(GetCurrentAppDomain(), + pType, + false, + EMPTY_BUFFER, + MemoryRange(&floatValue, sizeof(double)), + pRegHolder, + ppValue); // throws } + EX_CATCH_HRESULT(hr); return hr; } @@ -6359,11 +6317,9 @@ HRESULT CordbNativeFrame::GetLocalFloatingPointValue(DWORD index, // contiguous local snapshot, then the value is built from that snapshot. // // Arguments: -// lowReg - the register holding the low 8 bytes. When lowIsFloat is true -// this is a 0-based fp register index, otherwise a CorDebugRegister. +// lowReg - the CorDebugRegister holding the low 8 bytes. // lowIsFloat - whether the low half is in a floating-point register. -// highReg - the register holding the high 8 bytes. When highIsFloat is true -// this is a 0-based fp register index, otherwise a CorDebugRegister. +// highReg - the CorDebugRegister holding the high 8 bytes. // highIsFloat - whether the high half is in a floating-point register. // pType - the type of the value. // ppValue - [out] the newly created value. @@ -6389,26 +6345,12 @@ HRESULT CordbNativeFrame::GetLocalTwoRegisterValue(DWORD lowReg, EX_TRY { - CordbThread * pThread = m_pThread; - - // Ensure the floating-point state is loaded if either half lives in an fp register. - if (lowIsFloat || highIsFloat) - { - if (!pThread->m_fFloatStateValid) - { - pThread->LoadFloatState(); - } - } - - const DWORD numFloatValues = - (DWORD)(sizeof(pThread->m_floatValues) / sizeof(pThread->m_floatValues[0])); - // Gather the low 8 bytes. if (lowIsFloat) { - if (lowReg >= numFloatValues) - ThrowHR(E_INVALIDARG); - memcpy(valueBuffer, &pThread->m_floatValues[lowReg], sizeof(double)); + double floatValue = 0.0; + IfFailThrow(ReadFloatContextRegister((CorDebugRegister)lowReg, &floatValue)); + memcpy(valueBuffer, &floatValue, sizeof(double)); } else { @@ -6420,9 +6362,9 @@ HRESULT CordbNativeFrame::GetLocalTwoRegisterValue(DWORD lowReg, // Gather the high 8 bytes. if (highIsFloat) { - if (highReg >= numFloatValues) - ThrowHR(E_INVALIDARG); - memcpy(valueBuffer + sizeof(double), &pThread->m_floatValues[highReg], sizeof(double)); + double floatValue = 0.0; + IfFailThrow(ReadFloatContextRegister((CorDebugRegister)highReg, &floatValue)); + memcpy(valueBuffer + sizeof(double), &floatValue, sizeof(double)); } else { @@ -6501,12 +6443,9 @@ bool CordbNativeFrame::IsLeafFrame() const { // check if the leaf frame in the leaf chain is "this" BOOL fSameControlRegisters = FALSE; - ULONG32 cbContext = GetProcess()->GetTargetContextSize(); - ContextBuffer thisContext = { const_cast(GetContext()), cbContext }; - ContextBuffer nativeFrameContext = { const_cast(pNFrame->GetContext()), cbContext }; IfFailThrow(GetProcess()->GetDAC()->CompareControlRegisters( - thisContext, - nativeFrameContext, + GetContext(), + pNFrame->GetContext(), &fSameControlRegisters)); if (fSameControlRegisters) { @@ -6525,10 +6464,9 @@ bool CordbNativeFrame::IsLeafFrame() const { IDacDbiInterface * pDAC = GetProcess()->GetDAC(); BOOL isLeaf; - ContextBuffer contextBuffer = { m_pContextBuffer, GetProcess()->GetTargetContextSize() }; IfFailThrow(pDAC->IsLeafFrame( m_pThread->m_vmThreadToken, - contextBuffer, + GetContext(), &isLeaf)); m_optfIsLeafFrame = (isLeaf == TRUE); } @@ -7732,10 +7670,10 @@ HRESULT CordbJITILFrame::GetNativeVariable(CordbType *type, // represent mixed int/fp pairs. Other targets still require // dedicated encodings for FP-containing multi-register values. hr = m_nativeFrame->GetLocalTwoRegisterValue( - lowIsFloat ? lowReg - ICorDebugInfo::REGNUM_FP_FIRST + lowIsFloat ? (CorDebugRegister)(REGISTER_AMD64_XMM0 + (lowReg - ICorDebugInfo::REGNUM_FP_FIRST)) : ConvertRegNumToCorDebugRegister(lowReg), lowIsFloat, - highIsFloat ? highReg - ICorDebugInfo::REGNUM_FP_FIRST + highIsFloat ? (CorDebugRegister)(REGISTER_AMD64_XMM0 + (highReg - ICorDebugInfo::REGNUM_FP_FIRST)) : ConvertRegNumToCorDebugRegister(highReg), highIsFloat, type, diff --git a/src/coreclr/debug/di/shimlocaldatatarget.cpp b/src/coreclr/debug/di/shimlocaldatatarget.cpp index 136ff3d8a20dfb..18b8372cf44b26 100644 --- a/src/coreclr/debug/di/shimlocaldatatarget.cpp +++ b/src/coreclr/debug/di/shimlocaldatatarget.cpp @@ -380,7 +380,7 @@ ShimLocalDataTarget::GetThreadContext( HRESULT hr = E_FAIL; - if (!CheckContextSizeForBuffer(contextSize, pContext)) + if (!CheckContextSizeForBuffer(contextSize, pContext) || contextSize < sizeof(T_CONTEXT)) { return E_INVALIDARG; } diff --git a/src/coreclr/debug/di/shimpriv.h b/src/coreclr/debug/di/shimpriv.h index 293caca13f283b..04e29e98d62df1 100644 --- a/src/coreclr/debug/di/shimpriv.h +++ b/src/coreclr/debug/di/shimpriv.h @@ -700,8 +700,8 @@ class ShimStackWalk void CancelUMChain() { m_reason = CHAIN_NONE; } BOOL IsTrackingUMChain() { return (m_reason == CHAIN_ENTER_UNMANAGED); } - BYTE * GetLeafNativeContext() { return m_leafNativeContext; } - BYTE * GetLeafManagedContext() { return m_leafManagedContext; } + ContextBuffer GetLeafNativeContext() { return { m_leafNativeContext, m_contextSize }; } + ContextBuffer GetLeafManagedContext() { return { m_leafManagedContext, m_contextSize }; } // Leaf CONTEXT buffers, sized at construction to the target's CONTEXT size. NewArrayHolder m_leafNativeContext; diff --git a/src/coreclr/debug/di/shimstackwalk.cpp b/src/coreclr/debug/di/shimstackwalk.cpp index 8d2e6bdcf0241e..ab4cdcf9cfcaa0 100644 --- a/src/coreclr/debug/di/shimstackwalk.cpp +++ b/src/coreclr/debug/di/shimstackwalk.cpp @@ -28,14 +28,14 @@ namespace ContextBuffer contextBuffer, CorDebugRegister reg) { - TADDR value = 0; + CORDB_REGISTER value = 0; IDacDbiInterface * pDAC = pThread->GetProcess()->GetDAC(); IfFailThrow(pDAC->ReadRegistersFromContext( contextBuffer, ®, 1, &value)); - return value; + return (TADDR)value; } } @@ -378,8 +378,7 @@ void ShimStackWalk::Populate() { // If we have hit any managed stack frame, then we may need to send // an enter-managed chain later. Save the CONTEXT now. - ContextBuffer contextBuffer = { chainInfo.GetLeafManagedContext(), chainInfo.m_contextSize }; - SaveChainContext(pSW, &chainInfo, contextBuffer); + SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafManagedContext()); chainInfo.m_fNeedEnterManagedChain = true; } @@ -434,8 +433,7 @@ void ShimStackWalk::Populate() // we have exhausted all the stack frames. // We need to save the CONTEXT to start tracking an unmanaged chain. - ContextBuffer contextBuffer = { chainInfo.GetLeafNativeContext(), chainInfo.m_contextSize }; - SaveChainContext(pSW, &chainInfo, contextBuffer); + SaveChainContext(pSW, &chainInfo, chainInfo.GetLeafNativeContext()); chainInfo.m_fLeafNativeContextIsValid = true; // begin tracking UM chain if we're supposed to @@ -1130,7 +1128,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa fManagedChain = TRUE; } - const BYTE * pChainContext = NULL; + ContextBuffer pChainContext = { NULL, 0 }; if (fManagedChain) { // The chain to be added is managed itself. So we don't need to send an enter-managed chain. @@ -1145,7 +1143,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa // We need to send an extra enter-managed chain. _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); CordbThread * pThread = static_cast(m_pThread.GetValue()); - ContextBuffer nativeContext = { pChainInfo->GetLeafNativeContext(), GetContextSize() }; + ContextBuffer nativeContext = pChainInfo->GetLeafNativeContext(); BYTE * sp = reinterpret_cast( ReadCtxReg(pThread, nativeContext, REGISTER_STACK_POINTER)); #if !defined(TARGET_ARM) && !defined(TARGET_ARM64) @@ -1156,7 +1154,7 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa #endif FramePointer fp = FramePointer::MakeFramePointer(sp); - ContextBuffer managedContext = { pChainInfo->GetLeafManagedContext(), pChainInfo->m_contextSize }; + ContextBuffer managedContext = pChainInfo->GetLeafManagedContext(); AppendChainWorker(pStackWalkInfo, managedContext, fp, @@ -1170,9 +1168,8 @@ void ShimStackWalk::AppendChain(ChainInfo * pChainInfo, StackWalkInfo * pStackWa } // Add the actual chain. - ContextBuffer chainContext = { const_cast(pChainContext), pChainInfo->m_contextSize }; AppendChainWorker(pStackWalkInfo, - chainContext, + pChainContext, pChainInfo->m_rootFP, pChainInfo->m_reason, fManagedChain); @@ -1467,7 +1464,7 @@ void ShimStackWalk::TrackUMChain(ChainInfo * pChainInfo, StackWalkInfo * pStackW { // check whether we get any stack range _ASSERTE(pChainInfo->m_fLeafNativeContextIsValid); - ContextBuffer contextBuffer = { pChainInfo->GetLeafNativeContext(), pChainInfo->m_contextSize }; + ContextBuffer contextBuffer = pChainInfo->GetLeafNativeContext(); FramePointer fpLeaf = GetFramePointerForChain(contextBuffer); // Don't bother creating an unmanaged chain if the stack range is empty. diff --git a/src/coreclr/debug/di/valuehome.cpp b/src/coreclr/debug/di/valuehome.cpp index 4bc6d73214763e..5814ca5fbdd757 100644 --- a/src/coreclr/debug/di/valuehome.cpp +++ b/src/coreclr/debug/di/valuehome.cpp @@ -374,9 +374,17 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue, { _ASSERTE((newValue.Size() == 4) || (newValue.Size() == 8)); - // update the thread's floating point stack - void * valueAddress = (void *) &(m_pFrame->m_pThread->m_floatValues[m_floatIndex]); - memcpy(valueAddress, newValue.StartAddress(), newValue.Size()); + IDacDbiInterface * pDAC = m_pFrame->GetProcess()->GetDAC(); + HRESULT hr = pDAC->WriteFloatRegisterToContext( + contextBuffer, + m_regNum, + (const BYTE *)newValue.StartAddress(), + (ULONG32)newValue.Size()); + if (FAILED(hr)) + { + _ASSERTE(!"Failed to write floating point register to context"); + ThrowHR(E_FAIL); + } } // FloatValueHome::SetEnregisteredValue // FloatRegValueHome::GetEnregisteredValue diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 0b029db59f5b5d..6047b4865c8eb1 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -9253,8 +9253,8 @@ TP_RESULT DebuggerFuncEvalComplete::TriggerPatch(DebuggerControllerPatch *patch, #error Not supported #endif #endif - CORDbgCopyThreadContext(reinterpret_cast(pCtx), - reinterpret_cast(&(m_pDE->m_context))); + CORDbgCopyThreadContext(reinterpret_cast(pCtx), sizeof(T_CONTEXT), + reinterpret_cast(&(m_pDE->m_context)), sizeof(T_CONTEXT)); // We've hit our patch, so simply disable all (which removes the // patch) and trigger the event. diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index ab2461a9487c56..2e4b26346525eb 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -13449,7 +13449,7 @@ LONG Debugger::FirstChanceSuspendHijackWorker(CONTEXT *pContext, Thread *pEEThread = debuggerBreakInThread ? NULL : g_pEEInterface->GetThread(); // Hook up the memory so RS can get to it - fcd.pLeftSideContext.Set((DT_CONTEXT*)pContext); + fcd.pLeftSideContext.Set((T_CONTEXT*)pContext); fcd.action = HIJACK_ACTION_EXIT_UNHANDLED; fcd.debugCounter = 0; diff --git a/src/coreclr/debug/inc/common.h b/src/coreclr/debug/inc/common.h index b17bf7915533b2..4a33f749502f3b 100644 --- a/src/coreclr/debug/inc/common.h +++ b/src/coreclr/debug/inc/common.h @@ -58,8 +58,13 @@ void InitEventForDebuggerNotification(DEBUG_EVENT * pDebugEvent, // CORDbgCopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // +// The source and destination are opaque byte buffers with an associated size. +// They only need to be at least sizeof(DT_CONTEXT) bytes and may be larger +// (for example a full T_CONTEXT that carries trailing XSTATE/SVE state which is +// not part of DT_CONTEXT); only the DT_CONTEXT portion is ever read or written. +// -extern void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc); +extern void CORDbgCopyThreadContext(BYTE* pDst, ULONG32 cbDst, const BYTE* pSrc, ULONG32 cbSrc); //--------------------------------------------------------------------------------------- // diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 6ff0d9aee57abc..2a128737ef2b13 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -1051,7 +1051,7 @@ IDacDbiInterface : public IUnknown // we don't have a filter CONTEXT on the LS anymore. // - virtual HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT VMPTR_CONTEXT * pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE GetManagedStoppedContext(VMPTR_Thread vmThread, OUT CORDB_ADDRESS * pRetVal) = 0; typedef enum { @@ -2207,13 +2207,7 @@ IDacDbiInterface : public IUnknown VMPTR_MethodDesc vmMethod, OUT UINT32* pTokenIndex) = 0; - typedef enum - { - kContextSizeBase = 0, - kContextSizeExtendedRegisters, - } ContextSizeFlags; - - virtual HRESULT STDMETHODCALLTYPE GetTargetContextSize(ContextSizeFlags flags, OUT ULONG32 * pSize) = 0; + virtual HRESULT STDMETHODCALLTYPE GetTargetContextSize(ULONG32 contextFlags, OUT ULONG32 * pSize) = 0; virtual HRESULT STDMETHODCALLTYPE WriteRegistersToContext( IN ContextBuffer contextBuffer, @@ -2225,7 +2219,7 @@ IDacDbiInterface : public IUnknown IN ContextBuffer contextBuffer, IN const CorDebugRegister * regs, IN ULONG32 nRegs, - OUT TADDR * pValues) = 0; + OUT CORDB_REGISTER * pValues) = 0; virtual HRESULT STDMETHODCALLTYPE GetAvailableRegistersMask( IN BOOL fActive, @@ -2237,40 +2231,11 @@ IDacDbiInterface : public IUnknown IN ULONG32 jitRegNum, OUT CorDebugRegister * pReg) = 0; - virtual HRESULT STDMETHODCALLTYPE ReadFloatRegistersFromContext( + virtual HRESULT STDMETHODCALLTYPE WriteFloatRegisterToContext( IN ContextBuffer contextBuffer, - IN ULONG32 regCount, - OUT DOUBLE values[CORDB_MAX_FLOAT_REGISTERS], - OUT ULONG32 * pValuesCount, - OUT int * pFirstFloatReg, - OUT ULONG32 * pFloatStackTop) = 0; - - typedef enum - { - kArchUnknown = 0, - kArchX86, - kArchAMD64, - kArchArm, - kArchArm64, - kArchLoongArch64, - kArchRiscV64, - kArchWasm, - } TargetArchitecture; - - typedef enum - { - kOSUnknown = 0, - kOSWindows, - kOSUnix, - } TargetOperatingSystem; - - struct TargetInfo - { - TargetArchitecture arch; - TargetOperatingSystem os; - }; - - virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; + IN CorDebugRegister reg, + IN const BYTE * pValue, + IN ULONG32 valueSize) = 0; virtual HRESULT STDMETHODCALLTYPE ContextHasExtendedRegisters( IN ContextBuffer contextBuffer, diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index ed0e31bf8988de..6966a6719c6d3d 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -546,10 +546,10 @@ struct MSLAYOUT Debugger_JITFuncData #endif // ARM context structures have a 16-byte alignment requirement struct MSLAYOUT Debugger_STRData { - // fp is fixed-width across target architectures. ctx points to a DBI-owned - // buffer containing the target's opaque CONTEXT byte image. + // fp is fixed-width across target architectures. ctx wraps a DBI-owned buffer + // (pointer plus size) holding the target's opaque CONTEXT byte image. CORDB_ADDRESS fp; - BYTE * ctx; + ContextBuffer ctx; VMPTR_AppDomain vmCurrentAppDomainToken; diff --git a/src/coreclr/debug/inc/dbgipcevents.h b/src/coreclr/debug/inc/dbgipcevents.h index 4a902beb6a76d9..bd3e5e0f82e934 100644 --- a/src/coreclr/debug/inc/dbgipcevents.h +++ b/src/coreclr/debug/inc/dbgipcevents.h @@ -424,6 +424,11 @@ class MSLAYOUT LsPointer : public GeneralLsPointer return CORDB_ADDRESS_TO_PTR((CORDB_ADDRESS)m_ptr); } + CORDB_ADDRESS UnsafeGetAddr() + { + return (CORDB_ADDRESS)m_ptr; + } + static LsPointer NullPtr() { return MakePtr(NULL); @@ -592,7 +597,7 @@ DEFINE_LSPTR_TYPE(class DebuggerEval, LSPTR_DEBUGGEREVAL); DEFINE_LSPTR_TYPE(class DebuggerStepper, LSPTR_STEPPER); // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct. -typedef LsPointer LSPTR_CONTEXT; +typedef LsPointer LSPTR_CONTEXT; DEFINE_LSPTR_TYPE(struct OBJECTHANDLE__, LSPTR_OBJECTHANDLE); DEFINE_LSPTR_TYPE(class TypeHandleDummyPtr, LSPTR_TYPEHANDLE); // TypeHandle in the LS is not a direct pointer. @@ -762,11 +767,6 @@ DEFINE_VMPTR(class AppDomain, PTR_AppDomain, VMPTR_AppDomain); // Need to be careful not to annoy the compiler here since DT_CONTEXT is a typedef, not a struct. // DEFINE_VMPTR(struct _CONTEXT, PTR_CONTEXT, VMPTR_CONTEXT); -#if defined(ALLOW_VMPTR_ACCESS) -typedef VMPTR_Base VMPTR_CONTEXT; -#else -typedef VMPTR_Base VMPTR_CONTEXT; -#endif DEFINE_VMPTR(class Module, PTR_Module, VMPTR_Module); @@ -958,8 +958,6 @@ struct MSLAYOUT IPCENames // We use a class/struct so that the function can rema #endif // !DACCESS_COMPILE -#define CORDB_MAX_FLOAT_REGISTERS 32 - class MSLAYOUT FramePointer { diff --git a/src/coreclr/debug/shared/amd64/primitives.cpp b/src/coreclr/debug/shared/amd64/primitives.cpp index 5f9e757dfc7705..4069f9a38ee911 100644 --- a/src/coreclr/debug/shared/amd64/primitives.cpp +++ b/src/coreclr/debug/shared/amd64/primitives.cpp @@ -16,8 +16,14 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + _ASSERTE(cbDst >= sizeof(DT_CONTEXT)); + _ASSERTE(cbSrc >= sizeof(DT_CONTEXT)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + ULONG dstFlags = pDst->ContextFlags; ULONG srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, diff --git a/src/coreclr/debug/shared/arm/primitives.cpp b/src/coreclr/debug/shared/arm/primitives.cpp index 58015ef2fb9e7a..bae8f734d46098 100644 --- a/src/coreclr/debug/shared/arm/primitives.cpp +++ b/src/coreclr/debug/shared/arm/primitives.cpp @@ -16,8 +16,14 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + _ASSERTE(cbDst >= sizeof(DT_CONTEXT)); + _ASSERTE(cbSrc >= sizeof(DT_CONTEXT)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, diff --git a/src/coreclr/debug/shared/arm64/primitives.cpp b/src/coreclr/debug/shared/arm64/primitives.cpp index 7216bab9301413..b3441fa912db05 100644 --- a/src/coreclr/debug/shared/arm64/primitives.cpp +++ b/src/coreclr/debug/shared/arm64/primitives.cpp @@ -16,8 +16,14 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + _ASSERTE(cbDst >= sizeof(DT_CONTEXT)); + _ASSERTE(cbSrc >= sizeof(DT_CONTEXT)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, diff --git a/src/coreclr/debug/shared/i386/primitives.cpp b/src/coreclr/debug/shared/i386/primitives.cpp index fb17af347d672d..a91503b13b8673 100644 --- a/src/coreclr/debug/shared/i386/primitives.cpp +++ b/src/coreclr/debug/shared/i386/primitives.cpp @@ -16,10 +16,27 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + // The buffers must at least be large enough to hold the ContextFlags field, which + // selects how much of the rest of the CONTEXT the copy below reads/writes. + _ASSERTE(cbDst >= offsetof(DT_CONTEXT, ContextFlags) + sizeof(DWORD)); + _ASSERTE(cbSrc >= offsetof(DT_CONTEXT, ContextFlags) + sizeof(DWORD)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; + + // The copy only touches the trailing ExtendedRegisters region when + // CONTEXT_EXTENDED_REGISTERS is set, so a smaller CONTEXT buffer that omits that + // array (e.g. CONTEXT_FULL without extended registers) is valid. + _ASSERTE(cbDst >= (((dstFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) + ? sizeof(DT_CONTEXT) : offsetof(DT_CONTEXT, ExtendedRegisters))); + _ASSERTE(cbSrc >= (((srcFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) + ? sizeof(DT_CONTEXT) : offsetof(DT_CONTEXT, ExtendedRegisters))); + LOG((LF_CORDB, LL_INFO1000000, "CP::CTC: pDst=0x%08x dstFlags=0x%x, pSrc=0x%08x srcFlags=0x%x\n", pDst, dstFlags, pSrc, srcFlags)); diff --git a/src/coreclr/debug/shared/loongarch64/primitives.cpp b/src/coreclr/debug/shared/loongarch64/primitives.cpp index 25d0db5dfad483..df79d064249775 100644 --- a/src/coreclr/debug/shared/loongarch64/primitives.cpp +++ b/src/coreclr/debug/shared/loongarch64/primitives.cpp @@ -17,8 +17,14 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + _ASSERTE(cbDst >= sizeof(DT_CONTEXT)); + _ASSERTE(cbSrc >= sizeof(DT_CONTEXT)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, diff --git a/src/coreclr/debug/shared/riscv64/primitives.cpp b/src/coreclr/debug/shared/riscv64/primitives.cpp index f0e809e107fcb9..bd1ffa7286fdfb 100644 --- a/src/coreclr/debug/shared/riscv64/primitives.cpp +++ b/src/coreclr/debug/shared/riscv64/primitives.cpp @@ -15,8 +15,14 @@ // CopyThreadContext() does an intelligent copy from pSrc to pDst, // respecting the ContextFlags of both contexts. // -void CORDbgCopyThreadContext(T_CONTEXT* pDst, const T_CONTEXT* pSrc) +void CORDbgCopyThreadContext(BYTE* pDstBuffer, ULONG32 cbDst, const BYTE* pSrcBuffer, ULONG32 cbSrc) { + _ASSERTE(cbDst >= sizeof(DT_CONTEXT)); + _ASSERTE(cbSrc >= sizeof(DT_CONTEXT)); + + DT_CONTEXT* pDst = reinterpret_cast(pDstBuffer); + const DT_CONTEXT* pSrc = reinterpret_cast(pSrcBuffer); + DWORD dstFlags = pDst->ContextFlags; DWORD srcFlags = pSrc->ContextFlags; LOG((LF_CORDB, LL_INFO1000000, diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index 93b495da8a8397..c5f479fcb126c0 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -50,7 +50,6 @@ typedef ULONG64 VMPTR_Assembly; typedef ULONG64 VMPTR_Module; typedef ULONG64 VMPTR_Thread; typedef ULONG64 VMPTR_MethodDesc; -typedef ULONG64 VMPTR_CONTEXT; typedef ULONG64 VMPTR_TypeHandle; typedef ULONG64 VMPTR_FieldDesc; typedef ULONG64 VMPTR_Object; @@ -64,6 +63,7 @@ typedef ULONG64 VMPTR_NativeCodeVersionNode; // Address and token types typedef ULONG64 CORDB_ADDRESS; +typedef ULONG64 CORDB_REGISTER; typedef ULONG64 GENERICS_TYPE_TOKEN; typedef ULONG64 PCODE; typedef ULONG64 TADDR; @@ -277,7 +277,7 @@ interface IDacDbiInterface : IUnknown [in] CALLBACK_DATA pUserData); // Context and Stack Walking - HRESULT GetManagedStoppedContext([in] VMPTR_Thread vmThread, [out] VMPTR_CONTEXT * pRetVal); + HRESULT GetManagedStoppedContext([in] VMPTR_Thread vmThread, [out] CORDB_ADDRESS * pRetVal); HRESULT CreateStackWalk([in] VMPTR_Thread vmThread, [in] ContextBuffer contextBuffer, [out] StackWalkHandle * ppSFIHandle); HRESULT DeleteStackWalk([in] StackWalkHandle ppSFIHandle); HRESULT GetStackWalkCurrentContext([in] StackWalkHandle pSFIHandle, [in] ContextBuffer contextBuffer); @@ -451,7 +451,7 @@ interface IDacDbiInterface : IUnknown // CONTEXT register accessors. HRESULT WriteRegistersToContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [in] const TADDR * values); - HRESULT ReadRegistersFromContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [out] TADDR * pValues); + HRESULT ReadRegistersFromContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [out] CORDB_REGISTER * pValues); // Returns the full availability bitmask for the target architecture in // CorDebugRegister bit positions, including both integer (GPR) and @@ -465,22 +465,15 @@ interface IDacDbiInterface : IUnknown // Translates a JIT ICorDebugInfo::RegNum to a CorDebugRegister value HRESULT ConvertJitRegNumToCorDebugRegister([in] ULONG32 jitRegNum, [out] int * pReg); - // Decodes the floating-point / SIMD register area of a DBI-side context buffer - // Out params: - // values[] - populated doubles - // pValuesCount - number of valid slots in values[] - // pFirstFloatReg - CorDebugRegister value of values[0] (logical - // numbering); -1 if the target arch exposes no floats - // via CordbRegisterSet (e.g. ARM today) - // pFloatStackTop - x87 top-of-stack depth on x86 (so DBI can preserve - // its stack-relative dispatch); 0 on every other arch - HRESULT ReadFloatRegistersFromContext( + // Writes a single floating-point / SIMD register into a DBI-side context + // buffer. SIMD register files receive a raw byte copy into the low bytes of + // the slot; x87 slots are numerically re-encoded into 80-bit double-extended + // form. valueSize is the natural width of the value (4 for R4, 8 for R8). + HRESULT WriteFloatRegisterToContext( [in] ContextBuffer contextBuffer, - [in] ULONG32 regCount, - [out] DOUBLE values[32], - [out] ULONG32 * pValuesCount, - [out] int * pFirstFloatReg, - [out] ULONG32 * pFloatStackTop); + [in] int reg, + [in] const BYTE * pValue, + [in] ULONG32 valueSize); // Returns the target's processor architecture and OS family. HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs index 1ed47ffac687fb..ba95a0513fe690 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/AMD64Context.cs @@ -196,6 +196,16 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // XMM0-XMM15 occupy the FltSave area with a 16-byte (128-bit) stride. + private const int XmmRegisterCount = 16; + private const int XmmRegisterStride = 16; + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + => SimdRegisterAccess.TryReadRegister(context, (int)Marshal.OffsetOf(nameof(Xmm)), XmmRegisterStride, XmmRegisterCount, index, out value); + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + => SimdRegisterAccess.TryWriteRegister(context, (int)Marshal.OffsetOf(nameof(Xmm)), XmmRegisterStride, XmmRegisterCount, index, value); + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs index df4effd35cdf73..0a262f65e1053a 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARM64Context.cs @@ -238,6 +238,16 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // V0-V31 are the 128-bit NEON registers, a 16-byte stride within the context. + private const int VRegisterCount = 32; + private const int VRegisterStride = 16; + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + => SimdRegisterAccess.TryReadRegister(context, (int)Marshal.OffsetOf(nameof(V)), VRegisterStride, VRegisterCount, index, out value); + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + => SimdRegisterAccess.TryWriteRegister(context, (int)Marshal.OffsetOf(nameof(V)), VRegisterStride, VRegisterCount, index, value); + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs index 6fbe44d2981b53..c29730b28b0f05 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ARMContext.cs @@ -162,6 +162,16 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // D0-D31 are the 64-bit views of the VFP/NEON register file, an 8-byte stride. + private const int DRegisterCount = 32; + private const int DRegisterStride = 8; + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + => SimdRegisterAccess.TryReadRegister(context, (int)Marshal.OffsetOf(nameof(D)), DRegisterStride, DRegisterCount, index, out value); + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + => SimdRegisterAccess.TryWriteRegister(context, (int)Marshal.OffsetOf(nameof(D)), DRegisterStride, DRegisterCount, index, value); + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs index 133f4e545385ef..85575024a662e7 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/ContextHolder.cs @@ -60,6 +60,8 @@ public unsafe byte[] GetBytes() public bool TryReadRegister(string fieldName, out TargetNUInt value) => Context.TryReadRegister(fieldName, out value); public bool TrySetRegister(int number, TargetNUInt value) => Context.TrySetRegister(number, value); public bool TryReadRegister(int number, out TargetNUInt value) => Context.TryReadRegister(number, out value); + public bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) => Context.TryReadFloatingPointRegister(context, index, out value); + public bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) => Context.TryWriteFloatingPointRegister(context, index, value); public (uint Flag, string Name)[] GetScalarRegisters() => Context.GetScalarRegisters(); public (uint Flag, int Start, int End)[] GetWideSpans() => Context.GetWideSpans(); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/FloatConversion.cs similarity index 60% rename from src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs rename to src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/FloatConversion.cs index 28f3ff036d38a1..a6320bb44fb258 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/Helpers/FloatConversion.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/FloatConversion.cs @@ -4,7 +4,7 @@ using System; using System.Buffers.Binary; -namespace Microsoft.Diagnostics.DataContractReader.Legacy; +namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; internal static class FloatConversion { @@ -88,4 +88,62 @@ public static double X87ExtendedToDouble(ReadOnlySpan slot10) res++; return BitConverter.Int64BitsToDouble(unchecked((long)(sign | res))); } + + // Encode an IEEE-754 binary64 value into an x87 80-bit double-extended slot + // (the inverse of X87ExtendedToDouble). Every finite binary64 is represented + // exactly, since the 64-bit extended significand and 15-bit exponent strictly + // contain binary64's 52-bit fraction and 11-bit exponent. Layout: bytes 0-7 = + // 64-bit significand with an explicit integer bit at 63; bytes 8-9 = 15-bit + // biased exponent (bias 16383) in bits 0-14 and the sign in bit 15. + public static void X87DoubleToExtended(double value, Span slot10) + { + ulong bits = (ulong)BitConverter.DoubleToInt64Bits(value); + ulong sign = (bits >> 63) & 1; + uint exp = (uint)((bits >> 52) & 0x7FF); + ulong frac = bits & ((1UL << 52) - 1); + + ulong mant; // 64-bit significand with explicit integer bit at 63 + ushort signExp; // sign (bit 15) + 15-bit biased exponent + + if (exp == 0x7FF) + { + // Infinity or NaN: max exponent, integer bit set. Preserve the NaN + // payload (shifted into the extended fraction) and force it quiet. + mant = (1UL << 63) | (frac << 11); + if (frac != 0) + mant |= 1UL << 62; // quiet bit + signExp = (ushort)((sign << 15) | 0x7FFF); + } + else if (exp == 0 && frac == 0) + { + // Signed zero. + mant = 0; + signExp = (ushort)(sign << 15); + } + else if (exp == 0) + { + // Binary64 subnormal: normalize into the wider extended exponent range. + // value = frac * 2^(-1074); shift the leading fraction bit up to bit 63. + int leadingZeros = 0; + ulong m = frac; + while ((m & (1UL << 51)) == 0) + { + m <<= 1; + leadingZeros++; + } + mant = m << 12; // integer bit lands at 63 + int e = -1023 - leadingZeros + 16383; // rebias to extended + signExp = (ushort)((sign << 15) | (uint)(e & 0x7FFF)); + } + else + { + // Normal: prepend the implicit integer bit, align to bit 63, rebias. + mant = ((1UL << 52) | frac) << 11; + int e = (int)exp - 1023 + 16383; + signExp = (ushort)((sign << 15) | (uint)(e & 0x7FFF)); + } + + BinaryPrimitives.WriteUInt64LittleEndian(slot10, mant); + BinaryPrimitives.WriteUInt16LittleEndian(slot10.Slice(8), signExp); + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs index 778c6ddf7dfc67..0c364c8f47ae02 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformAgnosticContext.cs @@ -31,6 +31,8 @@ public interface IPlatformAgnosticContext public abstract bool TryReadRegister(string fieldName, out TargetNUInt value); public abstract bool TrySetRegister(int number, TargetNUInt value); public abstract bool TryReadRegister(int number, out TargetNUInt value); + public abstract bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value); + public abstract bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value); // The register copy set derived from the context's [Register]-tagged fields, used to // implement CONTEXT-flag-gated copies. Integer/control/segment registers are named and diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs index 22e487c288ba6f..c345182832b7fb 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/IPlatformContext.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; + namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; public interface IPlatformContext @@ -37,6 +39,9 @@ public interface IPlatformContext bool TrySetRegister(int number, TargetNUInt value); bool TryReadRegister(int number, out TargetNUInt value); + bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value); + bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value); + (uint Flag, string Name)[] GetScalarRegisters(); (uint Flag, int Start, int End)[] GetWideSpans(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs index 91d3cae1d28d2d..d4cd0bdade34e8 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs @@ -231,6 +231,16 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // F0-F31 hold the 256-bit LASX vector registers, a 32-byte stride within the context. + private const int FRegisterCount = 32; + private const int FRegisterStride = 32; + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + => SimdRegisterAccess.TryReadRegister(context, (int)Marshal.OffsetOf(nameof(F)), FRegisterStride, FRegisterCount, index, out value); + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + => SimdRegisterAccess.TryWriteRegister(context, (int)Marshal.OffsetOf(nameof(F)), FRegisterStride, FRegisterCount, index, value); + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs index f329828a69798c..a7a08594737c82 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs @@ -228,6 +228,16 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // F0-F31 are the 64-bit floating-point registers, an 8-byte stride within the context. + private const int FRegisterCount = 32; + private const int FRegisterStride = 8; + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + => SimdRegisterAccess.TryReadRegister(context, (int)Marshal.OffsetOf(nameof(F)), FRegisterStride, FRegisterCount, index, out value); + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + => SimdRegisterAccess.TryWriteRegister(context, (int)Marshal.OffsetOf(nameof(F)), FRegisterStride, FRegisterCount, index, value); + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/SimdRegisterAccess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/SimdRegisterAccess.cs new file mode 100644 index 00000000000000..0ef4f58f2f7c44 --- /dev/null +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/SimdRegisterAccess.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers.Binary; + +namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; + +/// +/// Shared helpers for reading and writing a scalar value from a fixed-stride floating-point / SIMD +/// register file (the V/XMM/F/D areas) laid out contiguously within a platform CONTEXT buffer. +/// +internal static class SimdRegisterAccess +{ + /// + /// Reads the low 64 bits (interpreted as a ) of the -th + /// register in the file that starts at with a + /// byte stride. Returns false when is outside the register file. + /// + public static bool TryReadRegister(ReadOnlySpan context, int fileOffset, int registerStride, int registerCount, int index, out double value) + { + value = 0.0; + if ((uint)index >= (uint)registerCount) + return false; + int offset = fileOffset + (index * registerStride); + if (offset + sizeof(ulong) <= context.Length) + value = BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(context.Slice(offset))); + return true; + } + + /// + /// Writes (4 or 8 bytes) into the low bytes of the -th + /// register in the file that starts at with a + /// byte stride. Returns false when is outside the register file. + /// + public static bool TryWriteRegister(Span context, int fileOffset, int registerStride, int registerCount, int index, ReadOnlySpan value) + { + if ((uint)index >= (uint)registerCount) + return false; + int offset = fileOffset + (index * registerStride); + if (offset + value.Length > context.Length) + return false; + value.CopyTo(context.Slice(offset, value.Length)); + return true; + } +} diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs index 0070fa0a3ecaab..32b574952ccf5e 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/X86Context.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.InteropServices; +using System.Buffers.Binary; using Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers.X86; namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; @@ -181,6 +182,61 @@ public bool TryReadRegister(int number, out TargetNUInt value) } } + // The x87 FP stack exposes 8 logical registers ST(0)-ST(7); each occupies a 10-byte + // 80-bit slot in the FloatSave register area. + private const int X87RegisterCount = 8; + + private static int Float80Size + => (int)Marshal.OffsetOf(nameof(ST1)) - (int)Marshal.OffsetOf(nameof(ST0)); + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + { + value = 0.0; + if ((uint)index >= X87RegisterCount) + return false; + + // The availability mask exposes all 8 slots even when the live stack is shallower; + // out-of-depth slots read as 0. + if (!TryGetX87SlotOffset(context, index, out int offset)) + return true; + + if (offset + Float80Size <= context.Length) + value = FloatConversion.X87ExtendedToDouble(context.Slice(offset, Float80Size)); + return true; + } + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) + { + if ((uint)index >= X87RegisterCount) + return false; + + // Writing an out-of-depth (or otherwise unresolvable) slot is not supported. + if (!TryGetX87SlotOffset(context, index, out int offset) || offset + Float80Size > context.Length) + return false; + + double d = value.Length == sizeof(float) + ? BitConverter.Int32BitsToSingle(BinaryPrimitives.ReadInt32LittleEndian(value)) + : BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(value)); + FloatConversion.X87DoubleToExtended(d, context.Slice(offset, Float80Size)); + return true; + } + + // Resolves the byte offset of the 80-bit slot backing logical register ST(). + // REGISTER_X86_FPSTACK_0 names the bottom of the logical stack: ST(i) with i = top - logicalIndex. + // Returns false when logicalIndex is beyond the live stack depth. + private static bool TryGetX87SlotOffset(ReadOnlySpan context, int logicalIndex, out int offset) + { + offset = 0; + uint statusWord = BinaryPrimitives.ReadUInt32LittleEndian(context.Slice((int)Marshal.OffsetOf(nameof(StatusWord)))); + uint rawTop = (statusWord >> 11) & 0x7; + uint floatStackTop = 7 - rawTop; + if ((uint)logicalIndex > floatStackTop) + return false; + uint physIdx = (rawTop + (floatStackTop - (uint)logicalIndex)) & 0x7; + offset = (int)Marshal.OffsetOf(nameof(ST0)) + ((int)physIdx * Float80Size); + return true; + } + public readonly (uint Flag, string Name)[] GetScalarRegisters() => s_scalarRegisters; public readonly (uint Flag, int Start, int End)[] GetWideSpans() => s_wideSpans; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index a3d1aff887945b..c662d5c35cb622 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -5784,7 +5783,7 @@ public int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex) return hr; } - public int GetTargetContextSize(ContextSizeFlags flags, uint* pSize) + public int GetTargetContextSize(uint contextFlags, uint* pSize) { int hr = HResults.S_OK; try @@ -5793,12 +5792,14 @@ public int GetTargetContextSize(ContextSizeFlags flags, uint* pSize) throw new ArgumentNullException(nameof(pSize)); IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); - *pSize = flags switch - { - ContextSizeFlags.Base => ctx.SizeWithoutExtendedRegisters, - ContextSizeFlags.ExtendedRegisters => ctx.Size, - _ => throw new ArgumentException($"Invalid context size flags {(int)flags}", nameof(flags)), - }; + + // The CONTEXT size varies with the flags only on platforms that support variable-sized + // CONTEXTs (currently just x86's extended registers). On every other platform + // ExtendedRegistersFlag is 0 and SizeWithoutExtendedRegisters == Size, so the full size + // is always returned. This mirrors the native DAC's TARGET_X86 build-time gate. + *pSize = ctx.ExtendedRegistersFlag != 0 && (contextFlags & ctx.ExtendedRegistersFlag) != ctx.ExtendedRegistersFlag + ? ctx.SizeWithoutExtendedRegisters + : ctx.Size; } catch (System.Exception ex) { @@ -5808,7 +5809,7 @@ public int GetTargetContextSize(ContextSizeFlags flags, uint* pSize) if (_legacy is not null) { uint sizeLocal; - int hrLocal = _legacy.GetTargetContextSize(flags, &sizeLocal); + int hrLocal = _legacy.GetTargetContextSize(contextFlags, &sizeLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) Debug.Assert(*pSize == sizeLocal, $"cDAC: {*pSize}, DAC: {sizeLocal}"); @@ -5817,56 +5818,6 @@ public int GetTargetContextSize(ContextSizeFlags flags, uint* pSize) return hr; } - public int GetTargetInfo(TargetInfo* pTargetInfo) - { - int hr = HResults.S_OK; - try - { - if (pTargetInfo is null) - throw new ArgumentNullException(nameof(pTargetInfo)); - - Contracts.IRuntimeInfo runtimeInfo = _target.Contracts.RuntimeInfo; - - pTargetInfo->Arch = runtimeInfo.GetTargetArchitecture() switch - { - Contracts.RuntimeInfoArchitecture.X86 => TargetArchitecture.X86, - Contracts.RuntimeInfoArchitecture.X64 => TargetArchitecture.AMD64, - Contracts.RuntimeInfoArchitecture.Arm => TargetArchitecture.Arm, - Contracts.RuntimeInfoArchitecture.Arm64 => TargetArchitecture.Arm64, - Contracts.RuntimeInfoArchitecture.LoongArch64 => TargetArchitecture.LoongArch64, - Contracts.RuntimeInfoArchitecture.RiscV64 => TargetArchitecture.RiscV64, - Contracts.RuntimeInfoArchitecture.Wasm => TargetArchitecture.Wasm, - _ => TargetArchitecture.Unknown, - }; - - pTargetInfo->OS = runtimeInfo.GetTargetOperatingSystem() switch - { - Contracts.RuntimeInfoOperatingSystem.Windows => TargetOperatingSystem.Windows, - Contracts.RuntimeInfoOperatingSystem.Unix => TargetOperatingSystem.Unix, - Contracts.RuntimeInfoOperatingSystem.Apple => TargetOperatingSystem.Unix, - _ => TargetOperatingSystem.Unknown, - }; - } - catch (System.Exception ex) - { - hr = ex.HResult; - } -#if DEBUG - if (_legacy is not null) - { - TargetInfo targetInfoLocal; - int hrLocal = _legacy.GetTargetInfo(&targetInfoLocal); - Debug.ValidateHResult(hr, hrLocal); - if (hr == HResults.S_OK) - { - Debug.Assert(pTargetInfo->Arch == targetInfoLocal.Arch, $"cDAC: {pTargetInfo->Arch}, DAC: {targetInfoLocal.Arch}"); - Debug.Assert(pTargetInfo->OS == targetInfoLocal.OS, $"cDAC: {pTargetInfo->OS}, DAC: {targetInfoLocal.OS}"); - } - } -#endif - return hr; - } - public int ContextHasExtendedRegisters(ContextBuffer contextBuffer, Interop.BOOL* pResult) { int hr = HResults.S_OK; @@ -6076,7 +6027,7 @@ public int WriteRegistersToContext(ContextBuffer contextBuffer, CorDebugRegister return hr; } - public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* pValues) + public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, ulong* pValues) { int hr = HResults.S_OK; try @@ -6091,13 +6042,27 @@ public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegiste throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); ctx.FillFromBuffer(new Span(contextBuffer.pContextBytes, (int)ctx.Size)); + ReadOnlySpan buf = new ReadOnlySpan(contextBuffer.pContextBytes, (int)ctx.Size); RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); for (uint i = 0; i < nRegs; i++) { - // Registers with no CONTEXT slot (float / SIMD) read as zero. string? name = MapToCdacName(arch, regs[i]); - pValues[i] = (name is not null && ctx.TryReadRegister(name, out TargetNUInt v)) ? (nuint)v.Value : 0; + if (name is not null && ctx.TryReadRegister(name, out TargetNUInt v)) + { + // Integer register: zero-extend the pointer-sized value to 64 bits. + pValues[i] = (ulong)v.Value; + } + else if (TryReadFloatRegister(ctx, buf, arch, regs[i], out double floatValue)) + { + // Float / SIMD register: its scalar 64-bit double bit pattern. + pValues[i] = (ulong)BitConverter.DoubleToInt64Bits(floatValue); + } + else + { + // Registers with no CONTEXT slot at all read as zero. + pValues[i] = 0; + } } } catch (System.Exception ex) @@ -6107,9 +6072,9 @@ public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegiste #if DEBUG if (_legacy is not null) { - nuint[] valuesLocal = new nuint[nRegs]; + ulong[] valuesLocal = new ulong[nRegs]; int hrLocal; - fixed (nuint* pValuesLocal = valuesLocal) + fixed (ulong* pValuesLocal = valuesLocal) hrLocal = _legacy.ReadRegistersFromContext(contextBuffer, regs, nRegs, pValuesLocal); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) @@ -6122,6 +6087,32 @@ public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegiste return hr; } + // Reads a single float / SIMD register's scalar 64-bit value (as a double) from the target context. + private static bool TryReadFloatRegister(IPlatformAgnosticContext ctx, ReadOnlySpan context, + RuntimeInfoArchitecture arch, CorDebugRegister reg, out double value) + { + value = 0.0; + if (!TryGetFloatRegisterIndex(arch, reg, out int index)) + return false; + return ctx.TryReadFloatingPointRegister(context, index, out value); + } + + private static bool TryGetFloatRegisterIndex(RuntimeInfoArchitecture arch, CorDebugRegister reg, out int index) + { + int first = arch switch + { + RuntimeInfoArchitecture.X86 => (int)CorDebugRegister.REGISTER_X86_FPSTACK_0, + RuntimeInfoArchitecture.X64 => (int)CorDebugRegister.REGISTER_AMD64_XMM0, + RuntimeInfoArchitecture.Arm64 => (int)CorDebugRegister.REGISTER_ARM64_V0, + RuntimeInfoArchitecture.Arm => (int)CorDebugRegister.REGISTER_ARM_D0, + RuntimeInfoArchitecture.LoongArch64 => (int)CorDebugRegister.REGISTER_LOONGARCH64_F0, + RuntimeInfoArchitecture.RiscV64 => (int)CorDebugRegister.REGISTER_RISCV64_F0, + _ => -1, + }; + index = first < 0 ? -1 : (int)reg - first; + return index >= 0; + } + public int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable) { int hr = HResults.S_OK; @@ -6191,123 +6182,35 @@ public int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* return hr; } - public int ReadFloatRegistersFromContext(ContextBuffer contextBuffer, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop) + public int WriteFloatRegisterToContext(ContextBuffer contextBuffer, CorDebugRegister reg, byte* pValue, uint valueSize) { +#if DEBUG + byte[]? originalContext = null; + if (contextBuffer.pContextBytes is not null && contextBuffer.contextSize > 0) + originalContext = new ReadOnlySpan(contextBuffer.pContextBytes, (int)contextBuffer.contextSize).ToArray(); +#endif int hr = HResults.S_OK; try { - if (contextBuffer.pContextBytes is null || values is null || pValuesCount is null || - pFirstFloatReg is null || pFloatStackTop is null || maxValues == 0) + if (contextBuffer.pContextBytes is null || pValue is null || + (valueSize != sizeof(float) && valueSize != sizeof(double))) { - throw new ArgumentException("Invalid argument to ReadFloatRegistersFromContext"); + throw new ArgumentException("Invalid argument to WriteFloatRegisterToContext"); } IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); if (contextBuffer.contextSize < ctx.Size) throw new ArgumentException("Context buffer too small", nameof(contextBuffer)); - ReadOnlySpan buf = new ReadOnlySpan(contextBuffer.pContextBytes, (int)ctx.Size); - - *pValuesCount = 0; - *pFirstFloatReg = -1; - *pFloatStackTop = 0; - new Span(values, (int)maxValues).Clear(); + Span buf = new Span(contextBuffer.pContextBytes, (int)ctx.Size); RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture(); + ReadOnlySpan valueBytes = new ReadOnlySpan(pValue, (int)valueSize); - // Read a little-endian 64-bit reinterpret at the given offset, or 0 if the - // requested slot lies beyond the buffer. - static double ReadSlot64(ReadOnlySpan buf, int offset) + if (!TryGetFloatRegisterIndex(arch, reg, out int index) || + !ctx.TryWriteFloatingPointRegister(buf, index, valueBytes)) { - if (offset < 0 || offset + sizeof(ulong) > buf.Length) - return 0.0; - return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(buf.Slice(offset))); - } - - switch (arch) - { - case RuntimeInfoArchitecture.X86: - { - // FloatSave.StatusWord is at 0x20; the 80-bit ST register area starts at 0x38. - const int StatusWordOffset = 0x20; - const int RegisterAreaOffset = 0x38; - uint statusWord = BinaryPrimitives.ReadUInt32LittleEndian(buf.Slice(StatusWordOffset)); - uint rawTop = (statusWord >> 11) & 0x7; - uint floatStackTop = 7 - rawTop; - *pFloatStackTop = floatStackTop; - *pFirstFloatReg = (int)CorDebugRegister.REGISTER_X86_FPSTACK_0; - - uint count = floatStackTop + 1; - if (count > maxValues) - count = maxValues; - *pValuesCount = count; - - for (uint i = 0; i < count; i++) - { - uint physIdx = (rawTop + i) & 0x7; - int slot = RegisterAreaOffset + (int)physIdx * 10; - values[i] = (slot + 10 <= buf.Length) ? FloatConversion.X87ExtendedToDouble(buf.Slice(slot, 10)) : 0.0; - } - break; - } - case RuntimeInfoArchitecture.X64: - { - // Xmm0 lives in the FltSave area at offset 0x1a0; 16 registers, 16-byte stride. - const int Xmm0Offset = 0x1a0; - uint count = 16; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = (int)CorDebugRegister.REGISTER_AMD64_XMM0; - for (uint i = 0; i < count; i++) - values[i] = ReadSlot64(buf, Xmm0Offset + (int)i * 16); - break; - } - case RuntimeInfoArchitecture.Arm64: - { - const int V0Offset = 0x110; - uint count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = (int)CorDebugRegister.REGISTER_ARM64_V0; - for (uint i = 0; i < count; i++) - values[i] = ReadSlot64(buf, V0Offset + (int)i * 16); - break; - } - case RuntimeInfoArchitecture.Arm: - { - // ARM D registers overlay the Q register area at offset 0x50; 8-byte stride. - const int D0Offset = 0x50; - uint count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - for (uint i = 0; i < count; i++) - values[i] = ReadSlot64(buf, D0Offset + (int)i * 8); - break; - } - case RuntimeInfoArchitecture.LoongArch64: - { - const int F0Offset = 0x110; - uint count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = (int)CorDebugRegister.REGISTER_LOONGARCH64_F0; - for (uint i = 0; i < count; i++) - values[i] = ReadSlot64(buf, F0Offset + (int)i * 32); - break; - } - case RuntimeInfoArchitecture.RiscV64: - { - const int F0Offset = 0x110; - uint count = 32; - if (count > maxValues) count = maxValues; - *pValuesCount = count; - *pFirstFloatReg = (int)CorDebugRegister.REGISTER_RISCV64_F0; - for (uint i = 0; i < count; i++) - values[i] = ReadSlot64(buf, F0Offset + (int)i * 8); - break; - } - default: - throw new NotImplementedException($"ReadFloatRegistersFromContext: unsupported architecture {arch}"); + throw new ArgumentException($"Register {reg} is not a float register", nameof(reg)); } } catch (System.Exception ex) @@ -6315,26 +6218,24 @@ static double ReadSlot64(ReadOnlySpan buf, int offset) hr = ex.HResult; } #if DEBUG - if (_legacy is not null && pValuesCount is not null && pFirstFloatReg is not null && - pFloatStackTop is not null && values is not null && maxValues > 0) + if (_legacy is not null && originalContext is not null && pValue is not null && + (valueSize == sizeof(float) || valueSize == sizeof(double))) { - double[] valuesLocal = new double[maxValues]; - uint valuesCountLocal; - int firstFloatRegLocal; - uint floatStackTopLocal; + // Replay the same write through the legacy DAC on a copy of the + // pre-write context bytes and confirm the resulting buffers match. + byte[] legacyContext = originalContext; int hrLocal; - fixed (double* pValuesLocal = valuesLocal) - hrLocal = _legacy.ReadFloatRegistersFromContext(contextBuffer, maxValues, pValuesLocal, - &valuesCountLocal, &firstFloatRegLocal, &floatStackTopLocal); + fixed (byte* pLegacy = legacyContext) + { + ContextBuffer legacyBuffer = new ContextBuffer { pContextBytes = pLegacy, contextSize = contextBuffer.contextSize }; + hrLocal = _legacy.WriteFloatRegisterToContext(legacyBuffer, reg, pValue, valueSize); + } Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) { - Debug.Assert(*pValuesCount == valuesCountLocal, $"count cDAC: {*pValuesCount}, DAC: {valuesCountLocal}"); - Debug.Assert(*pFirstFloatReg == firstFloatRegLocal, $"firstFloatReg cDAC: {*pFirstFloatReg}, DAC: {firstFloatRegLocal}"); - Debug.Assert(*pFloatStackTop == floatStackTopLocal, $"floatStackTop cDAC: {*pFloatStackTop}, DAC: {floatStackTopLocal}"); - for (uint i = 0; i < *pValuesCount && i < maxValues; i++) - Debug.Assert(BitConverter.DoubleToInt64Bits(values[i]) == BitConverter.DoubleToInt64Bits(valuesLocal[i]), - $"float[{i}] cDAC: {values[i]}, DAC: {valuesLocal[i]}"); + ReadOnlySpan cdacResult = new ReadOnlySpan(contextBuffer.pContextBytes, (int)contextBuffer.contextSize); + Debug.Assert(cdacResult.SequenceEqual(legacyContext), + "cDAC and DAC produced different context bytes after WriteFloatRegisterToContext"); } } #endif diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index b3d356c340c644..54251164d35072 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -319,8 +319,8 @@ public struct DebuggerIPCE_STRData_StubFrame // Holds data for each stack frame or chain, passed from the RC to the DI during a // stack walk. Mirrors the native Debugger_STRData in src/coreclr/debug/inc/dacdbistructures.h. -// ctx is a host-sized pointer to a DBI-owned buffer containing the target's opaque -// CONTEXT byte image; paths that produce no context leave it 0. +// ctx wraps a host-sized pointer to a DBI-owned buffer (plus its size) holding the +// target's opaque CONTEXT byte image; paths that produce no context leave it zeroed. [StructLayout(LayoutKind.Explicit)] public struct Debugger_STRData { @@ -332,12 +332,12 @@ public enum EType } [FieldOffset(0)] public ulong fp; // CORDB_ADDRESS - [FieldOffset(8)] public nuint ctx; // BYTE* (host-sized) - [FieldOffset(16)] public ulong vmCurrentAppDomainToken; // VMPTR_AppDomain - [FieldOffset(24)] public EType eType; + [FieldOffset(8)] public ContextBuffer ctx; // ContextBuffer (host-sized pointer + size) + [FieldOffset(24)] public ulong vmCurrentAppDomainToken; // VMPTR_AppDomain + [FieldOffset(32)] public EType eType; // v (method frame) and stubFrame overlap, mirroring the native anonymous union. - [FieldOffset(32)] public DebuggerIPCE_STRData_MethodFrame v; - [FieldOffset(32)] public DebuggerIPCE_STRData_StubFrame stubFrame; + [FieldOffset(40)] public DebuggerIPCE_STRData_MethodFrame v; + [FieldOffset(40)] public DebuggerIPCE_STRData_StubFrame stubFrame; } #pragma warning restore CS0649 @@ -500,37 +500,6 @@ public enum CorDebugSetContextFlags SET_CONTEXT_FLAG_UNWIND_FRAME = 0x2, } -public enum TargetArchitecture : int -{ - Unknown = 0, - X86, - AMD64, - Arm, - Arm64, - LoongArch64, - RiscV64, - Wasm, -} - -public enum TargetOperatingSystem : int -{ - Unknown = 0, - Windows, - Unix, -} - -public struct TargetInfo -{ - public TargetArchitecture Arch; - public TargetOperatingSystem OS; -} - -public enum ContextSizeFlags : int -{ - Base = 0, - ExtendedRegisters, -} - public enum CorDebugRegister : int { REGISTER_INSTRUCTION_POINTER = 0, @@ -1070,13 +1039,13 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); [PreserveSig] - int GetTargetContextSize(ContextSizeFlags flags, uint* pSize); + int GetTargetContextSize(uint contextFlags, uint* pSize); [PreserveSig] int WriteRegistersToContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* values); [PreserveSig] - int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, nuint* pValues); + int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegister* regs, uint nRegs, ulong* pValues); [PreserveSig] int GetAvailableRegistersMask(Interop.BOOL fActive, Interop.BOOL fQuickUnwind, uint regCount, byte* pAvailable); @@ -1085,10 +1054,7 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int ConvertJitRegNumToCorDebugRegister(uint jitRegNum, CorDebugRegister* pReg); [PreserveSig] - int ReadFloatRegistersFromContext(ContextBuffer contextBuffer, uint maxValues, double* values, uint* pValuesCount, int* pFirstFloatReg, uint* pFloatStackTop); - - [PreserveSig] - int GetTargetInfo(TargetInfo* pTargetInfo); + int WriteFloatRegisterToContext(ContextBuffer contextBuffer, CorDebugRegister reg, byte* pValue, uint valueSize); [PreserveSig] int ContextHasExtendedRegisters(ContextBuffer contextBuffer, Interop.BOOL* pResult); From f75cbfbeb4348252ccd6b8e8939bceb25d0f4cef Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 8 Jul 2026 13:42:18 -0700 Subject: [PATCH 14/26] Add GetTargetInfo DacDbi API Introduces IDacDbiInterface::GetTargetInfo, which reports the target's processor architecture and OS family, along with the TargetInfo/TargetArchitecture/TargetOperatingSystem types. Includes the native DAC implementation and the managed cDAC implementation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 38 +++++++++++++ src/coreclr/debug/daccess/dacdbiimpl.h | 1 + src/coreclr/debug/inc/dacdbiinterface.h | 28 ++++++++++ src/coreclr/inc/dacdbi.idl | 9 ++-- .../Dbi/DacDbiImpl.cs | 53 +++++++++++++++++++ .../Dbi/IDacDbiInterface.cs | 30 +++++++++++ 6 files changed, 154 insertions(+), 5 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 972e1d03de9055..df00a968f17c5a 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -8021,6 +8021,44 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetGenericArgTokenIndex(VMPTR_Met return S_OK; } +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetInfo(OUT TargetInfo * pTargetInfo) +{ + DD_ENTER_MAY_THROW; + + if (pTargetInfo == NULL) + return E_INVALIDARG; + +#if defined(TARGET_X86) + pTargetInfo->arch = kArchX86; +#elif defined(TARGET_AMD64) + pTargetInfo->arch = kArchAMD64; +#elif defined(TARGET_ARM) + pTargetInfo->arch = kArchArm; +#elif defined(TARGET_ARM64) + pTargetInfo->arch = kArchArm64; +#elif defined(TARGET_LOONGARCH64) + pTargetInfo->arch = kArchLoongArch64; +#elif defined(TARGET_RISCV64) + pTargetInfo->arch = kArchRiscV64; +#elif defined(TARGET_WASM) + pTargetInfo->arch = kArchWasm; +#else + pTargetInfo->arch = kArchUnknown; +#endif + +#if defined(TARGET_UNIX) + pTargetInfo->os = kOSUnix; +#elif defined(TARGET_WINDOWS) + pTargetInfo->os = kOSWindows; +#else + pTargetInfo->os = kOSUnknown; +#endif + + pTargetInfo->pointerSize = sizeof(TADDR); + + return S_OK; +} + DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, UINT32 handleMask, BOOL resolvePointers) : mDac(dac), mWalkStacks(walkStacks), mHandleMask(handleMask), mStackWalker(NULL), mResolvePointers(resolvePointers), mHandleWalker(NULL) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 99d727b3e9ec8e..09543ba08a1199 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -168,6 +168,7 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN ContextBuffer contextBuffer1, IN ContextBuffer contextBuffer2, OUT BOOL * pResult); HRESULT STDMETHODCALLTYPE CopyContext(IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags); + HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 2a128737ef2b13..e9602834ec8d9a 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -2254,6 +2254,34 @@ IDacDbiInterface : public IUnknown IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags) = 0; + typedef enum + { + kArchUnknown = 0, + kArchX86, + kArchAMD64, + kArchArm, + kArchArm64, + kArchLoongArch64, + kArchRiscV64, + kArchWasm, + } TargetArchitecture; + + typedef enum + { + kOSUnknown = 0, + kOSWindows, + kOSUnix, + } TargetOperatingSystem; + + struct TargetInfo + { + TargetArchitecture arch; + TargetOperatingSystem os; + ULONG32 pointerSize; + }; + + // Returns the target's processor architecture and OS family. + virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; // The following tag tells the DD-marshalling tool to stop scanning. // END_MARSHAL diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index c5f479fcb126c0..aeab9cf6f364d1 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -133,7 +133,7 @@ typedef struct { void *pList; int nEntries; } DacDbiArrayList_CORDB_ADDRESS; typedef struct { void *pList; int nEntries; } DacDbiArrayList_GUID; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_SEGMENT; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_MEMORY_RANGE; -typedef struct { int arch; int os; } TargetInfo; +typedef struct { int arch; int os; ULONG32 pointerSize; } TargetInfo; cpp_quote("#endif") @@ -447,7 +447,7 @@ interface IDacDbiInterface : IUnknown HRESULT GetGenericArgTokenIndex([in] VMPTR_MethodDesc vmMethod, [out] UINT32 * pTokenIndex); // Context size queries - HRESULT GetTargetContextSize([in] int flags, [out] ULONG32 * pSize); + HRESULT GetTargetContextSize([in] ULONG32 contextFlags, [out] ULONG32 * pSize); // CONTEXT register accessors. HRESULT WriteRegistersToContext([in] ContextBuffer contextBuffer, [in] const int * regs, [in] ULONG32 nRegs, [in] const TADDR * values); @@ -475,9 +475,6 @@ interface IDacDbiInterface : IUnknown [in] const BYTE * pValue, [in] ULONG32 valueSize); - // Returns the target's processor architecture and OS family. - HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); - HRESULT ContextHasExtendedRegisters([in] ContextBuffer contextBuffer, [out] BOOL * pResult); HRESULT CompareControlRegisters([in] ContextBuffer contextBuffer1, [in] ContextBuffer contextBuffer2, [out] BOOL * pResult); @@ -487,4 +484,6 @@ interface IDacDbiInterface : IUnknown // pulls exactly the requested chunks from the source; flags == 0 preserves // the destination's existing ContextFlags. HRESULT CopyContext([in] ContextBuffer destinationContext, [in] ContextBuffer sourceContext, [in] ULONG32 flags); + // Returns the target's processor architecture and OS family. + HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index c662d5c35cb622..6e639019b5f155 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -6087,6 +6087,59 @@ public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegiste return hr; } + public int GetTargetInfo(TargetInfo* pTargetInfo) + { + int hr = HResults.S_OK; + try + { + if (pTargetInfo is null) + throw new ArgumentNullException(nameof(pTargetInfo)); + + Contracts.IRuntimeInfo runtimeInfo = _target.Contracts.RuntimeInfo; + + pTargetInfo->Arch = runtimeInfo.GetTargetArchitecture() switch + { + Contracts.RuntimeInfoArchitecture.X86 => TargetArchitecture.X86, + Contracts.RuntimeInfoArchitecture.X64 => TargetArchitecture.AMD64, + Contracts.RuntimeInfoArchitecture.Arm => TargetArchitecture.Arm, + Contracts.RuntimeInfoArchitecture.Arm64 => TargetArchitecture.Arm64, + Contracts.RuntimeInfoArchitecture.LoongArch64 => TargetArchitecture.LoongArch64, + Contracts.RuntimeInfoArchitecture.RiscV64 => TargetArchitecture.RiscV64, + Contracts.RuntimeInfoArchitecture.Wasm => TargetArchitecture.Wasm, + _ => TargetArchitecture.Unknown, + }; + + pTargetInfo->OS = runtimeInfo.GetTargetOperatingSystem() switch + { + Contracts.RuntimeInfoOperatingSystem.Windows => TargetOperatingSystem.Windows, + Contracts.RuntimeInfoOperatingSystem.Unix => TargetOperatingSystem.Unix, + Contracts.RuntimeInfoOperatingSystem.Apple => TargetOperatingSystem.Unix, + _ => TargetOperatingSystem.Unknown, + }; + + pTargetInfo->PointerSize = (uint)_target.PointerSize; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + TargetInfo targetInfoLocal; + int hrLocal = _legacy.GetTargetInfo(&targetInfoLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + { + Debug.Assert(pTargetInfo->Arch == targetInfoLocal.Arch, $"cDAC: {pTargetInfo->Arch}, DAC: {targetInfoLocal.Arch}"); + Debug.Assert(pTargetInfo->OS == targetInfoLocal.OS, $"cDAC: {pTargetInfo->OS}, DAC: {targetInfoLocal.OS}"); + Debug.Assert(pTargetInfo->PointerSize == targetInfoLocal.PointerSize, $"cDAC: {pTargetInfo->PointerSize}, DAC: {targetInfoLocal.PointerSize}"); + } + } +#endif + return hr; + } + // Reads a single float / SIMD register's scalar 64-bit value (as a double) from the target context. private static bool TryReadFloatRegister(IPlatformAgnosticContext ctx, ReadOnlySpan context, RuntimeInfoArchitecture arch, CorDebugRegister reg, out double value) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 54251164d35072..45a03b9842a741 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -1038,6 +1038,7 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); + [PreserveSig] [PreserveSig] int GetTargetContextSize(uint contextFlags, uint* pSize); @@ -1064,4 +1065,33 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags); + + [PreserveSig] + int GetTargetInfo(TargetInfo* pTargetInfo); +} + +public enum TargetArchitecture +{ + Unknown = 0, + X86, + AMD64, + Arm, + Arm64, + LoongArch64, + RiscV64, + Wasm, +} + +public enum TargetOperatingSystem +{ + Unknown = 0, + Windows, + Unix, +} + +public struct TargetInfo +{ + public TargetArchitecture Arch; + public TargetOperatingSystem OS; + public uint PointerSize; } From c4e0eba3e54b6e90439bff0673e5aa480cacf9fb Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 21 Jul 2026 16:20:54 -0700 Subject: [PATCH 15/26] codE review --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 38 ------------- src/coreclr/debug/daccess/dacdbiimpl.h | 1 - src/coreclr/debug/di/process.cpp | 6 +-- src/coreclr/debug/inc/dacdbiinterface.h | 3 -- src/coreclr/inc/dacdbi.idl | 2 - .../Dbi/DacDbiImpl.cs | 53 ------------------- .../Dbi/IDacDbiInterface.cs | 4 -- 7 files changed, 3 insertions(+), 104 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index df00a968f17c5a..972e1d03de9055 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -8021,44 +8021,6 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetGenericArgTokenIndex(VMPTR_Met return S_OK; } -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTargetInfo(OUT TargetInfo * pTargetInfo) -{ - DD_ENTER_MAY_THROW; - - if (pTargetInfo == NULL) - return E_INVALIDARG; - -#if defined(TARGET_X86) - pTargetInfo->arch = kArchX86; -#elif defined(TARGET_AMD64) - pTargetInfo->arch = kArchAMD64; -#elif defined(TARGET_ARM) - pTargetInfo->arch = kArchArm; -#elif defined(TARGET_ARM64) - pTargetInfo->arch = kArchArm64; -#elif defined(TARGET_LOONGARCH64) - pTargetInfo->arch = kArchLoongArch64; -#elif defined(TARGET_RISCV64) - pTargetInfo->arch = kArchRiscV64; -#elif defined(TARGET_WASM) - pTargetInfo->arch = kArchWasm; -#else - pTargetInfo->arch = kArchUnknown; -#endif - -#if defined(TARGET_UNIX) - pTargetInfo->os = kOSUnix; -#elif defined(TARGET_WINDOWS) - pTargetInfo->os = kOSWindows; -#else - pTargetInfo->os = kOSUnknown; -#endif - - pTargetInfo->pointerSize = sizeof(TADDR); - - return S_OK; -} - DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, UINT32 handleMask, BOOL resolvePointers) : mDac(dac), mWalkStacks(walkStacks), mHandleMask(handleMask), mStackWalker(NULL), mResolvePointers(resolvePointers), mHandleWalker(NULL) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 09543ba08a1199..99d727b3e9ec8e 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -168,7 +168,6 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN ContextBuffer contextBuffer1, IN ContextBuffer contextBuffer2, OUT BOOL * pResult); HRESULT STDMETHODCALLTYPE CopyContext(IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags); - HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo); private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 16de37d13a72eb..502350d719a07d 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -1463,7 +1463,7 @@ ULONG32 CordbProcess::GetTargetContextSize() if (m_ctxSize == 0) { ULONG32 size = 0; - IfFailThrow(GetDAC()->GetTargetContextSize(DT_CONTEXT_ALL, &size)); + IfFailThrow(GetDAC()->GetTargetContextSize(0x00000020L, &size)); // CONTEXT_EXTENDED_REGISTERS m_ctxSize = size; } return m_ctxSize; @@ -5836,7 +5836,7 @@ HRESULT CordbProcess::SafeReadThreadContext(CORDB_ADDRESS remoteContextAddr, Con // At a minimum we have room for a whole context up to the extended registers. ULONG32 minContextSize; - IfFailThrow(GetDAC()->GetTargetContextSize(DT_CONTEXT_FULL, &minContextSize)); + IfFailThrow(GetDAC()->GetTargetContextSize(0, &minContextSize)); // Read the minimum part. TargetBuffer tbMin = tbFull.SubBuffer(0, minContextSize); @@ -5885,7 +5885,7 @@ HRESULT CordbProcess::SafeWriteThreadContext(CORDB_ADDRESS remoteContextAddr, Co BOOL hasExtendedRegisters = FALSE; IfFailThrow(GetDAC()->ContextHasExtendedRegisters(contextBuffer, &hasExtendedRegisters)); IfFailThrow(GetDAC()->GetTargetContextSize( - hasExtendedRegisters ? DT_CONTEXT_ALL : DT_CONTEXT_FULL, + hasExtendedRegisters ? 0x00000020L : 0, // CONTEXT_EXTENDED_REGISTERS &sizeToWrite)); CORDB_ADDRESS pRemoteContext = remoteContextAddr; diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index e9602834ec8d9a..8c76282b89c911 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -2280,9 +2280,6 @@ IDacDbiInterface : public IUnknown ULONG32 pointerSize; }; - // Returns the target's processor architecture and OS family. - virtual HRESULT STDMETHODCALLTYPE GetTargetInfo(OUT TargetInfo * pTargetInfo) = 0; - // The following tag tells the DD-marshalling tool to stop scanning. // END_MARSHAL diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index aeab9cf6f364d1..9b237559a1ae29 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -484,6 +484,4 @@ interface IDacDbiInterface : IUnknown // pulls exactly the requested chunks from the source; flags == 0 preserves // the destination's existing ContextFlags. HRESULT CopyContext([in] ContextBuffer destinationContext, [in] ContextBuffer sourceContext, [in] ULONG32 flags); - // Returns the target's processor architecture and OS family. - HRESULT GetTargetInfo([out] struct TargetInfo * pTargetInfo); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 6e639019b5f155..c662d5c35cb622 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -6087,59 +6087,6 @@ public int ReadRegistersFromContext(ContextBuffer contextBuffer, CorDebugRegiste return hr; } - public int GetTargetInfo(TargetInfo* pTargetInfo) - { - int hr = HResults.S_OK; - try - { - if (pTargetInfo is null) - throw new ArgumentNullException(nameof(pTargetInfo)); - - Contracts.IRuntimeInfo runtimeInfo = _target.Contracts.RuntimeInfo; - - pTargetInfo->Arch = runtimeInfo.GetTargetArchitecture() switch - { - Contracts.RuntimeInfoArchitecture.X86 => TargetArchitecture.X86, - Contracts.RuntimeInfoArchitecture.X64 => TargetArchitecture.AMD64, - Contracts.RuntimeInfoArchitecture.Arm => TargetArchitecture.Arm, - Contracts.RuntimeInfoArchitecture.Arm64 => TargetArchitecture.Arm64, - Contracts.RuntimeInfoArchitecture.LoongArch64 => TargetArchitecture.LoongArch64, - Contracts.RuntimeInfoArchitecture.RiscV64 => TargetArchitecture.RiscV64, - Contracts.RuntimeInfoArchitecture.Wasm => TargetArchitecture.Wasm, - _ => TargetArchitecture.Unknown, - }; - - pTargetInfo->OS = runtimeInfo.GetTargetOperatingSystem() switch - { - Contracts.RuntimeInfoOperatingSystem.Windows => TargetOperatingSystem.Windows, - Contracts.RuntimeInfoOperatingSystem.Unix => TargetOperatingSystem.Unix, - Contracts.RuntimeInfoOperatingSystem.Apple => TargetOperatingSystem.Unix, - _ => TargetOperatingSystem.Unknown, - }; - - pTargetInfo->PointerSize = (uint)_target.PointerSize; - } - catch (System.Exception ex) - { - hr = ex.HResult; - } -#if DEBUG - if (_legacy is not null) - { - TargetInfo targetInfoLocal; - int hrLocal = _legacy.GetTargetInfo(&targetInfoLocal); - Debug.ValidateHResult(hr, hrLocal); - if (hr == HResults.S_OK) - { - Debug.Assert(pTargetInfo->Arch == targetInfoLocal.Arch, $"cDAC: {pTargetInfo->Arch}, DAC: {targetInfoLocal.Arch}"); - Debug.Assert(pTargetInfo->OS == targetInfoLocal.OS, $"cDAC: {pTargetInfo->OS}, DAC: {targetInfoLocal.OS}"); - Debug.Assert(pTargetInfo->PointerSize == targetInfoLocal.PointerSize, $"cDAC: {pTargetInfo->PointerSize}, DAC: {targetInfoLocal.PointerSize}"); - } - } -#endif - return hr; - } - // Reads a single float / SIMD register's scalar 64-bit value (as a double) from the target context. private static bool TryReadFloatRegister(IPlatformAgnosticContext ctx, ReadOnlySpan context, RuntimeInfoArchitecture arch, CorDebugRegister reg, out double value) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 45a03b9842a741..d5c31708fb76e1 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -1038,7 +1038,6 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int GetGenericArgTokenIndex(ulong vmMethod, uint* pIndex); - [PreserveSig] [PreserveSig] int GetTargetContextSize(uint contextFlags, uint* pSize); @@ -1065,9 +1064,6 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags); - - [PreserveSig] - int GetTargetInfo(TargetInfo* pTargetInfo); } public enum TargetArchitecture From 171a6286879095307ff56aa90f3292dbe7e65666 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Tue, 21 Jul 2026 22:18:06 -0700 Subject: [PATCH 16/26] fix merge --- .../Contracts/StackWalk/Context/WasmContext.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs index 24ac092843f18b..209f11a502d670 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs @@ -159,4 +159,15 @@ public readonly bool TryReadRegister(int number, out TargetNUInt value) value = default; return false; } + + public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, int index, out double value) + { + value = default; + return false; + } + + public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) => false; + + public readonly (uint Flag, string Name)[] GetScalarRegisters() => []; + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => []; } From c117f11958f70421fb28f0e737158a99f92dc55e Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 22 Jul 2026 10:25:32 -0700 Subject: [PATCH 17/26] fix loong and riscv --- .../Contracts/StackWalk/Context/LoongArch64Context.cs | 2 +- .../Contracts/StackWalk/Context/RISCV64Context.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs index d4cd0bdade34e8..75ba2e786c07a7 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/LoongArch64Context.cs @@ -10,7 +10,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; /// /// LoongArch64-specific thread context. /// -[StructLayout(LayoutKind.Explicit, Pack = 1)] +[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 0x520)] internal struct LoongArch64Context : IPlatformContext { [Flags] diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs index a7a08594737c82..a59552648aca12 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/RISCV64Context.cs @@ -10,7 +10,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; /// /// RISC-V 64-bit specific thread context. /// -[StructLayout(LayoutKind.Explicit, Pack = 1)] +[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 0x220)] internal struct RISCV64Context : IPlatformContext { [Flags] From f445952d4842bdf9277f7912bb548669651716e0 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 15:44:18 -0700 Subject: [PATCH 18/26] Update src/coreclr/debug/inc/dacdbistructures.h Co-authored-by: Noah Falk --- src/coreclr/debug/inc/dacdbistructures.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index 6966a6719c6d3d..02ed43fbf4bd17 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -160,7 +160,12 @@ struct MSLAYOUT TargetBuffer ULONG cbSize; }; -// Describes an opaque target CONTEXT buffer in the host. +// A variable sized host memory context buffer in target architecture specific layout. +// The currently supported layout matches the Windows CONTEXT structure for the +// target architecture. +// Not (yet) supported: +// - Optional trailing XState feature data in the buffer +// - Add an architecture enum field to make the struct self-describing struct MSLAYOUT ContextBuffer { BYTE * pContextBytes; From 24b52fd1488af7255c41567f8ad9993b60b45468 Mon Sep 17 00:00:00 2001 From: rcj1 Date: Wed, 22 Jul 2026 16:12:27 -0700 Subject: [PATCH 19/26] only copy part of context that is required by the context flags --- src/coreclr/debug/di/cordb.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/di/cordb.cpp b/src/coreclr/debug/di/cordb.cpp index 295b42f444c2e7..debabd9cb98831 100644 --- a/src/coreclr/debug/di/cordb.cpp +++ b/src/coreclr/debug/di/cordb.cpp @@ -449,7 +449,7 @@ DbiGetThreadContext(HANDLE hThread, ctx->ContextFlags = lpContext->ContextFlags; if (::GetThreadContext(hThread, ctx)) { - *lpContext = *(T_CONTEXT*)ctx; + memcpy(lpContext, ctx, ContextSizeForFlags(ctx->ContextFlags)); res = TRUE; } @@ -485,7 +485,7 @@ DbiSetThreadContext(HANDLE hThread, CONTEXT *ctx = (CONTEXT*)_aligned_malloc(sizeof(CONTEXT), 16); if (ctx) { - *ctx = *(CONTEXT*)lpContext; + memcpy(ctx, lpContext, ContextSizeForFlags(lpContext->ContextFlags)); res = ::SetThreadContext(hThread, ctx); _aligned_free(ctx); } From ee43cdc2dc7d90f9af9e4417949e144b65667b36 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 16:46:55 -0700 Subject: [PATCH 20/26] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/coreclr/debug/di/shimlocaldatatarget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/debug/di/shimlocaldatatarget.cpp b/src/coreclr/debug/di/shimlocaldatatarget.cpp index 18b8372cf44b26..fb2317a0ff9e2e 100644 --- a/src/coreclr/debug/di/shimlocaldatatarget.cpp +++ b/src/coreclr/debug/di/shimlocaldatatarget.cpp @@ -380,7 +380,7 @@ ShimLocalDataTarget::GetThreadContext( HRESULT hr = E_FAIL; - if (!CheckContextSizeForBuffer(contextSize, pContext) || contextSize < sizeof(T_CONTEXT)) + if ((pContext == NULL) || !CheckContextSizeForFlags(contextSize, contextFlags)) { return E_INVALIDARG; } From 18e4abae453d758c4a0bebceab13425ecf9505a4 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 21:52:33 -0700 Subject: [PATCH 21/26] Update IDacDbiInterface.cs --- .../Dbi/IDacDbiInterface.cs | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 69b40812ab645a..9150db45f7f76d 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -1079,29 +1079,3 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, [PreserveSig] int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags); } - -public enum TargetArchitecture -{ - Unknown = 0, - X86, - AMD64, - Arm, - Arm64, - LoongArch64, - RiscV64, - Wasm, -} - -public enum TargetOperatingSystem -{ - Unknown = 0, - Windows, - Unix, -} - -public struct TargetInfo -{ - public TargetArchitecture Arch; - public TargetOperatingSystem OS; - public uint PointerSize; -} From 0c59041ff9271d80ff00305049250f981dc8ab28 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 21:54:17 -0700 Subject: [PATCH 22/26] Update dacdbiinterface.h --- src/coreclr/debug/inc/dacdbiinterface.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 8c76282b89c911..2a128737ef2b13 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -2254,31 +2254,6 @@ IDacDbiInterface : public IUnknown IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags) = 0; - typedef enum - { - kArchUnknown = 0, - kArchX86, - kArchAMD64, - kArchArm, - kArchArm64, - kArchLoongArch64, - kArchRiscV64, - kArchWasm, - } TargetArchitecture; - - typedef enum - { - kOSUnknown = 0, - kOSWindows, - kOSUnix, - } TargetOperatingSystem; - - struct TargetInfo - { - TargetArchitecture arch; - TargetOperatingSystem os; - ULONG32 pointerSize; - }; // The following tag tells the DD-marshalling tool to stop scanning. // END_MARSHAL From 6334ea1c0ef10e1c0bfb7b39a97c82e2e8064808 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 21:55:09 -0700 Subject: [PATCH 23/26] Update dacdbi.idl --- src/coreclr/inc/dacdbi.idl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index 9b237559a1ae29..aa1c651fd31bee 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -133,7 +133,6 @@ typedef struct { void *pList; int nEntries; } DacDbiArrayList_CORDB_ADDRESS; typedef struct { void *pList; int nEntries; } DacDbiArrayList_GUID; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_SEGMENT; typedef struct { void *pList; int nEntries; } DacDbiArrayList_COR_MEMORY_RANGE; -typedef struct { int arch; int os; ULONG32 pointerSize; } TargetInfo; cpp_quote("#endif") From e287b49ef8d50e984ea7b6119d7e8b22486feba0 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Wed, 22 Jul 2026 21:55:37 -0700 Subject: [PATCH 24/26] Update src/coreclr/debug/inc/dacdbistructures.h Co-authored-by: Jan Kotas --- src/coreclr/debug/inc/dacdbistructures.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index 02ed43fbf4bd17..a2095abc5267c1 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -161,8 +161,8 @@ struct MSLAYOUT TargetBuffer }; // A variable sized host memory context buffer in target architecture specific layout. -// The currently supported layout matches the Windows CONTEXT structure for the -// target architecture. +// The currently supported layout matches the CONTEXT structure for the +// target architecture and OS. // Not (yet) supported: // - Optional trailing XState feature data in the buffer // - Add an architecture enum field to make the struct self-describing From 45920f1c2b9be46ba04311345c2939f4d65ccc4d Mon Sep 17 00:00:00 2001 From: rcj1 Date: Thu, 23 Jul 2026 13:00:13 -0700 Subject: [PATCH 25/26] E --- src/coreclr/debug/daccess/dacdbiimpl.cpp | 41 ++++++--- src/coreclr/debug/daccess/dacdbiimpl.h | 6 +- src/coreclr/debug/di/process.cpp | 1 - src/coreclr/debug/di/rspriv.h | 3 - src/coreclr/debug/di/rsregsetcommon.cpp | 6 +- src/coreclr/debug/di/rsstackwalk.cpp | 20 ++++- src/coreclr/debug/di/rsthread.cpp | 39 ++------- src/coreclr/debug/inc/dacdbiinterface.h | 15 +++- src/coreclr/inc/dacdbi.idl | 14 ++-- .../Dbi/DacDbiImpl.cs | 24 ++++-- .../Dbi/IDacDbiInterface.cs | 9 +- .../cdac/tests/UnitTests/DacDbiImplTests.cs | 84 +++++++++++++++++++ 12 files changed, 191 insertions(+), 71 deletions(-) diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 972e1d03de9055..18560e3df9b016 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5874,6 +5874,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CompareControlRegisters( HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CopyContext( IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, + IN ContextCopyMode copyMode, IN ULONG32 flags) { DD_ENTER_MAY_THROW; @@ -5885,19 +5886,37 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CopyContext( // ContextFlags. if (!CheckContextSizeForBuffer(sourceContext.contextSize, sourceContext.pContextBytes)) return E_INVALIDARG; + if (copyMode != kCopyContextUseExplicitFlags && flags != 0) + return E_INVALIDARG; - if (flags != 0) - { - // flags != 0 stamps the destination's ContextFlags before the copy, so the - // chunk-wise copy pulls exactly the requested pieces from the source. - if (!CheckContextSizeForFlags(destinationContext.contextSize, flags)) - return E_INVALIDARG; - reinterpret_cast(destinationContext.pContextBytes)->ContextFlags = flags; - } - else + switch (copyMode) { - // flags == 0 preserves the destination's existing ContextFlags. - if (!CheckContextSizeForBuffer(destinationContext.contextSize, destinationContext.pContextBytes)) + case kCopyContextPreserveDestinationFlags: + if (!CheckContextSizeForBuffer(destinationContext.contextSize, destinationContext.pContextBytes)) + return E_INVALIDARG; + break; + + case kCopyContextMergeSourceFlags: + { + if (!CheckContextSizeForBuffer(destinationContext.contextSize, destinationContext.pContextBytes)) + return E_INVALIDARG; + + DT_CONTEXT * pDestination = reinterpret_cast(destinationContext.pContextBytes); + const DT_CONTEXT * pSource = reinterpret_cast(sourceContext.pContextBytes); + DWORD mergedFlags = pDestination->ContextFlags | pSource->ContextFlags; + if (!CheckContextSizeForFlags(destinationContext.contextSize, mergedFlags)) + return E_INVALIDARG; + pDestination->ContextFlags = mergedFlags; + break; + } + + case kCopyContextUseExplicitFlags: + if (!CheckContextSizeForFlags(destinationContext.contextSize, flags)) + return E_INVALIDARG; + reinterpret_cast(destinationContext.pContextBytes)->ContextFlags = flags; + break; + + default: return E_INVALIDARG; } diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 99d727b3e9ec8e..40873fc5aa6345 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -167,7 +167,11 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE CompareControlRegisters(IN ContextBuffer contextBuffer1, IN ContextBuffer contextBuffer2, OUT BOOL * pResult); - HRESULT STDMETHODCALLTYPE CopyContext(IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, IN ULONG32 flags); + HRESULT STDMETHODCALLTYPE CopyContext( + IN ContextBuffer destinationContext, + IN ContextBuffer sourceContext, + IN ContextCopyMode copyMode, + IN ULONG32 flags); private: void TypeHandleToExpandedTypeInfoImpl(AreValueTypesBoxed boxed, diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index 502350d719a07d..45ff58221055a5 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -12511,7 +12511,6 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven T_CONTEXT tempDebugContext; tempDebugContext.ContextFlags = CONTEXT_FULL; DbiGetThreadContext(pUnmanagedThread->m_handle, &tempDebugContext); - CordbUnmanagedThread::LogContext(&tempDebugContext); #if defined(TARGET_X86) || defined(TARGET_AMD64) const ULONG_PTR breakpointOpcodeSize = 1; #elif defined(TARGET_ARM64) diff --git a/src/coreclr/debug/di/rspriv.h b/src/coreclr/debug/di/rspriv.h index 614de00725cb4b..bcf4a18b431846 100644 --- a/src/coreclr/debug/di/rspriv.h +++ b/src/coreclr/debug/di/rspriv.h @@ -10509,9 +10509,6 @@ class CordbUnmanagedThread : public CordbBase HRESULT RestoreLeafSeh(); #endif - // Logs basic data about a context to the debugging log - static VOID LogContext(T_CONTEXT* pContext); - public: HANDLE m_handle; diff --git a/src/coreclr/debug/di/rsregsetcommon.cpp b/src/coreclr/debug/di/rsregsetcommon.cpp index d779f07c5ba3af..82835e6c7bb10d 100644 --- a/src/coreclr/debug/di/rsregsetcommon.cpp +++ b/src/coreclr/debug/di/rsregsetcommon.cpp @@ -163,7 +163,11 @@ HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) // Overlay this frame's registers from the cached CONTEXT buffer, honoring the destination's // ContextFlags (the leaf's if copied above, otherwise the caller's incoming flags). ContextBuffer destinationContext = { context, contextSize }; - IfFailThrow(pDAC->CopyContext(destinationContext, m_contextBuffer, 0)); + IfFailThrow(pDAC->CopyContext( + destinationContext, + m_contextBuffer, + IDacDbiInterface::kCopyContextPreserveDestinationFlags, + 0)); } EX_CATCH_HRESULT(hr); return hr; diff --git a/src/coreclr/debug/di/rsstackwalk.cpp b/src/coreclr/debug/di/rsstackwalk.cpp index e23c57f0d7b30e..ad50faf8379435 100644 --- a/src/coreclr/debug/di/rsstackwalk.cpp +++ b/src/coreclr/debug/di/rsstackwalk.cpp @@ -264,8 +264,13 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } + DT_CONTEXT * pContext = reinterpret_cast(pbContextBuf); + + // Some helper functions that examine the context expect the flags to be initialized. + pContext->ContextFlags = contextFlags; + // check the size of the incoming buffer - if (contextBufSize < ContextSizeForFlags(contextFlags)) + if (!CheckContextSizeForBuffer(contextBufSize, pbContextBuf)) { ThrowWin32(ERROR_INSUFFICIENT_BUFFER); } @@ -293,7 +298,11 @@ HRESULT CordbStackWalk::GetContext(ULONG32 contextFlags, // Stamp the requested contextFlags on the destination so the copy // pulls exactly those chunks from the source. ContextBuffer destinationContext = { pbContextBuf, contextBufSize }; - IfFailThrow(pDAC->CopyContext(destinationContext, GetContextBuffer(), contextFlags)); + IfFailThrow(pDAC->CopyContext( + destinationContext, + GetContextBuffer(), + IDacDbiInterface::kCopyContextUseExplicitFlags, + contextFlags)); } } } @@ -351,10 +360,13 @@ void CordbStackWalk::SetContextWorker(CorDebugSetContextFlag flag, ULONG32 conte ULONG32 cbCtx = GetProcess()->GetTargetContextSize(); NewArrayHolder tmpCtx(new BYTE[cbCtx]); memcpy(tmpCtx, m_pContextBuffer, cbCtx); - // flags == 0: tmpCtx already carries the desired ContextFlags (copied above). ContextBuffer temporaryContext = { tmpCtx, cbCtx }; ContextBuffer sourceContext = { context, contextSize }; - IfFailThrow(pDAC->CopyContext(temporaryContext, sourceContext, 0)); + IfFailThrow(pDAC->CopyContext( + temporaryContext, + sourceContext, + IDacDbiInterface::kCopyContextMergeSourceFlags, + 0)); IfFailThrow(pDAC->CheckContext(m_pCordbThread->m_vmThreadToken, temporaryContext)); memcpy(m_pContextBuffer, tmpCtx, cbCtx); diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index e2dbf43ebbac94..108aaa79d03126 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -1592,8 +1592,11 @@ HRESULT CordbThread::SetManagedContext(ContextBuffer contextBuffer) hr = GetProcess()->SafeReadThreadContext(m_vmLeftSideContext, temporaryContext); IfFailThrow(hr); - // flags == 0: tempContext already carries the target's ContextFlags (read above). - IfFailThrow(GetProcess()->GetDAC()->CopyContext(temporaryContext, contextBuffer, 0)); + IfFailThrow(GetProcess()->GetDAC()->CopyContext( + temporaryContext, + contextBuffer, + IDacDbiInterface::kCopyContextPreserveDestinationFlags, + 0)); hr = GetProcess()->SafeWriteThreadContext(m_vmLeftSideContext, temporaryContext); IfFailThrow(hr); @@ -3221,7 +3224,6 @@ HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) "HijackedForSync=%d RaiseExceptionHijacked=%d.\n", IsContextSet(), IsGenericHijacked(), IsBlockingForSync(), IsRaiseExceptionHijacked())); LOG((LF_CORDB, LL_INFO10000, "CUT::GTC: hijackCtx is:\n")); - LogContext(GetHijackCtx()); CORDbgCopyThreadContext(reinterpret_cast(pContext), sizeof(T_CONTEXT), reinterpret_cast(GetHijackCtx()), sizeof(T_CONTEXT)); } @@ -3256,7 +3258,6 @@ HRESULT CordbUnmanagedThread::GetThreadContext(T_CONTEXT* pContext) { UnsetSSFlag(pContext); } - LogContext(pContext); return hr; } @@ -3271,8 +3272,6 @@ HRESULT CordbUnmanagedThread::SetThreadContext(T_CONTEXT* pContext) LOG((LF_CORDB, LL_INFO10000, "CUT::STC: thread=0x%p, flags=0x%x.\n", this, pContext->ContextFlags)); - LogContext(pContext); - // If the thread is first chance hijacked, then write the context into the remote process. If the thread is generic // hijacked, then update the copy of the context that we already have. Otherwise call the normal Win32 function. @@ -3369,32 +3368,6 @@ VOID CordbUnmanagedThread::EndStepping() _ASSERTE(succ); } - -// Writes some details of the given context into the debugger log -VOID CordbUnmanagedThread::LogContext(T_CONTEXT* pContext) -{ -#if defined(TARGET_X86) - LOG((LF_CORDB, LL_INFO10000, - "CUT::LC: Eip=0x%08x, Esp=0x%08x, Eflags=0x%08x\n", pContext->Eip, pContext->Esp, - pContext->EFlags)); -#elif defined(TARGET_AMD64) - LOG((LF_CORDB, LL_INFO10000, - "CUT::LC: Rip=" FMT_ADDR ", Rsp=" FMT_ADDR ", Eflags=0x%08x\n", - DBG_ADDR(pContext->Rip), - DBG_ADDR(pContext->Rsp), - pContext->EFlags)); // EFlags is still 32bits on AMD64 -#elif defined(TARGET_ARM64) - LOG((LF_CORDB, LL_INFO10000, - "CUT::LC: Pc=" FMT_ADDR ", Sp=" FMT_ADDR ", Lr=" FMT_ADDR ", Cpsr=" FMT_ADDR "\n", - DBG_ADDR(pContext->Pc), - DBG_ADDR(pContext->Sp), - DBG_ADDR(pContext->Lr), - DBG_ADDR(pContext->Cpsr))); -#else // TARGET_X86 - PORTABILITY_ASSERT("LogContext needs a PC and stack pointer."); -#endif // TARGET_X86 -} - // Hijacks this thread using the FirstChanceSuspend hijack HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() { @@ -3425,7 +3398,6 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() // snapshot the current context so we can start spoofing it LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: hijackCtx started as:\n")); - LogContext(GetHijackCtx()); // Save the thread's full context + CONTEXT_EXTENDED_REGISTERS // to avoid getting incomplete information and corrupt the thread context @@ -3451,7 +3423,6 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync() CORDbgCopyThreadContext(reinterpret_cast(GetHijackCtx()), sizeof(T_CONTEXT), reinterpret_cast(&context), sizeof(context)); LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Hijacking for sync. Original context is:\n", this)); - LogContext(GetHijackCtx()); // We're hijacking now... SetState(CUTS_FirstChanceHijacked); diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index 2a128737ef2b13..397b99f592cbac 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -2246,13 +2246,20 @@ IDacDbiInterface : public IUnknown IN ContextBuffer contextBuffer2, OUT BOOL * pResult) = 0; - // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both - // contexts. flags != 0 first stamps dstCtxBuf->ContextFlags = flags so the - // copy pulls exactly the requested chunks from the source; flags == 0 - // preserves the destination's existing ContextFlags. + typedef enum + { + kCopyContextPreserveDestinationFlags = 0, + kCopyContextMergeSourceFlags, + kCopyContextUseExplicitFlags, + } ContextCopyMode; + + // Copies sourceContext into destinationContext, respecting the ContextFlags + // selected by copyMode. flags supplies the destination ContextFlags when + // copyMode is kCopyContextUseExplicitFlags. virtual HRESULT STDMETHODCALLTYPE CopyContext( IN ContextBuffer destinationContext, IN ContextBuffer sourceContext, + IN ContextCopyMode copyMode, IN ULONG32 flags) = 0; // The following tag tells the DD-marshalling tool to stop scanning. diff --git a/src/coreclr/inc/dacdbi.idl b/src/coreclr/inc/dacdbi.idl index aa1c651fd31bee..5b256da9b5e8fa 100644 --- a/src/coreclr/inc/dacdbi.idl +++ b/src/coreclr/inc/dacdbi.idl @@ -97,6 +97,7 @@ typedef int DynamicMethodType; typedef int FrameType; typedef int EHijackReason; typedef int CLR_DEBUGGING_PROCESS_FLAGS; +typedef int ContextCopyMode; // Size type typedef unsigned int SIZE_T; @@ -478,9 +479,12 @@ interface IDacDbiInterface : IUnknown HRESULT CompareControlRegisters([in] ContextBuffer contextBuffer1, [in] ContextBuffer contextBuffer2, [out] BOOL * pResult); - // Copies srcCtxBuf into dstCtxBuf, respecting the ContextFlags of both - // contexts. flags != 0 first stamps dstCtxBuf's ContextFlags so the copy - // pulls exactly the requested chunks from the source; flags == 0 preserves - // the destination's existing ContextFlags. - HRESULT CopyContext([in] ContextBuffer destinationContext, [in] ContextBuffer sourceContext, [in] ULONG32 flags); + // Copies sourceContext into destinationContext, respecting the ContextFlags + // selected by copyMode. flags supplies the destination ContextFlags when + // copyMode requests explicit flags. + HRESULT CopyContext( + [in] ContextBuffer destinationContext, + [in] ContextBuffer sourceContext, + [in] ContextCopyMode copyMode, + [in] ULONG32 flags); }; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 18ff3d72018c41..03afcabbc81763 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -5894,7 +5894,7 @@ public int CompareControlRegisters(ContextBuffer contextBuffer1, ContextBuffer c return hr; } - public int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags) + public int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, ContextCopyMode copyMode, uint flags) { int hr = HResults.S_OK; IPlatformAgnosticContext ctx = IPlatformAgnosticContext.GetContextForPlatform(_target); @@ -5921,10 +5921,22 @@ public int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceCon IPlatformAgnosticContext srcCtx = IPlatformAgnosticContext.GetContextForPlatform(_target); srcCtx.FillFromBuffer(src); - // flags != 0 stamps the destination's ContextFlags so the copy pulls exactly the - // requested groups from the source; flags == 0 preserves the destination's flags. - if (flags != 0) - dstCtx.RawContextFlags = flags; + if (copyMode != ContextCopyMode.UseExplicitFlags && flags != 0) + throw new ArgumentException("Flags are only valid when explicit context flags are requested.", nameof(flags)); + + switch (copyMode) + { + case ContextCopyMode.PreserveDestinationFlags: + break; + case ContextCopyMode.MergeSourceFlags: + dstCtx.RawContextFlags |= srcCtx.RawContextFlags; + break; + case ContextCopyMode.UseExplicitFlags: + dstCtx.RawContextFlags = flags; + break; + default: + throw new ArgumentException("Invalid context copy mode.", nameof(copyMode)); + } uint dstFlags = dstCtx.RawContextFlags; uint srcFlags = srcCtx.RawContextFlags; @@ -5961,7 +5973,7 @@ public int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceCon { ContextBuffer scratchDestination = new() { pContextBytes = pScratchDst, contextSize = ctx.Size }; ContextBuffer scratchSource = new() { pContextBytes = pScratchSrc, contextSize = ctx.Size }; - int hrLocal = _legacy.CopyContext(scratchDestination, scratchSource, flags); + int hrLocal = _legacy.CopyContext(scratchDestination, scratchSource, copyMode, flags); Debug.ValidateHResult(hr, hrLocal); if (hr == HResults.S_OK) Debug.Assert(new ReadOnlySpan(destinationContext.pContextBytes, (int)ctx.Size).SequenceEqual(scratchDst.AsSpan(0, (int)ctx.Size)), diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 9150db45f7f76d..eb175946717dff 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -1077,5 +1077,12 @@ int EnumerateAsyncLocals(ulong vmMethod, ulong codeAddr, uint state, int CompareControlRegisters(ContextBuffer contextBuffer1, ContextBuffer contextBuffer2, Interop.BOOL* pResult); [PreserveSig] - int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, uint flags); + int CopyContext(ContextBuffer destinationContext, ContextBuffer sourceContext, ContextCopyMode copyMode, uint flags); +} + +public enum ContextCopyMode +{ + PreserveDestinationFlags = 0, + MergeSourceFlags, + UseExplicitFlags, } diff --git a/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs b/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs index 0e078bf6d03a33..58a7f95b2094db 100644 --- a/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs +++ b/src/native/managed/cdac/tests/UnitTests/DacDbiImplTests.cs @@ -847,6 +847,90 @@ public static IEnumerable TargetArchitectures_SpRange() } } + [Theory] + [MemberData(nameof(TargetArchitectures))] + public void CopyContext_CopyModeControlsContextFlags(MockTarget.Architecture arch, string targetArch) + { + var target = new TestPlaceholderTarget.Builder(arch) + .AddGlobalStrings((Constants.Globals.Architecture, targetArch)) + .AddContract(version: "c1") + .Build(); + DacDbiImpl dacDbi = new(target, legacyObj: null); + + IPlatformAgnosticContext destinationContext = IPlatformAgnosticContext.GetContextForPlatform(target); + IPlatformAgnosticContext sourceContext = IPlatformAgnosticContext.GetContextForPlatform(target); + destinationContext.RawContextFlags = destinationContext.ContextControlFlags; + sourceContext.RawContextFlags = sourceContext.FullContextFlags; + + string? sourceOnlyRegister = null; + foreach ((uint flag, string name) in sourceContext.GetScalarRegisters()) + { + if ((sourceContext.FullContextFlags & flag) == flag && + (destinationContext.ContextControlFlags & flag) != flag) + { + sourceOnlyRegister = name; + break; + } + } + + Assert.NotNull(sourceOnlyRegister); + TargetNUInt expectedValue = new(0x1234); + Assert.True(sourceContext.TrySetRegister(sourceOnlyRegister, expectedValue)); + + byte[] destinationBytes = destinationContext.GetBytes(); + byte[] sourceBytes = sourceContext.GetBytes(); + fixed (byte* pDestination = destinationBytes) + fixed (byte* pSource = sourceBytes) + { + ContextBuffer destinationBuffer = new() { pContextBytes = pDestination, contextSize = (uint)destinationBytes.Length }; + ContextBuffer sourceBuffer = new() { pContextBytes = pSource, contextSize = (uint)sourceBytes.Length }; + int hr = dacDbi.CopyContext(destinationBuffer, sourceBuffer, ContextCopyMode.PreserveDestinationFlags, flags: 0); + Assert.Equal(System.HResults.S_OK, hr); + } + + destinationContext.FillFromBuffer(destinationBytes); + Assert.Equal(destinationContext.ContextControlFlags, destinationContext.RawContextFlags); + Assert.True(destinationContext.TryReadRegister(sourceOnlyRegister, out TargetNUInt preservedValue)); + Assert.NotEqual(expectedValue, preservedValue); + + fixed (byte* pDestination = destinationBytes) + fixed (byte* pSource = sourceBytes) + { + ContextBuffer destinationBuffer = new() { pContextBytes = pDestination, contextSize = (uint)destinationBytes.Length }; + ContextBuffer sourceBuffer = new() { pContextBytes = pSource, contextSize = (uint)sourceBytes.Length }; + int hr = dacDbi.CopyContext(destinationBuffer, sourceBuffer, ContextCopyMode.MergeSourceFlags, flags: 0); + Assert.Equal(System.HResults.S_OK, hr); + } + + destinationContext.FillFromBuffer(destinationBytes); + Assert.Equal(sourceContext.FullContextFlags, destinationContext.RawContextFlags); + Assert.True(destinationContext.TryReadRegister(sourceOnlyRegister, out TargetNUInt actualValue)); + Assert.Equal(expectedValue, actualValue); + + TargetNUInt destinationValue = new(0x5678); + destinationContext.RawContextFlags = destinationContext.FullContextFlags; + Assert.True(destinationContext.TrySetRegister(sourceOnlyRegister, destinationValue)); + destinationBytes = destinationContext.GetBytes(); + + fixed (byte* pDestination = destinationBytes) + fixed (byte* pSource = sourceBytes) + { + ContextBuffer destinationBuffer = new() { pContextBytes = pDestination, contextSize = (uint)destinationBytes.Length }; + ContextBuffer sourceBuffer = new() { pContextBytes = pSource, contextSize = (uint)sourceBytes.Length }; + int hr = dacDbi.CopyContext( + destinationBuffer, + sourceBuffer, + ContextCopyMode.UseExplicitFlags, + flags: 0); + Assert.Equal(System.HResults.S_OK, hr); + } + + destinationContext.FillFromBuffer(destinationBytes); + Assert.Equal(0u, destinationContext.RawContextFlags); + Assert.True(destinationContext.TryReadRegister(sourceOnlyRegister, out actualValue)); + Assert.Equal(destinationValue, actualValue); + } + [Theory] [MemberData(nameof(TargetArchitectures_SpRange))] public void CheckContext_WithControlFlag_ValidatesSpRange(MockTarget.Architecture arch, string targetArch, ulong sp, int expectedHr) From 945bb4b9667615c890dfcce01d3bd3aba19c4602 Mon Sep 17 00:00:00 2001 From: Rachel Jarvi Date: Fri, 24 Jul 2026 15:03:41 -0700 Subject: [PATCH 26/26] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Contracts/StackWalk/Context/WasmContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs index 209f11a502d670..1b4ed25fadf091 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/Context/WasmContext.cs @@ -168,6 +168,6 @@ public readonly bool TryReadFloatingPointRegister(ReadOnlySpan context, in public readonly bool TryWriteFloatingPointRegister(Span context, int index, ReadOnlySpan value) => false; - public readonly (uint Flag, string Name)[] GetScalarRegisters() => []; - public readonly (uint Flag, int Start, int End)[] GetWideSpans() => []; + public readonly (uint Flag, string Name)[] GetScalarRegisters() => Array.Empty<(uint Flag, string Name)>(); + public readonly (uint Flag, int Start, int End)[] GetWideSpans() => Array.Empty<(uint Flag, int Start, int End)>(); }