Hacking CordbProcess::GetThreadContext / SetThreadContext to retrieve/modify managed...
authorAndrew Au <andrewau@microsoft.com>
Tue, 26 Jun 2018 17:31:07 +0000 (10:31 -0700)
committerAndrew Au <cshung@gmail.com>
Wed, 7 Nov 2018 02:34:47 +0000 (18:34 -0800)
Commit migrated from https://github.com/dotnet/coreclr/commit/f72bba95b01c790f92641b9d7d96bf23a014dd3e

src/coreclr/src/debug/di/process.cpp
src/coreclr/src/debug/ee/controller.cpp

index 1ab0724..64446cd 100644 (file)
@@ -6454,12 +6454,9 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE
 {
     PUBLIC_REENTRANT_API_ENTRY(this);
     FAIL_IF_NEUTERED(this);
-    FAIL_IF_MANAGED_ONLY(this);
-
-    DT_CONTEXT * pContext;
     LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x\n", threadID));
 
-    RSLockHolder lockHolder(GetProcessLock());
+    DT_CONTEXT * pContext;
 
     if (contextSize != sizeof(DT_CONTEXT))
     {
@@ -6471,21 +6468,52 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE
 
     VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true);
 
-#if !defined(FEATURE_INTEROP_DEBUGGING)
-    return E_NOTIMPL;
-#else
-    // Find the unmanaged thread
-    CordbUnmanagedThread *ut = GetUnmanagedThread(threadID);
-
-    if (ut == NULL)
+    if (this->IsInteropDebugging())
     {
-        LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
+        RSLockHolder lockHolder(GetProcessLock());
 
-        return E_INVALIDARG;
+        // Find the unmanaged thread
+        CordbUnmanagedThread *ut = GetUnmanagedThread(threadID);
+
+        if (ut == NULL)
+        {
+            LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
+
+            return E_INVALIDARG;
+        }
+
+        return ut->GetThreadContext((DT_CONTEXT*)context);
     }
+    else
+    {
+        RSLockHolder ch(GetProcess()->GetStopGoLock());
+        RSLockHolder lockHolder(GetProcessLock());
 
-    return ut->GetThreadContext((DT_CONTEXT*)context);
-#endif // FEATURE_INTEROP_DEBUGGING
+        HRESULT hr = S_OK;
+        EX_TRY
+        {
+            CordbThread* thread = this->TryLookupThreadByVolatileOSId(threadID);
+            if (thread == NULL)
+            {
+                LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
+
+                hr = E_INVALIDARG;
+            }
+            else
+            {
+                DT_CONTEXT* managedContext;
+                hr = thread->GetManagedContext(&managedContext);
+                *pContext = *managedContext;
+            }
+        }
+        EX_CATCH
+        {
+            hr = E_FAIL;
+        }
+        EX_END_CATCH(SwallowAllExceptions)
+
+        return hr;
+    }
 }
 
 // Public implementation of ICorDebugProcess::SetThreadContext.
@@ -6494,67 +6522,86 @@ HRESULT CordbProcess::GetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE
 HRESULT CordbProcess::SetThreadContext(DWORD threadID, ULONG32 contextSize, BYTE context[])
 {
     PUBLIC_REENTRANT_API_ENTRY(this);
-    FAIL_IF_MANAGED_ONLY(this);
 
-#if !defined(FEATURE_INTEROP_DEBUGGING)
-    return E_NOTIMPL;
-#else
     HRESULT hr = S_OK;
 
-    RSLockHolder lockHolder(GetProcessLock());
-
-    CordbUnmanagedThread *ut = NULL;
+    // @todo -  could we look at the context flags and return E_INVALIDARG if they're bad?
+    FAIL_IF_NEUTERED(this);
+    VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true);
 
     if (contextSize != sizeof(DT_CONTEXT))
     {
         LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, context size is invalid.\n", threadID));
-        hr = E_INVALIDARG;
-        goto Label_Done;
+        return E_INVALIDARG;
     }
 
-    // @todo -  could we look at the context flags and return E_INVALIDARG if they're bad?
-    FAIL_IF_NEUTERED(this);
-    VALIDATE_POINTER_TO_OBJECT_ARRAY(context, BYTE, contextSize, true, true);
+    DT_CONTEXT* pContext = (DT_CONTEXT*)context;
 
