Skip to content

Commit a3fb0d3

Browse files
authored
Support managed debugging when CET is enabled (#73572)
* Support managed debugging when CET is enabled * Use DataTarget ReadVirtual function to read data Remove RS GetLiveContext/SetLiveContext implementations Update debugger contract * Clean up contracts and add extra validation in SetThreadContextNeeded message * Add OUT_OF_PROCESS_SETTHREADCONTEXT ifdef * Add todo comment to merge ICorDebugMutableDataTarget::SetThreadContext with HandleSetThreadContextNeeded implementation
1 parent 66165e6 commit a3fb0d3

File tree

11 files changed

+355
-25
lines changed

11 files changed

+355
-25
lines changed

src/coreclr/clrdefinitions.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET
6262
endif(CLR_CMAKE_TARGET_WIN32)
6363
endif(CLR_CMAKE_TARGET_ARCH_AMD64 OR CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM64)
6464

65+
if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64)
66+
add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT)
67+
endif(CLR_CMAKE_TARGET_WIN32)
68+
6569
# Features - please keep them alphabetically sorted
6670
if(CLR_CMAKE_TARGET_WIN32)
6771
if(NOT CLR_CMAKE_TARGET_ARCH_I386)

src/coreclr/debug/di/process.cpp

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7661,6 +7661,8 @@ HRESULT CordbProcess::GetRuntimeOffsets()
76617661
m_runtimeOffsets.m_debuggerWordTLSIndex));
76627662
#endif // FEATURE_INTEROP_DEBUGGING
76637663

7664+
LOG((LF_CORDB, LL_INFO10000, " m_setThreadContextNeededAddr= 0x%p\n",
7665+
m_runtimeOffsets.m_setThreadContextNeededAddr));
76647666
LOG((LF_CORDB, LL_INFO10000, " m_TLSIndex= 0x%08x\n",
76657667
m_runtimeOffsets.m_TLSIndex));
76667668
LOG((LF_CORDB, LL_INFO10000, " m_EEThreadStateOffset= 0x%08x\n",
@@ -7719,6 +7721,7 @@ HRESULT CordbProcess::GetRuntimeOffsets()
77197721
m_runtimeOffsets.m_signalHijackCompleteBPAddr,
77207722
m_runtimeOffsets.m_excepNotForRuntimeBPAddr,
77217723
m_runtimeOffsets.m_notifyRSOfSyncCompleteBPAddr,
7724+
m_runtimeOffsets.m_setThreadContextNeededAddr,
77227725
};
77237726

77247727
const int NumFlares = ARRAY_SIZE(flares);
@@ -11152,7 +11155,162 @@ void CordbProcess::FilterClrNotification(
1115211155
}
1115311156
}
1115411157

