diff --git a/src/coreclr/debug/createdump/datatarget.cpp b/src/coreclr/debug/createdump/datatarget.cpp index 0bf0ed23c66c5c..6f6a68ef70eed6 100644 --- a/src/coreclr/debug/createdump/datatarget.cpp +++ b/src/coreclr/debug/createdump/datatarget.cpp @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "createdump.h" +#include #if defined(HOST_ARM64) // Flag to check if atomics feature is available on @@ -181,7 +182,7 @@ DumpDataTarget::GetThreadContext( /* [in] */ ULONG32 contextSize, /* [out, size_is(contextSize)] */ PBYTE context) { - if (contextSize < sizeof(CONTEXT)) + if (contextSize < sizeof(DT_CONTEXT)) { assert(false); return E_INVALIDARG; diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp index aa0c739eeac395..3a0ceb80e6057f 100644 --- a/src/coreclr/debug/daccess/daccess.cpp +++ b/src/coreclr/debug/daccess/daccess.cpp @@ -7896,7 +7896,7 @@ void DacStackReferenceWalker::WalkStack() // Get the current thread's context and set that as the filter context if (mThread->GetFilterContext() == NULL && mThread->GetProfilerFilterContext() == NULL) { - mDac->m_pTarget->GetThreadContext(mThread->GetOSThreadId(), CONTEXT_FULL, sizeof(ctx), (BYTE*)&ctx); + mDac->m_pTarget->GetThreadContext(mThread->GetOSThreadId(), CONTEXT_FULL, sizeof(DT_CONTEXT), (BYTE*)&ctx); mThread->SetProfilerFilterContext(&ctx); contextHolder.Activate(mThread); } diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 2b2a39c1c282df..2d546ece1ccec3 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -5199,7 +5199,7 @@ void DacDbiInterfaceImpl::Hijack( HRESULT hr = m_pTarget->GetThreadContext( dwThreadId, CONTEXT_FULL, - sizeof(ctx), + sizeof(DT_CONTEXT), (BYTE*) &ctx); IfFailThrow(hr); @@ -5346,7 +5346,7 @@ void DacDbiInterfaceImpl::Hijack( // // Commit the context. // - hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(ctx), reinterpret_cast (&ctx)); + hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(DT_CONTEXT), reinterpret_cast (&ctx)); IfFailThrow(hr); } @@ -5717,7 +5717,7 @@ void DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContex pContextBuffer->ContextFlags = DT_CONTEXT_ALL; HRESULT hr = m_pTarget->GetThreadContext(pThread->GetOSThreadId(), pContextBuffer->ContextFlags, - sizeof(*pContextBuffer), + sizeof(DT_CONTEXT), reinterpret_cast(pContextBuffer)); if (hr == E_NOTIMPL) { diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index b56ac6af5bd365..c62233238ad7b1 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -153,9 +153,14 @@ void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle, void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackFrameIterator * pIter, DT_CONTEXT * pContext) { - // convert the current REGDISPLAY to a CONTEXT + // convert the current REGDISPLAY to a DT_CONTEXT CrawlFrame * pCF = &(pIter->m_crawl); - UpdateContextFromRegDisp(pCF->GetRegisterSet(), reinterpret_cast(pContext)); + T_CONTEXT tmpContext = { }; + UpdateContextFromRegDisp(pCF->GetRegisterSet(), &tmpContext); + CopyMemory(pContext, &tmpContext, sizeof(*pContext)); +#if defined(TARGET_X86) || defined(TARGET_AMD64) + pContext->ContextFlags &= ~(CONTEXT_XSTATE & CONTEXT_AREA_MASK); +#endif } @@ -180,7 +185,7 @@ void DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmTh // Allocate a context in DDImpl's memory space. DDImpl can't contain raw pointers back into // the client space since that may not marshal. T_CONTEXT * pContext2 = GetContextBufferFromHandle(pSFIHandle); - *pContext2 = *reinterpret_cast(pContext); // memcpy + CopyMemory(pContext2, pContext, sizeof(*pContext)); // update the REGDISPLAY with the given CONTEXT. // Be sure that the context is in DDImpl's memory space and not the Right-sides. @@ -657,8 +662,12 @@ void DacDbiInterfaceImpl::ConvertContextToDebuggerRegDisplay(const DT_CONTEXT * // This is a bit cumbersome. First we need to convert the CONTEXT into a REGDISPLAY. Then we need // to convert the REGDISPLAY to a DebuggerREGDISPLAY. + T_CONTEXT tmpContext = { }; + CopyMemory(&tmpContext, pInContext, sizeof(*pInContext)); + REGDISPLAY rd; - FillRegDisplay(&rd, reinterpret_cast(const_cast(pInContext))); + FillRegDisplay(&rd, &tmpContext); + SetDebuggerREGDISPLAYFromREGDISPLAY(pOutDRD, &rd); } diff --git a/src/coreclr/debug/daccess/reimpl.cpp b/src/coreclr/debug/daccess/reimpl.cpp index 0c94f50e355227..1935eacce97258 100644 --- a/src/coreclr/debug/daccess/reimpl.cpp +++ b/src/coreclr/debug/daccess/reimpl.cpp @@ -107,7 +107,7 @@ DacGetThreadContext(Thread* thread, T_CONTEXT* context) HRESULT status = g_dacImpl->m_pTarget-> GetThreadContext(thread->GetOSThreadId(), contextFlags, - sizeof(*context), (PBYTE)context); + sizeof(DT_CONTEXT), (PBYTE)context); if (status != S_OK) { DacError(status); diff --git a/src/coreclr/debug/daccess/stack.cpp b/src/coreclr/debug/daccess/stack.cpp index 309cb89657a969..9402d529eb8ea3 100644 --- a/src/coreclr/debug/daccess/stack.cpp +++ b/src/coreclr/debug/daccess/stack.cpp @@ -104,8 +104,9 @@ ClrDataStackWalk::GetContext( } else { - *(PT_CONTEXT)contextBuf = m_context; - UpdateContextFromRegDisp(&m_regDisp, (PT_CONTEXT)contextBuf); + T_CONTEXT tmpContext = m_context; + UpdateContextFromRegDisp(&m_regDisp, &tmpContext); + CopyMemory(contextBuf, &tmpContext, contextBufSize); status = S_OK; } } @@ -154,7 +155,7 @@ ClrDataStackWalk::SetContext2( { // Copy the context to local state so // that its lifetime extends beyond this call. - m_context = *(PT_CONTEXT)context; + CopyMemory(&m_context, context, contextSize); m_thread->FillRegDisplay(&m_regDisp, &m_context); m_frameIter.ResetRegDisp(&m_regDisp, (flags & CLRDATA_STACK_SET_CURRENT_CONTEXT) != 0); m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp); @@ -660,7 +661,7 @@ ClrDataFrame::GetContext( EX_TRY { - *(PT_CONTEXT)contextBuf = m_context; + CopyMemory(contextBuf, &m_context, contextBufSize); status = S_OK; } EX_CATCH diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index eef6850080fa6c..f3be5c2b374e12 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -6438,7 +6438,7 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE DT_CONTEXT * pContext; - if (contextSize != sizeof(DT_CONTEXT)) + if (contextSize < sizeof(DT_CONTEXT)) { LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID)); return E_INVALIDARG; @@ -11179,10 +11179,10 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId) ThrowHR(HRESULT_FROM_GetLastError()); } - CONTEXT context = { 0 }; + DT_CONTEXT context = { 0 }; context.ContextFlags = CONTEXT_FULL; - HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(CONTEXT), reinterpret_cast (&context)); + HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(DT_CONTEXT), reinterpret_cast (&context)); IfFailThrow(hr); TADDR lsContextAddr = (TADDR)context.Rcx; diff --git a/src/coreclr/debug/inc/common.h b/src/coreclr/debug/inc/common.h index 2caabe108ee310..16cfb852896d16 100644 --- a/src/coreclr/debug/inc/common.h +++ b/src/coreclr/debug/inc/common.h @@ -96,7 +96,15 @@ ULONG32 ContextSizeForFlags(ULONG32 flags) else #endif // TARGET_X86 { +#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS) && defined(TARGET_AMD64) + if ((flags & CONTEXT_XSTATE) == CONTEXT_XSTATE) + { + return sizeof(T_CONTEXT); + } + return offsetof(T_CONTEXT, XStateFeaturesMask); +#else return sizeof(T_CONTEXT); +#endif } } diff --git a/src/coreclr/debug/inc/dbgtargetcontext.h b/src/coreclr/debug/inc/dbgtargetcontext.h index dc3b853014dee2..fa6c7b92cb8848 100644 --- a/src/coreclr/debug/inc/dbgtargetcontext.h +++ b/src/coreclr/debug/inc/dbgtargetcontext.h @@ -25,9 +25,15 @@ // ByteSwapContext. // -// -// **** NOTE: Keep these in sync with pal/inc/pal.h **** -// +// **** +// **** NOTE: T_CONTEXT (in pal/inc/pal.h) can now be larger than DT_CONTEXT (currently T_CONTEXT on Linux/MacOS +// **** x64 includes the XSTATE registers). This means the following: +// **** +// **** 1) The DBI/DAC APIs cannot assume that incoming context buffers are T_CONTEXT sized. +// **** 2) When the DAC calls the supplied data target's context APIs, the size of the context buffer must +// **** be the size of the DT_CONTEXT for compatiblity. +// **** 3) DBI/DAC code can not cast and copy from a T_CONTEXT into a DT_CONTEXT buffer. +// **** // This odd define pattern is needed because in DBI we set _TARGET_ to match the host and // DBG_TARGET to control our targeting. In x-plat DBI DBG_TARGET won't match _TARGET_ and @@ -54,6 +60,8 @@ #define DTCONTEXT_IS_RISCV64 #endif +#define CONTEXT_AREA_MASK 0xffff + #if defined(DTCONTEXT_IS_X86) #define DT_SIZE_OF_80387_REGISTERS 80 @@ -118,6 +126,8 @@ typedef struct { } DT_CONTEXT; +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on X86"); + // Since the target is little endian in this case we only have to provide a real implementation of // ByteSwapContext if the platform we're building on is big-endian. #ifdef BIGENDIAN @@ -280,6 +290,12 @@ typedef struct DECLSPEC_ALIGN(16) { DWORD64 LastExceptionFromRip; } DT_CONTEXT; +#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS) +static_assert(sizeof(DT_CONTEXT) == offsetof(T_CONTEXT, XStateFeaturesMask), "DT_CONTEXT must not include the XSTATE registers on AMD64"); +#else +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on AMD64"); +#endif + #elif defined(DTCONTEXT_IS_ARM) #define DT_CONTEXT_ARM 0x00200000L @@ -361,6 +377,8 @@ typedef DECLSPEC_ALIGN(8) struct { } DT_CONTEXT; +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on ARM32"); + #elif defined(DTCONTEXT_IS_ARM64) #define DT_CONTEXT_ARM64 0x00400000L @@ -452,7 +470,10 @@ typedef DECLSPEC_ALIGN(16) struct { } DT_CONTEXT; +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on ARM64"); + #elif defined(DTCONTEXT_IS_LOONGARCH64) + #define DT_CONTEXT_LOONGARCH64 0x00800000L #define DT_CONTEXT_CONTROL (DT_CONTEXT_LOONGARCH64 | 0x1L) @@ -516,7 +537,10 @@ typedef DECLSPEC_ALIGN(16) struct { ULONGLONG F[32]; } DT_CONTEXT; +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size"); + #elif defined(DTCONTEXT_IS_RISCV64) + #define DT_CONTEXT_RISCV64 0x01000000L #define DT_CONTEXT_CONTROL (DT_CONTEXT_RISCV64 | 0x1L) @@ -580,10 +604,10 @@ typedef DECLSPEC_ALIGN(16) struct { ULONGLONG F[32]; } DT_CONTEXT; +static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size"); #else #error Unsupported platform #endif - #endif // __DBG_TARGET_CONTEXT_INCLUDED