-    // Find the unmanaged thread
-    ut = GetUnmanagedThread(threadID);
-
-    if (ut == NULL)
+    if (this->IsInteropDebugging())
     {
-        LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, thread is invalid.\n", threadID));
-        hr = E_INVALIDARG;
-        goto Label_Done;
-    }
+        RSLockHolder lockHolder(GetProcessLock());
 
-    hr = ut->SetThreadContext((DT_CONTEXT*)context);
+        CordbUnmanagedThread *ut = NULL;
 
+        // Find the unmanaged thread
+        ut = GetUnmanagedThread(threadID);
 
-    // 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.
-    if (SUCCEEDED(hr))
-    {
-        // @dbgtodo stackwalk: this should all disappear with V3 stackwalker and getting rid of SetThreadContext.
-        EX_TRY
+        if (ut == NULL)
         {
-            // Find the managed thread.  Returns NULL if thread is not managed.
-            // If we don't have a thread prveiously cached, then there's no state to update.
-            CordbThread * pThread = TryLookupThreadByVolatileOSId(threadID);
+            LOG((LF_CORDB, LL_INFO10000, "CP::STC: thread=0x%x, thread is invalid.\n", threadID));
+            return E_INVALIDARG;
+        }
 
-            if (pThread != NULL)
+        hr = ut->SetThreadContext(pContext);
+
+        // 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.
+        if (SUCCEEDED(hr))
+        {
+            // @dbgtodo stackwalk: this should all disappear with V3 stackwalker and getting rid of SetThreadContext.
+            EX_TRY
             {
-                // In V2, we used to update the CONTEXT of the leaf chain if the chain is an unmanaged chain.
-                // In Arrowhead, we just force a cleanup of the stackwalk cache.  This is a more correct
-                // thing to do anyway, since the CONTEXT being set could be anything.
-                pThread->CleanupStack();
+                // Find the managed thread.  Returns NULL if thread is not managed.
+                // If we don't have a thread prveiously cached, then there's no state to update.
+                CordbThread * pThread = TryLookupThreadByVolatileOSId(threadID);
+
+                if (pThread != NULL)
+                {
+                    // In V2, we used to update the CONTEXT of the leaf chain if the chain is an unmanaged chain.
+                    // In Arrowhead, we just force a cleanup of the stackwalk cache.  This is a more correct
+                    // thing to do anyway, since the CONTEXT being set could be anything.
+                    pThread->CleanupStack();
+                }
             }
+            EX_CATCH_HRESULT(hr);
         }
-        EX_CATCH_HRESULT(hr);
     }
+    else
+    {
+        RSLockHolder ch(GetProcess()->GetStopGoLock());
+        RSLockHolder lockHolder(GetProcessLock());
+        
+        EX_TRY
+        {
+            CordbThread* thread = this->TryLookupThreadByVolatileOSId(threadID);
+            if (thread == NULL)
+            {
+                LOG((LF_CORDB, LL_INFO10000, "CP::GTC: thread=0x%x, thread id is invalid.\n", threadID));
 
-Label_Done:
-    return ErrWrapper(hr);
+                hr = E_INVALIDARG;
+            }
 
-#endif // FEATURE_INTEROP_DEBUGGING
+            hr = thread->SetManagedContext(pContext);
+        }
+        EX_CATCH
+        {
+            hr = E_FAIL;
+        }
+        EX_END_CATCH(SwallowAllExceptions)
+
+        
+    }
+    return hr;
 }
 
 
index 5ae9a95..c4b2927 100644 (file)
@@ -3017,15 +3017,15 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
         reabort = thread->m_StateNC & Thread::TSNC_DebuggerReAbort;
         SENDIPCEVENT_END;
 
-        CONTEXT c;
-        c.ContextFlags = CONTEXT_DEBUG_REGISTERS;
-        thread->GetThreadContext(&c);
-
-        context->Dr7 = c.Dr7;
-        context->Dr0 = c.Dr0;
-        context->Dr1 = c.Dr1;
-        context->Dr2 = c.Dr2;
-        context->Dr3 = c.Dr3;
+        // CONTEXT c;
+        // c.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+        // thread->GetThreadContext(&c);
+
+        // context->Dr7 = c.Dr7;
+        // context->Dr0 = c.Dr0;
+        // context->Dr1 = c.Dr1;
+        // context->Dr2 = c.Dr2;
+        // context->Dr3 = c.Dr3;
 
         if (!atSafePlace)
             g_pDebugger->DecThreadsAtUnsafePlaces();