11158+
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
11159+
void CordbProcess::HandleSetThreadContextNeeded(DWORD dwThreadId)
11160+
{
11161+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded\n"));
11162+
11163+
#if defined(TARGET_WINDOWS) && defined(TARGET_AMD64)
11164+
HandleHolder hThread = OpenThread(
11165+
THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME,
11166+
FALSE, // thread handle is not inheritable.
11167+
dwThreadId);
11168+
11169+
if (hThread == NULL)
11170+
{
11171+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from OpenThread\n"));
11172+
ThrowHR(E_UNEXPECTED);
11173+
}
11174+
11175+
DWORD previousSuspendCount = ::SuspendThread(hThread);
11176+
if (previousSuspendCount == (DWORD)-1)
11177+
{
11178+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from SuspendThread\n"));
11179+
ThrowHR(HRESULT_FROM_GetLastError());
11180+
}
11181+
11182+
CONTEXT context = { 0 };
11183+
context.ContextFlags = CONTEXT_FULL;
11184+
11185+
HRESULT hr = GetDataTarget()->GetThreadContext(dwThreadId, CONTEXT_FULL, sizeof(CONTEXT), reinterpret_cast<BYTE*> (&context));
11186+
IfFailThrow(hr);
11187+
11188+
TADDR lsContextAddr = (TADDR)context.Rcx;
11189+
DWORD contextSize = (DWORD)context.Rdx;
11190+
11191+
TADDR expectedRip = (TADDR)context.R8;
11192+
TADDR expectedRsp = (TADDR)context.R9;
11193+
11194+
if (contextSize == 0 || contextSize > sizeof(CONTEXT) + 25000)
11195+
{
11196+
_ASSERTE(!"Corrupted HandleSetThreadContextNeeded message received");
11197+
11198+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Corrupted HandleSetThreadContextNeeded message received\n"));
11199+
11200+
ThrowHR(E_UNEXPECTED);
11201+
}
11202+
11203+
PCONTEXT pContext = (PCONTEXT)_alloca(contextSize);
11204+
ULONG32 cbRead;
11205+
hr = GetDataTarget()->ReadVirtual(lsContextAddr, reinterpret_cast<BYTE*>(pContext), contextSize, &cbRead);
11206+
if (FAILED(hr))
11207+
{
11208+
_ASSERTE(!"ReadVirtual failed");
11209+
11210+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - ReadVirtual (error: 0x%X).\n", hr));
11211+
11212+
ThrowHR(CORDBG_E_READVIRTUAL_FAILURE);
11213+
}
11214+
11215+
if (cbRead != contextSize)
11216+
{
11217+
_ASSERTE(!"ReadVirtual context size mismatch");
1115511218

11219+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - ReadVirtual context size mismatch\n"));
11220+
11221+
ThrowHR(ERROR_PARTIAL_COPY);
11222+
}
11223+
11224+
if (pContext->Rip != expectedRip || pContext->Rsp != expectedRsp)
11225+
{
11226+
_ASSERTE(!"ReadVirtual unexpectedly returned mismatched Rip and Rsp registers");
11227+
11228+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - ReadVirtual unexpectedly returned mismatched Rip and Rsp registers\n"));
11229+
11230+
ThrowHR(E_UNEXPECTED);
11231+
}
11232+
11233+
// TODO: Ideally we would use ICorDebugMutableDataTarget::SetThreadContext however this API currently only handles the legacy context.
11234+
// We should combine the following code with the shared implementation
11235+
11236+
// The initialize call should fail but return contextSize
11237+
contextSize = 0;
11238+
DWORD contextFlags = pContext->ContextFlags;
11239+
BOOL success = InitializeContext(NULL, contextFlags, NULL, &contextSize);
11240+
11241+
if(success || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
11242+
{
11243+
_ASSERTE(!"InitializeContext unexpectedly succeeded or didn't return ERROR_INSUFFICIENT_BUFFER");
11244+
11245+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - InitializeContext unexpectedly succeeded or didn't return ERROR_INSUFFICIENT_BUFFER\n"));
11246+
11247+
ThrowHR(E_UNEXPECTED);
11248+
}
11249+
11250+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - InitializeContext ContextSize %d\n", contextSize));
11251+
11252+
PVOID pBuffer = _alloca(contextSize);
11253+
PCONTEXT pFrameContext = NULL;
11254+
success = InitializeContext(pBuffer, contextFlags, &pFrameContext, &contextSize);
11255+
if (!success)
11256+
{
11257+
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
11258+
_ASSERTE(!"InitializeContext failed");
11259+
11260+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from InitializeContext (error: 0x%X [%d]).\n", hr, GetLastError()));
11261+
11262+
ThrowHR(hr);
11263+
}
11264+
11265+
_ASSERTE((BYTE*)pFrameContext == pBuffer);
11266+
11267+
success = CopyContext(pFrameContext, contextFlags, pContext);
11268+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - CopyContext=%s %d\n", success?"SUCCESS":"FAIL", GetLastError()));
11269+
if (!success)
11270+
{
11271+
HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
11272+
_ASSERTE(!"CopyContext failed");
11273+
11274+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from CopyContext (error: 0x%X [%d]).\n", hr, GetLastError()));
11275+
11276+
ThrowHR(hr);
11277+
}
11278+
11279+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Set Thread Context - ID = 0x%X, SS enabled = %d\n", dwThreadId, /*(uint64_t)hThread,*/ (pContext->EFlags & 0x100) != 0));
11280+
11281+
DWORD lastError = 0;
11282+
11283+
success = ::SetThreadContext(hThread, pFrameContext);
11284+
if (!success)
11285+
{
11286+
lastError = ::GetLastError();
11287+
}
11288+
11289+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Set Thread Context Completed: Success=%d GetLastError=%d hr=0x%X\n", success, lastError, HRESULT_FROM_WIN32(lastError)));
11290+
_ASSERTE(success);
11291+
11292+
DWORD suspendCount = ::ResumeThread(hThread);
11293+
if (suspendCount == (DWORD)-1)
11294+
{
11295+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from ResumeThread\n"));
11296+
ThrowHR(HRESULT_FROM_GetLastError());
11297+
}
11298+
if (suspendCount != previousSuspendCount + 1)
11299+
{
11300+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from ResumeThread\n"));
11301+
ThrowHR(E_UNEXPECTED);
11302+
}
11303+
11304+
if (!success)
11305+
{
11306+
LOG((LF_CORDB, LL_INFO10000, "RS HandleSetThreadContextNeeded - Unexpected result from SetThreadContext\n"));
11307+
ThrowHR(HRESULT_FROM_WIN32(lastError));
11308+
}
11309+
#else
11310+
#error Platform not supported
11311+
#endif
11312+
}
11313+
#endif // OUT_OF_PROCESS_SETTHREADCONTEXT
1115611314

1115711315
//
1115811316
// If the thread has an unhandled managed exception, hijack it.
@@ -11377,7 +11535,15 @@ HRESULT CordbProcess::Filter(
1137711535

1137811536
// holder will invoke DeleteIPCEventHelper(pManagedEvent).
1137911537
}
11538+
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
11539+
else if (dwFirstChance && pRecord->ExceptionCode == STATUS_BREAKPOINT && pRecord->ExceptionAddress == m_runtimeOffsets.m_setThreadContextNeededAddr)
11540+
{
11541+
// this is a request to set the thread context out of process
1138011542

11543+
HandleSetThreadContextNeeded(dwThreadId);
11544+
*pContinueStatus = DBG_CONTINUE;
11545+
}
11546+
#endif
1138111547
}
1138211548
PUBLIC_API_END(hr);
1138311549
// we may not find the correct mscordacwks so fail gracefully

src/coreclr/debug/di/rspriv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3280,6 +3280,10 @@ class CordbProcess :
32803280
#endif
32813281
}
32823282

3283+
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
3284+
void HandleSetThreadContextNeeded(DWORD dwThreadId);
3285+
#endif
3286+
32833287
//
32843288
// Shim callbacks to simulate fake attach events.
32853289
//

src/coreclr/debug/ee/amd64/dbghelpers.asm

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,13 @@ LEAF_ENTRY NotifyRightSideOfSyncCompleteFlare, _TEXT
157157
ret
158158
LEAF_END NotifyRightSideOfSyncCompleteFlare, _TEXT
159159

160-
160+
; Flare for setting the context out of process
161+
LEAF_ENTRY SetThreadContextNeededFlare, _TEXT
162+
int 3
163+
; make sure that the basic block is unique
164+
test rax,7
165+
ret
166+
LEAF_END SetThreadContextNeededFlare, _TEXT
161167

162168
; This goes at the end of the assembly file
163169
end

0 commit comments

Comments
 (0)