@@ -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
0 commit comments