Skip to content

Commit 49af07c

Browse files
tommcdonMike McLaughlin
andauthored
Fix x64 macOS and Linux managed debugging (#84655)
* Limit context size in DAC stackwalker * Constrain debugger x64 context size check to Linux and macOS * Exclude DAC and DBI cross-os compilation with context adjustment * Fix non-x64 builds --------- Co-authored-by: Mike McLaughlin <[email protected]>
1 parent a2c095e commit 49af07c

File tree

9 files changed

+64
-21
lines changed

9 files changed

+64
-21
lines changed

src/coreclr/debug/createdump/datatarget.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
#include "createdump.h"
5+
#include <dbgtargetcontext.h>
56

67
#if defined(HOST_ARM64)
78
// Flag to check if atomics feature is available on
@@ -181,7 +182,7 @@ DumpDataTarget::GetThreadContext(
181182
/* [in] */ ULONG32 contextSize,
182183
/* [out, size_is(contextSize)] */ PBYTE context)
183184
{
184-
if (contextSize < sizeof(CONTEXT))
185+
if (contextSize < sizeof(DT_CONTEXT))
185186
{
186187
assert(false);
187188
return E_INVALIDARG;

src/coreclr/debug/daccess/daccess.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7896,7 +7896,7 @@ void DacStackReferenceWalker::WalkStack()
78967896
// Get the current thread's context and set that as the filter context
78977897
if (mThread->GetFilterContext() == NULL && mThread->GetProfilerFilterContext() == NULL)
78987898
{
7899-
mDac->m_pTarget->GetThreadContext(mThread->GetOSThreadId(), CONTEXT_FULL, sizeof(ctx), (BYTE*)&ctx);
7899+
mDac->m_pTarget->GetThreadContext(mThread->GetOSThreadId(), CONTEXT_FULL, sizeof(DT_CONTEXT), (BYTE*)&ctx);
79007900
mThread->SetProfilerFilterContext(&ctx);
79017901
contextHolder.Activate(mThread);
79027902
}

src/coreclr/debug/daccess/dacdbiimpl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5199,7 +5199,7 @@ void DacDbiInterfaceImpl::Hijack(
51995199
HRESULT hr = m_pTarget->GetThreadContext(
52005200
dwThreadId,
52015201
CONTEXT_FULL,
5202-
sizeof(ctx),
5202+
sizeof(DT_CONTEXT),
52035203
(BYTE*) &ctx);
52045204
IfFailThrow(hr);
52055205

@@ -5346,7 +5346,7 @@ void DacDbiInterfaceImpl::Hijack(
53465346
//
53475347
// Commit the context.
53485348
//
5349-
hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(ctx), reinterpret_cast<BYTE*> (&ctx));
5349+
hr = m_pMutableTarget->SetThreadContext(dwThreadId, sizeof(DT_CONTEXT), reinterpret_cast<BYTE*> (&ctx));
53505350
IfFailThrow(hr);
53515351
}
53525352

@@ -5717,7 +5717,7 @@ void DacDbiInterfaceImpl::GetContext(VMPTR_Thread vmThread, DT_CONTEXT * pContex
57175717
pContextBuffer->ContextFlags = DT_CONTEXT_ALL;
57185718
HRESULT hr = m_pTarget->GetThreadContext(pThread->GetOSThreadId(),
57195719
pContextBuffer->ContextFlags,
5720-
sizeof(*pContextBuffer),
5720+
sizeof(DT_CONTEXT),
57215721
reinterpret_cast<BYTE *>(pContextBuffer));
57225722
if (hr == E_NOTIMPL)
57235723
{

src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,14 @@ void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackWalkHandle pSFIHandle,
153153
void DacDbiInterfaceImpl::GetStackWalkCurrentContext(StackFrameIterator * pIter,
154154
DT_CONTEXT * pContext)
155155
{
156-
// convert the current REGDISPLAY to a CONTEXT
156+
// convert the current REGDISPLAY to a DT_CONTEXT
157157
CrawlFrame * pCF = &(pIter->m_crawl);
158-
UpdateContextFromRegDisp(pCF->GetRegisterSet(), reinterpret_cast<T_CONTEXT *>(pContext));
158+
T_CONTEXT tmpContext = { };
159+
UpdateContextFromRegDisp(pCF->GetRegisterSet(), &tmpContext);
160+
CopyMemory(pContext, &tmpContext, sizeof(*pContext));
161+
#if defined(TARGET_X86) || defined(TARGET_AMD64)
162+
pContext->ContextFlags &= ~(CONTEXT_XSTATE & CONTEXT_AREA_MASK);
163+
#endif
159164
}
160165

161166

@@ -180,7 +185,7 @@ void DacDbiInterfaceImpl::SetStackWalkCurrentContext(VMPTR_Thread vmTh
180185
// Allocate a context in DDImpl's memory space. DDImpl can't contain raw pointers back into
181186
// the client space since that may not marshal.
182187
T_CONTEXT * pContext2 = GetContextBufferFromHandle(pSFIHandle);
183-
*pContext2 = *reinterpret_cast<T_CONTEXT *>(pContext); // memcpy
188+
CopyMemory(pContext2, pContext, sizeof(*pContext));
184189

185190
// update the REGDISPLAY with the given CONTEXT.
186191
// 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 *
657662

658663
// This is a bit cumbersome. First we need to convert the CONTEXT into a REGDISPLAY. Then we need
659664
// to convert the REGDISPLAY to a DebuggerREGDISPLAY.
665+
T_CONTEXT tmpContext = { };
666+
CopyMemory(&tmpContext, pInContext, sizeof(*pInContext));
667+
660668
REGDISPLAY rd;
661-
FillRegDisplay(&rd, reinterpret_cast<T_CONTEXT *>(const_cast<DT_CONTEXT *>(pInContext)));
669+
FillRegDisplay(&rd, &tmpContext);
670+
662671
SetDebuggerREGDISPLAYFromREGDISPLAY(pOutDRD, &rd);
663672
}
664673

src/coreclr/debug/daccess/reimpl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ DacGetThreadContext(Thread* thread, T_CONTEXT* context)
107107
HRESULT status =
108108
g_dacImpl->m_pTarget->
109109
GetThreadContext(thread->GetOSThreadId(), contextFlags,
110-
sizeof(*context), (PBYTE)context);
110+
sizeof(DT_CONTEXT), (PBYTE)context);
111111
if (status != S_OK)
112112
{
113113
DacError(status);

src/coreclr/debug/daccess/stack.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ ClrDataStackWalk::GetContext(
104104
}
105105
else
106106
{
107-
*(PT_CONTEXT)contextBuf = m_context;
108-
UpdateContextFromRegDisp(&m_regDisp, (PT_CONTEXT)contextBuf);
107+
T_CONTEXT tmpContext = m_context;
108+
UpdateContextFromRegDisp(&m_regDisp, &tmpContext);
109+
CopyMemory(contextBuf, &tmpContext, contextBufSize);
109110
status = S_OK;
110111
}
111112
}
@@ -154,7 +155,7 @@ ClrDataStackWalk::SetContext2(
154155
{
155156
// Copy the context to local state so
156157
// that its lifetime extends beyond this call.
157-
m_context = *(PT_CONTEXT)context;
158+
CopyMemory(&m_context, context, contextSize);
158159
m_thread->FillRegDisplay(&m_regDisp, &m_context);
159160
m_frameIter.ResetRegDisp(&m_regDisp, (flags & CLRDATA_STACK_SET_CURRENT_CONTEXT) != 0);
160161
m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
@@ -660,7 +661,7 @@ ClrDataFrame::GetContext(
660661

661662
EX_TRY
662663
{
663-
*(PT_CONTEXT)contextBuf = m_context;
664+
CopyMemory(contextBuf, &m_context, contextBufSize);
664665
status = S_OK;
665666
}
666667
EX_CATCH

src/coreclr/debug/di/process.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6438,7 +6438,7 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE
64386438

64396439
DT_CONTEXT * pContext;
64406440

6441-
if (contextSize != sizeof(DT_CONTEXT))
6441+
if (contextSize < sizeof(DT_CONTEXT))
64426442
{
64436443
LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, context size is invalid.\n", threadID));
64446444
return E_INVALIDARG;
@@ -11179,10 +11179,10 @@ void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
1117911179
ThrowHR(HRESULT_FROM_GetLastError());
1118011180
}
1118111181

11182-
CONTEXT context = { 0 };
11182+
DT_CONTEXT context = { 0 };
1118311183
context.ContextFlags = CONTEXT_FULL;
1118411184

11185-
HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(CONTEXT), reinterpret_cast<BYTE*> (&context));
11185+
HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(DT_CONTEXT), reinterpret_cast<BYTE*> (&context));
1118611186
IfFailThrow(hr);
1118711187

1118811188
TADDR lsContextAddr = (TADDR)context.Rcx;

src/coreclr/debug/inc/common.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,15 @@ ULONG32 ContextSizeForFlags(ULONG32 flags)
9696
else
9797
#endif // TARGET_X86
9898
{
99+
#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
100+
if ((flags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
101+
{
102+
return sizeof(T_CONTEXT);
103+
}
104+
return offsetof(T_CONTEXT, XStateFeaturesMask);
105+
#else
99106
return sizeof(T_CONTEXT);
107+
#endif
100108
}
101109
}
102110

src/coreclr/debug/inc/dbgtargetcontext.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@
2525
// ByteSwapContext.
2626
//
2727

28-
//
29-
// **** NOTE: Keep these in sync with pal/inc/pal.h ****
30-
//
28+
// ****
29+
// **** NOTE: T_CONTEXT (in pal/inc/pal.h) can now be larger than DT_CONTEXT (currently T_CONTEXT on Linux/MacOS
30+
// **** x64 includes the XSTATE registers). This means the following:
31+
// ****
32+
// **** 1) The DBI/DAC APIs cannot assume that incoming context buffers are T_CONTEXT sized.
33+
// **** 2) When the DAC calls the supplied data target's context APIs, the size of the context buffer must
34+
// **** be the size of the DT_CONTEXT for compatiblity.
35+
// **** 3) DBI/DAC code can not cast and copy from a T_CONTEXT into a DT_CONTEXT buffer.
36+
// ****
3137

3238
// This odd define pattern is needed because in DBI we set _TARGET_ to match the host and
3339
// DBG_TARGET to control our targeting. In x-plat DBI DBG_TARGET won't match _TARGET_ and
@@ -54,6 +60,8 @@
5460
#define DTCONTEXT_IS_RISCV64
5561
#endif
5662

63+
#define CONTEXT_AREA_MASK 0xffff
64+
5765
#if defined(DTCONTEXT_IS_X86)
5866

5967
#define DT_SIZE_OF_80387_REGISTERS 80
@@ -118,6 +126,8 @@ typedef struct {
118126

119127
} DT_CONTEXT;
120128

129+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on X86");
130+
121131
// Since the target is little endian in this case we only have to provide a real implementation of
122132
// ByteSwapContext if the platform we're building on is big-endian.
123133
#ifdef BIGENDIAN
@@ -280,6 +290,12 @@ typedef struct DECLSPEC_ALIGN(16) {
280290
DWORD64 LastExceptionFromRip;
281291
} DT_CONTEXT;
282292

293+
#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS)
294+
static_assert(sizeof(DT_CONTEXT) == offsetof(T_CONTEXT, XStateFeaturesMask), "DT_CONTEXT must not include the XSTATE registers on AMD64");
295+
#else
296+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on AMD64");
297+
#endif
298+
283299
#elif defined(DTCONTEXT_IS_ARM)
284300

285301
#define DT_CONTEXT_ARM 0x00200000L
@@ -361,6 +377,8 @@ typedef DECLSPEC_ALIGN(8) struct {
361377

362378
} DT_CONTEXT;
363379

380+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on ARM32");
381+
364382
#elif defined(DTCONTEXT_IS_ARM64)
365383

366384
#define DT_CONTEXT_ARM64 0x00400000L
@@ -452,7 +470,10 @@ typedef DECLSPEC_ALIGN(16) struct {
452470

453471
} DT_CONTEXT;
454472

473+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on ARM64");
474+
455475
#elif defined(DTCONTEXT_IS_LOONGARCH64)
476+
456477
#define DT_CONTEXT_LOONGARCH64 0x00800000L
457478

458479
#define DT_CONTEXT_CONTROL (DT_CONTEXT_LOONGARCH64 | 0x1L)
@@ -516,7 +537,10 @@ typedef DECLSPEC_ALIGN(16) struct {
516537
ULONGLONG F[32];
517538
} DT_CONTEXT;
518539

540+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size");
541+
519542
#elif defined(DTCONTEXT_IS_RISCV64)
543+
520544
#define DT_CONTEXT_RISCV64 0x01000000L
521545

522546
#define DT_CONTEXT_CONTROL (DT_CONTEXT_RISCV64 | 0x1L)
@@ -580,10 +604,10 @@ typedef DECLSPEC_ALIGN(16) struct {
580604
ULONGLONG F[32];
581605
} DT_CONTEXT;
582606

607+
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size");
583608

584609
#else
585610
#error Unsupported platform
586611
#endif
587612

588-
589613
#endif // __DBG_TARGET_CONTEXT_INCLUDED

0 commit comments

Comments
 (0)