x86 only stackwalk fix
authorAndrew Au <andrewau@microsoft.com>
Wed, 10 Oct 2018 00:32:33 +0000 (17:32 -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/b70d04f9112548b1718e1768cf0cb35943724946

src/coreclr/src/debug/ee/controller.cpp
src/coreclr/src/debug/ee/controller.h

index 74d9f11..60d634a 100644 (file)
@@ -944,6 +944,11 @@ HRESULT DebuggerController::Initialize()
 //
 //---------------------------------------------------------------------------------------
 
+bool DebuggerController::s_fUnwoundWriteBarrier = false;
+DWORD DebuggerController::s_eipBeforeUnwoundWriteBarrier = 0;
+DWORD DebuggerController::s_ecxBeforeUnwoundWriteBarrier = 0;
+DWORD DebuggerController::s_ebpBeforeUnwoundWriteBarrier = 0;
+
 DebuggerController::DebuggerController(Thread * pThread, AppDomain * pAppDomain)
   : m_pAppDomain(pAppDomain), 
     m_thread(pThread), 
@@ -2730,6 +2735,20 @@ DPOSS_ACTION DebuggerController::ScanForTriggers(CORDB_ADDRESS_TYPE *address,
         tpr != TPR_TRIGGER_ONLY_THIS && 
         DebuggerDataBreakpoint::TriggerDataBreakpoint(thread, context))
     {
+        if (1) /* FIXME : IP range check is required */
+        {
+            // TODO: Comment on the JIT helper as well
+            DWORD* esp = (DWORD*)context->Esp;
+            DebuggerController::s_eipBeforeUnwoundWriteBarrier = context->Eip;
+            DebuggerController::s_ebpBeforeUnwoundWriteBarrier = context->Ebp;
+            DebuggerController::s_ecxBeforeUnwoundWriteBarrier = context->Ecx;
+            context->Ebp = *esp; esp++;
+            context->Ecx = *esp; esp++;
+            context->Eip = *esp; esp++;
+            context->Esp = (DWORD)esp;
+
+            DebuggerController::s_fUnwoundWriteBarrier = true;
+        }
         DebuggerDataBreakpoint *pDataBreakpoint = new (interopsafe) DebuggerDataBreakpoint(thread);
         pDcq->dcqEnqueue(pDataBreakpoint, FALSE);
     }
@@ -3015,7 +3034,18 @@ DPOSS_ACTION DebuggerController::DispatchPatchOrSingleStep(Thread *thread, CONTE
         // If we need to to a re-abort (see below), then save the current IP in the thread's context before we block and
         // possibly let another func eval get setup.
         reabort = thread->m_StateNC & Thread::TSNC_DebuggerReAbort;
+
         SENDIPCEVENT_END;
+        
+        if (DebuggerController::s_fUnwoundWriteBarrier)
+        {
+            DWORD* esp = (DWORD*)context->Esp;
+            context->Eip = DebuggerController::s_eipBeforeUnwoundWriteBarrier; esp--;
+            context->Ecx = DebuggerController::s_ecxBeforeUnwoundWriteBarrier; esp--;
+            context->Ebp = DebuggerController::s_ebpBeforeUnwoundWriteBarrier; esp--;
+            context->Esp = (DWORD)esp;
+            DebuggerController::s_fUnwoundWriteBarrier = false;
+        }
 
         if (!atSafePlace)
             g_pDebugger->DecThreadsAtUnsafePlaces();
index d73a432..8cc242f 100644 (file)
@@ -1386,7 +1386,7 @@ public:
     // the bp. So we pass in an extra flag, fInteruptedBySetIp,  to let the controller decide how to handle this.
     // Since SetIP only works within a single function, this can only be an issue if a thread's current stopping
     // location and the patch it set are in the same function. (So this could happen for step-over, but never
-    // setp-out). 
+    // step-out). 
     // This flag will almost always be false.
     // 
     // Once we actually send the event, we're under the debugger lock, and so the world is stable underneath us.
@@ -1414,7 +1414,13 @@ private:
     bool                m_deleted;
     bool                m_fEnableMethodEnter;
 
+    static bool         s_fUnwoundWriteBarrier;
+    static DWORD        s_eipBeforeUnwoundWriteBarrier;
+    static DWORD        s_ecxBeforeUnwoundWriteBarrier;
+    static DWORD        s_ebpBeforeUnwoundWriteBarrier;
+
 #endif // !DACCESS_COMPILE
+    
 };
 
 
@@ -1798,16 +1804,8 @@ public:
 
         CONTEXT *context = g_pEEInterface->GetThreadFilterContext(thread);
 
-        // If we got interupted by SetIp, we just don't send the IPC event. Our triggers are still
-        // active so no harm done.
-        if (!fInteruptedBySetIp)
-        {
-            g_pDebugger->SendDataBreakpoint(thread, context, this);
-            return true;
-        }
-
-        // Controller is still alive, will fire if we hit the breakpoint again.
-        return false;
+        g_pDebugger->SendDataBreakpoint(thread, context, this);
+        return true;
     }
 
     static bool TriggerDataBreakpoint(Thread *thread, CONTEXT * pContext)