From abde3f9498f09b5016a7a0d7d2e1b81ce5c1b614 Mon Sep 17 00:00:00 2001 From: mikelle-rogers <45022607+mikelle-rogers@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:12:38 -0700 Subject: [PATCH] Update stepping through MulticastDelegate under the Debugger (#108414) * macOS stepping with multicast delegates * remove one call of MulticastDebuggerTraceHelper * change int to INT_PTR * change to QCall and optimize * styling and cleanup --- .../src/System/StubHelpers.cs | 10 +- src/coreclr/debug/ee/controller.cpp | 112 ++++++++++++++++-- src/coreclr/debug/ee/controller.h | 8 +- src/coreclr/debug/ee/debugger.cpp | 9 +- src/coreclr/debug/ee/debugger.h | 3 + src/coreclr/vm/comdelegate.cpp | 40 +++---- src/coreclr/vm/dbginterface.h | 1 + src/coreclr/vm/ecalllist.h | 1 - src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/stubhelpers.cpp | 15 ++- src/coreclr/vm/stubhelpers.h | 4 +- src/coreclr/vm/stubmgr.cpp | 61 +++------- src/coreclr/vm/stubmgr.h | 75 +++--------- src/coreclr/vm/vars.cpp | 5 + src/coreclr/vm/vars.hpp | 5 + 15 files changed, 204 insertions(+), 146 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 33d9c6ef28765b..6d9c3d7680f316 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1583,8 +1583,14 @@ internal static void ValidateObject(object obj, IntPtr pMD) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern IntPtr GetStubContext(); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void MulticastDebuggerTraceHelper(object o, int count); + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void MulticastDebuggerTraceHelper(object o, int count) + { + MulticastDebuggerTraceHelperQCall(ObjectHandleOnStack.Create(ref o), count); + } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint="StubHelpers_MulticastDebuggerTraceHelper")] + private static partial void MulticastDebuggerTraceHelperQCall(ObjectHandleOnStack obj, int count); [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 8b7d0d88cc426c..4ce03c05704f75 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -943,7 +943,8 @@ DebuggerController::DebuggerController(Thread * pThread, AppDomain * pAppDomain) m_unwindFP(LEAF_MOST_FRAME), m_eventQueuedCount(0), m_deleted(false), - m_fEnableMethodEnter(false) + m_fEnableMethodEnter(false), + m_multicastDelegateHelper(false) { CONTRACTL { @@ -1133,6 +1134,8 @@ void DebuggerController::DisableAll() DisableTraceCall(); if (m_fEnableMethodEnter) DisableMethodEnter(); + if (m_multicastDelegateHelper) + DisableMultiCastDelegate(); } } @@ -2279,6 +2282,7 @@ static bool _AddrIsJITHelper(PCODE addr) // method & return true. // // Return true if we set a patch, else false +#ifndef DACCESS_COMPILE bool DebuggerController::PatchTrace(TraceDestination *trace, FramePointer fp, bool fStopInUnmanaged) @@ -2364,7 +2368,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_FRAME_PUSH: LOG((LF_CORDB, LL_INFO10000, - "Setting frame patch at 0x%p(%p)\n", trace->GetAddress(), fp.GetSPValue())); + "Setting frame patch at %p(%p)\n", trace->GetAddress(), fp.GetSPValue())); AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)trace->GetAddress(), fp, @@ -2374,13 +2378,12 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, case TRACE_MGR_PUSH: LOG((LF_CORDB, LL_INFO10000, - "Setting frame patch (TRACE_MGR_PUSH) at 0x%p(%p)\n", - trace->GetAddress(), fp.GetSPValue())); - + "Setting frame patch (TRACE_MGR_PUSH) at %p(%p)\n", + trace->GetAddress(), fp.GetSPValue())); dcp = AddAndActivateNativePatchForAddress((CORDB_ADDRESS_TYPE *)trace->GetAddress(), - LEAF_MOST_FRAME, // But Mgr_push can't have fp affinity! - TRUE, - DPT_DEFAULT_TRACE_TYPE); // TRACE_OTHER + LEAF_MOST_FRAME, // But Mgr_push can't have fp affinity! + TRUE, + DPT_DEFAULT_TRACE_TYPE); // TRACE_OTHER // Now copy over the trace field since TriggerPatch will expect this // to be set for this case. if (dcp != NULL) @@ -2390,6 +2393,10 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, return true; + case TRACE_MULTICAST_DELEGATE_HELPER: + EnableMultiCastDelegate(); + return true; + case TRACE_OTHER: LOG((LF_CORDB, LL_INFO10000, "Can't set a trace patch for TRACE_OTHER...\n")); @@ -2400,6 +2407,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace, return false; } } +#endif //----------------------------------------------------------------------------- // Checks if the patch matches the context + thread. @@ -3879,6 +3887,73 @@ void DebuggerController::DispatchMethodEnter(void * pIP, FramePointer fp) } +void DebuggerController::EnableMultiCastDelegate() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + ControllerLockHolder chController; + if (!m_multicastDelegateHelper) + { + LOG((LF_CORDB, LL_INFO1000000, "DC::EnableMultiCastDel, this=%p, previously disabled\n", this)); + m_multicastDelegateHelper = true; + g_multicastDelegateTraceActiveCount += 1; + } + else + { + LOG((LF_CORDB, LL_INFO1000000, "DC::EnableMultiCastDel, this=%p, already set\n", this)); + } +} + +void DebuggerController::DisableMultiCastDelegate() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + ControllerLockHolder chController; + if (m_multicastDelegateHelper) + { + LOG((LF_CORDB, LL_INFO10000, "DC::DisableMultiCastDelegate, this=%p, previously set\n", this)); + m_multicastDelegateHelper = false; + g_multicastDelegateTraceActiveCount -= 1; + } + else + { + LOG((LF_CORDB, LL_INFO10000, "DC::DisableMultiCastDelegate, this=%p, already disabled\n", this)); + } +} + +// Loop through controllers and dispatch TriggerMulticastDelegate +void DebuggerController::DispatchMulticastDelegate(DELEGATEREF pbDel, INT32 countDel) +{ + LOG((LF_CORDB, LL_INFO10000, "DC::DispatchMulticastDelegate\n")); + + Thread * pThread = g_pEEInterface->GetThread(); + _ASSERTE(pThread != NULL); + + ControllerLockHolder lockController; + + DebuggerController *p = g_controllers; + while (p != NULL) + { + if (p->m_multicastDelegateHelper) + { + if ((p->GetThread() == NULL) || (p->GetThread() == pThread)) + { + p->TriggerMulticastDelegate(pbDel, countDel); + } + } + p = p->m_next; + } +} // // AddProtection adds page protection to (at least) the given range of // addresses @@ -4023,6 +4098,10 @@ void DebuggerController::DispatchFuncEvalExit(Thread * thread) } +void DebuggerController::TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount) +{ + _ASSERTE(!"This code should be unreachable. If your controller enables MulticastDelegateHelper events,it should also override this callback to do something useful when the event arrives."); +} #ifdef _DEBUG @@ -6283,7 +6362,7 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio && g_pEEInterface->FollowTrace(&trace) && PatchTrace(&trace, info->m_activeFrame.fp, true)) - break; + continue; } else if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget) @@ -7553,6 +7632,21 @@ void DebuggerStepper::TriggerUnwind(Thread *thread, m_reason = unwindReason; } +void DebuggerStepper::TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount) +{ + TraceDestination trace; + FramePointer fp = LEAF_MOST_FRAME; + + PTRARRAYREF pDelInvocationList = (PTRARRAYREF) pDel->GetInvocationList(); + DELEGATEREF pCurrentInvokeDel = (DELEGATEREF) pDelInvocationList->GetAt(delegateCount); + + StubLinkStubManager::TraceDelegateObject((BYTE*)OBJECTREFToObject(pCurrentInvokeDel), &trace); + + g_pEEInterface->FollowTrace(&trace); + //fStopInUnmanaged only matters for TRACE_UNMANAGED + PatchTrace(&trace, fp, /*fStopInUnmanaged*/false); + this->DisableMultiCastDelegate(); +} // Prepare for sending an event. // This is called 1:1 w/ SendEvent, but this method can be called in a GC_TRIGGERABLE context diff --git a/src/coreclr/debug/ee/controller.h b/src/coreclr/debug/ee/controller.h index 16e702e5cd35a6..5c14bb201554d9 100644 --- a/src/coreclr/debug/ee/controller.h +++ b/src/coreclr/debug/ee/controller.h @@ -1089,6 +1089,7 @@ class DebuggerController // pIP is the ip right after the prolog of the method we've entered. // fp is the frame pointer for that method. static void DispatchMethodEnter(void * pIP, FramePointer fp); + static void DispatchMulticastDelegate(DELEGATEREF pbDel, INT32 countDel); // Delete any patches that exist for a specific module and optionally a specific AppDomain. @@ -1299,6 +1300,9 @@ class DebuggerController void EnableMethodEnter(); void DisableMethodEnter(); + void EnableMultiCastDelegate(); + void DisableMultiCastDelegate(); + void DisableAll(); virtual DEBUGGER_CONTROLLER_TYPE GetDCType( void ) @@ -1398,6 +1402,7 @@ class DebuggerController const BYTE * ip, FramePointer fp); + virtual void TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount); // Send the managed debug event. // This is called after TriggerPatch/TriggerSingleStep actually trigger. @@ -1437,6 +1442,7 @@ class DebuggerController int m_eventQueuedCount; bool m_deleted; bool m_fEnableMethodEnter; + bool m_multicastDelegateHelper; #endif // !DACCESS_COMPILE }; @@ -1638,7 +1644,7 @@ class DebuggerStepper : public DebuggerController virtual void TriggerMethodEnter(Thread * thread, DebuggerJitInfo * dji, const BYTE * ip, FramePointer fp); - + void TriggerMulticastDelegate(DELEGATEREF pDel, INT32 delegateCount); void ResetRange(); diff --git a/src/coreclr/debug/ee/debugger.cpp b/src/coreclr/debug/ee/debugger.cpp index 7015d6010f1664..695f48752c16c3 100644 --- a/src/coreclr/debug/ee/debugger.cpp +++ b/src/coreclr/debug/ee/debugger.cpp @@ -26,6 +26,7 @@ #include "../../vm/dwreport.h" #include "../../vm/eepolicy.h" #include "../../vm/excep.h" + #if defined(FEATURE_DBGIPC_TRANSPORT_VM) #include "dbgtransportsession.h" #endif // FEATURE_DBGIPC_TRANSPORT_VM @@ -12588,7 +12589,7 @@ bool Debugger::IsThreadAtSafePlace(Thread *thread) // any thread handling a SO is not at a safe place. // NOTE: don't check for thread->IsExceptionInProgress(), SO has special handling // that directly sets the last thrown object without ever creating a tracker. - // (Tracker is what thread->IsExceptionInProgress() checks for) + // (Tracker is what thread->IsExceptionInProgress() checks for) if (g_pEEInterface->GetThreadException(thread) == CLRException::GetPreallocatedStackOverflowExceptionHandle()) { return false; @@ -16775,6 +16776,12 @@ BOOL Debugger::IsOutOfProcessSetContextEnabled() } #endif // OUT_OF_PROCESS_SETTHREADCONTEXT #endif // DACCESS_COMPILE +#ifndef DACCESS_COMPILE +void Debugger::MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count) +{ + DebuggerController::DispatchMulticastDelegate(pbDel, count); +} +#endif //DACCESS_COMPILE #endif //DEBUGGING_SUPPORTED diff --git a/src/coreclr/debug/ee/debugger.h b/src/coreclr/debug/ee/debugger.h index c7689e3548fc6b..d9513cac8f5abc 100644 --- a/src/coreclr/debug/ee/debugger.h +++ b/src/coreclr/debug/ee/debugger.h @@ -2610,6 +2610,9 @@ class Debugger : public DebugInterface bool ThisIsHelperThread(void); HRESULT ReDaclEvents(PSECURITY_DESCRIPTOR securityDescriptor); +#ifndef DACCESS_COMPILE + void MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count); +#endif #ifdef DACCESS_COMPILE virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index b3dcb78a7e0326..8f20a405f7a5f8 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2137,18 +2137,30 @@ extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegat dwReturnValNum = pCode->NewLocal(sig.GetRetTypeHandleNT()); ILCodeLabel *nextDelegate = pCode->NewCodeLabel(); - ILCodeLabel *checkCount = pCode->NewCodeLabel(); // initialize counter pCode->EmitLDC(0); pCode->EmitSTLOC(dwLoopCounterNum); - // Make the shape of the loop similar to what C# compiler emits - pCode->EmitBR(checkCount); - //Label_nextDelegate: pCode->EmitLabel(nextDelegate); +#ifdef DEBUGGING_SUPPORTED + ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); + ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); + + // Call MulticastDebuggerTraceHelper only if we have a controller subscribing to the event + pCode->EmitLDC((DWORD_PTR)&g_multicastDelegateTraceActiveCount); + pCode->EmitCONV_I(); + pCode->EmitLDIND_I4(); + // g_multicastDelegateTraceActiveCount != 0 + pCode->EmitLDC(0); + pCode->EmitCEQ(); + pCode->EmitBRFALSE(invokeTraceHelper); + + pCode->EmitLabel(debuggerCheckEnd); +#endif // DEBUGGING_SUPPORTED + // Load next delegate from array using LoopCounter as index pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_LIST))); @@ -2172,26 +2184,6 @@ extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegat pCode->EmitADD(); pCode->EmitSTLOC(dwLoopCounterNum); - //Label_checkCount - pCode->EmitLabel(checkCount); - -#ifdef DEBUGGING_SUPPORTED - ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); - ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); - - // Call MulticastDebuggerTraceHelper only if any debugger is attached - pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); - pCode->EmitCONV_I(); - pCode->EmitLDIND_I4(); - - // (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0 - pCode->EmitLDC(DBCF_ATTACHED); - pCode->EmitAND(); - pCode->EmitBRTRUE(invokeTraceHelper); - - pCode->EmitLabel(debuggerCheckEnd); -#endif // DEBUGGING_SUPPORTED - // compare LoopCounter with InvocationCount. If less then branch to nextDelegate pCode->EmitLDLOC(dwLoopCounterNum); pCode->EmitLoadThis(); diff --git a/src/coreclr/vm/dbginterface.h b/src/coreclr/vm/dbginterface.h index 7c2efd46d3a7a2..9a58eea52ad256 100644 --- a/src/coreclr/vm/dbginterface.h +++ b/src/coreclr/vm/dbginterface.h @@ -408,6 +408,7 @@ class DebugInterface #ifndef DACCESS_COMPILE virtual HRESULT DeoptimizeMethod(Module* pModule, mdMethodDef methodDef) = 0; virtual HRESULT IsMethodDeoptimized(Module *pModule, mdMethodDef methodDef, BOOL *pResult) = 0; + virtual void MulticastTraceNextStep(DELEGATEREF pbDel, INT32 count) = 0; #endif //DACCESS_COMPILE }; diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 06270369d943b5..25ec7d044d5a3b 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -386,7 +386,6 @@ FCFuncStart(gStubHelperFuncs) FCFuncElement("CalcVaListSize", StubHelpers::CalcVaListSize) FCFuncElement("LogPinnedArgument", StubHelpers::LogPinnedArgument) FCFuncElement("GetStubContext", StubHelpers::GetStubContext) - FCFuncElement("MulticastDebuggerTraceHelper", StubHelpers::MulticastDebuggerTraceHelper) FCFuncElement("NextCallReturnAddress", StubHelpers::NextCallReturnAddress) FCFuncEnd() diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 39961782935952..5558e8efd91868 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -466,6 +466,7 @@ static const Entry s_QCall[] = DllImportEntry(StubHelpers_MarshalToUnmanagedVaList) DllImportEntry(StubHelpers_ValidateObject) DllImportEntry(StubHelpers_ValidateByref) + DllImportEntry(StubHelpers_MulticastDebuggerTraceHelper) #ifdef PROFILING_SUPPORTED DllImportEntry(StubHelpers_ProfilerBeginTransitionCallback) DllImportEntry(StubHelpers_ProfilerEndTransitionCallback) diff --git a/src/coreclr/vm/stubhelpers.cpp b/src/coreclr/vm/stubhelpers.cpp index 775c965c7a93a5..c3ec58f129b753 100644 --- a/src/coreclr/vm/stubhelpers.cpp +++ b/src/coreclr/vm/stubhelpers.cpp @@ -16,6 +16,7 @@ #include "comdatetime.h" #include "gcheaputilities.h" #include "interoputil.h" +#include "../debug/ee/debugger.h" #ifdef FEATURE_COMINTEROP #include @@ -736,12 +737,18 @@ FCIMPL1(DWORD, StubHelpers::CalcVaListSize, VARARGS *varargs) } FCIMPLEND -FCIMPL2(void, StubHelpers::MulticastDebuggerTraceHelper, Object* element, INT32 count) +extern "C" void QCALLTYPE StubHelpers_MulticastDebuggerTraceHelper(QCall::ObjectHandleOnStack element, INT32 count) { - FCALL_CONTRACT; - FCUnique(0xa5); + QCALL_CONTRACT; + + BEGIN_QCALL; + + GCX_COOP(); + + g_pDebugger->MulticastTraceNextStep((DELEGATEREF)(element.Get()), count); + + END_QCALL; } -FCIMPLEND FCIMPL0(void*, StubHelpers::NextCallReturnAddress) { diff --git a/src/coreclr/vm/stubhelpers.h b/src/coreclr/vm/stubhelpers.h index 72f5102aa9c823..e77ce5f2e7f46e 100644 --- a/src/coreclr/vm/stubhelpers.h +++ b/src/coreclr/vm/stubhelpers.h @@ -39,8 +39,6 @@ class StubHelpers static FCDECL2(void, LogPinnedArgument, MethodDesc *localDesc, Object *nativeArg); static FCDECL1(DWORD, CalcVaListSize, VARARGS *varargs); - static FCDECL2(void, MulticastDebuggerTraceHelper, Object*, INT32); - static FCDECL0(void*, NextCallReturnAddress); }; @@ -74,4 +72,6 @@ extern "C" void QCALLTYPE StubHelpers_MarshalToUnmanagedVaList(va_list va, DWORD extern "C" void QCALLTYPE StubHelpers_ValidateObject(QCall::ObjectHandleOnStack pObj, MethodDesc *pMD); extern "C" void QCALLTYPE StubHelpers_ValidateByref(void *pByref, MethodDesc *pMD); +extern "C" void QCALLTYPE StubHelpers_MulticastDebuggerTraceHelper(QCall::ObjectHandleOnStack element, INT32 count); + #endif // __STUBHELPERS_h__ diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 35eefe21168809..31a01fc83986f5 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -19,14 +19,15 @@ const char *GetTType( TraceType tt) switch( tt ) { - case TRACE_ENTRY_STUB: return "TRACE_ENTRY_STUB"; - case TRACE_STUB: return "TRACE_STUB"; - case TRACE_UNMANAGED: return "TRACE_UNMANAGED"; - case TRACE_MANAGED: return "TRACE_MANAGED"; - case TRACE_FRAME_PUSH: return "TRACE_FRAME_PUSH"; - case TRACE_MGR_PUSH: return "TRACE_MGR_PUSH"; - case TRACE_OTHER: return "TRACE_OTHER"; - case TRACE_UNJITTED_METHOD: return "TRACE_UNJITTED_METHOD"; + case TRACE_ENTRY_STUB: return "TRACE_ENTRY_STUB"; + case TRACE_STUB: return "TRACE_STUB"; + case TRACE_UNMANAGED: return "TRACE_UNMANAGED"; + case TRACE_MANAGED: return "TRACE_MANAGED"; + case TRACE_FRAME_PUSH: return "TRACE_FRAME_PUSH"; + case TRACE_MGR_PUSH: return "TRACE_MGR_PUSH"; + case TRACE_OTHER: return "TRACE_OTHER"; + case TRACE_UNJITTED_METHOD: return "TRACE_UNJITTED_METHOD"; + case TRACE_MULTICAST_DELEGATE_HELPER: return "TRACE_MULTICAST_DELEGATE_HELPER"; } return "TRACE_REALLY_WACKED"; } @@ -118,6 +119,10 @@ const CHAR * TraceDestination::DbgToString(SString & buffer) pValue = buffer.GetUTF8(); break; + case TRACE_MULTICAST_DELEGATE_HELPER: + pValue = "TRACE_MULTICAST_DELEGATE_HELPER"; + break; + case TRACE_OTHER: pValue = "TRACE_OTHER"; break; @@ -1711,21 +1716,14 @@ BOOL ILStubManager::DoTraceStub(PCODE stubStartAddress, MethodDesc* pStubMD = ExecutionManager::GetCodeMethodDesc(stubStartAddress); if (pStubMD != NULL && pStubMD->AsDynamicMethodDesc()->IsMulticastStub()) { -#if defined(TARGET_ARM64) && defined(__APPLE__) - //On ARM64 Mac, we cannot put a breakpoint inside of MulticastDebuggerTraceHelper - LOG((LF_CORDB, LL_INFO10000, "ILSM::DoTraceStub: skipping on arm64-macOS\n")); - return FALSE; -#else - traceDestination = GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper); -#endif //defined(TARGET_ARM64) && defined(__APPLE__) + trace->InitForMulticastDelegateHelper(); } else { // This call is going out to unmanaged code, either through pinvoke or COM interop. - traceDestination = stubStartAddress; + trace->InitForManagerPush(stubStartAddress, this); } - trace->InitForManagerPush(traceDestination, this); LOG_TRACE_DESTINATION(trace, traceDestination, "ILStubManager::DoTraceStub"); return TRUE; @@ -1774,12 +1772,6 @@ BOOL ILStubManager::TraceManager(Thread *thread, PCODE stubIP = GetIP(pContext); *pRetAddr = (BYTE *)StubManagerHelpers::GetReturnAddress(pContext); - if (stubIP == GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper)) - { - stubIP = (PCODE)*pRetAddr; - *pRetAddr = (BYTE*)StubManagerHelpers::GetRetAddrFromMulticastILStubFrame(pContext); - } - DynamicMethodDesc *pStubMD = Entry2MethodDesc(stubIP, NULL)->AsDynamicMethodDesc(); TADDR arg = StubManagerHelpers::GetHiddenArg(pContext); Object * pThis = StubManagerHelpers::GetThisPtr(pContext); @@ -1788,29 +1780,10 @@ BOOL ILStubManager::TraceManager(Thread *thread, // See code:ILStubCache.CreateNewMethodDesc for the code that sets flags on stub MDs PCODE target = (PCODE)NULL; - if (pStubMD->IsMulticastStub()) { - _ASSERTE(GetIP(pContext) == GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper)); - - int delegateCount = (int)StubManagerHelpers::GetSecondArg(pContext); - int totalDelegateCount = (int)*(size_t*)((BYTE*)pThis + DelegateObject::GetOffsetOfInvocationCount()); - if (delegateCount == totalDelegateCount) - { - LOG((LF_CORDB, LL_INFO1000, "ILSM::TraceManager: Fired all delegates\n")); - return FALSE; - } - else - { - // We're going to execute stub delegateCount next, so go and grab it. - BYTE *pbDelInvocationList = *(BYTE **)((BYTE*)pThis + DelegateObject::GetOffsetOfInvocationList()); - - BYTE* pbDel = *(BYTE**)( ((ArrayBase *)pbDelInvocationList)->GetDataPtr() + - ((ArrayBase *)pbDelInvocationList)->GetComponentSize()*delegateCount); - - _ASSERTE(pbDel); - return StubLinkStubManager::TraceDelegateObject(pbDel, trace); - } + _ASSERTE(!"We should never get here. Multicast Delegates should not invoke TraceManager."); + return FALSE; } else if (pStubMD->IsReverseStub()) { diff --git a/src/coreclr/vm/stubmgr.h b/src/coreclr/vm/stubmgr.h index 679b4fe077ee8b..6d3174366a729b 100644 --- a/src/coreclr/vm/stubmgr.h +++ b/src/coreclr/vm/stubmgr.h @@ -53,16 +53,17 @@ // TraceType indicates what this 'target' is enum TraceType { - TRACE_ENTRY_STUB, // Stub goes to an unmanaged entry stub - TRACE_STUB, // Stub goes to another stub - TRACE_UNMANAGED, // Stub goes to unmanaged code - TRACE_MANAGED, // Stub goes to Jitted code - TRACE_UNJITTED_METHOD, // Is the prestub, since there is no code, the address will actually be a MethodDesc* + TRACE_ENTRY_STUB, // Stub goes to an unmanaged entry stub + TRACE_STUB, // Stub goes to another stub + TRACE_UNMANAGED, // Stub goes to unmanaged code + TRACE_MANAGED, // Stub goes to Jitted code + TRACE_UNJITTED_METHOD, // Is the prestub, since there is no code, the address will actually be a MethodDesc* - TRACE_FRAME_PUSH, // Don't know where stub goes, stop at address, and then ask the frame that is on the stack - TRACE_MGR_PUSH, // Don't know where stub goes, stop at address then call TraceManager() below to find out + TRACE_FRAME_PUSH, // Don't know where stub goes, stop at address, and then ask the frame that is on the stack + TRACE_MGR_PUSH, // Don't know where stub goes, stop at address then call TraceManager() below to find out + TRACE_MULTICAST_DELEGATE_HELPER, // Stub goes to a multicast delegate helper - TRACE_OTHER // We are going somewhere you can't step into (eg. ee helper function) + TRACE_OTHER // We are going somewhere you can't step into (eg. ee helper function) }; class StubManager; @@ -147,6 +148,14 @@ class TraceDestination this->stubManager = NULL; } + + void InitForMulticastDelegateHelper() + { + this->type = TRACE_MULTICAST_DELEGATE_HELPER; + this->address = (PCODE)NULL; + this->stubManager = NULL; + } + // Nobody recognized the target address. We will not be able to step-in to it. // This is ok if the target just calls into mscorwks (such as an Fcall) because // there's no managed code to step in to, and we don't support debugging the CLR @@ -853,56 +862,6 @@ class StubManagerHelpers #endif } - static PCODE GetRetAddrFromMulticastILStubFrame(T_CONTEXT * pContext) - { - /* - Following is the callstack corresponding to context received by ILStubManager::TraceManager. - This function returns the return address (user code address) where control should return after all - delegates in multicast delegate have been executed. - - StubHelpers::MulticastDebuggerTraceHelper - IL_STUB_MulticastDelegate_Invoke - UserCode which invokes multicast delegate <--- - */ - -#if defined(TARGET_X86) - return *((PCODE *)pContext->Ebp + 1); -#elif defined(TARGET_AMD64) - T_CONTEXT context(*pContext); - Thread::VirtualUnwindCallFrame(&context); - Thread::VirtualUnwindCallFrame(&context); - - return context.Rip; -#elif defined(TARGET_ARM) - return *((PCODE *)((TADDR)pContext->R11) + 1); -#elif defined(TARGET_ARM64) - return *((PCODE *)pContext->Fp + 1); -#else - PORTABILITY_ASSERT("StubManagerHelpers::GetRetAddrFromMulticastILStubFrame"); - return (TADDR)NULL; -#endif - } - - static TADDR GetSecondArg(T_CONTEXT * pContext) - { -#if defined(TARGET_X86) - return pContext->Edx; -#elif defined(TARGET_AMD64) -#ifdef UNIX_AMD64_ABI - return pContext->Rsi; -#else - return pContext->Rdx; -#endif -#elif defined(TARGET_ARM) - return pContext->R1; -#elif defined(TARGET_ARM64) - return pContext->X1; -#else - PORTABILITY_ASSERT("StubManagerHelpers::GetSecondArg"); - return (TADDR)NULL; -#endif - } - }; #endif // !__stubmgr_h__ diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index ebd5310e40e6dc..ddf1ff0a15d897 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -143,6 +143,11 @@ GVAL_IMPL_INIT(DWORD, g_CORDebuggerControlFlags, DBCF_NORMAL_OPERATION); #ifdef DEBUGGING_SUPPORTED GPTR_IMPL(EEDbgInterfaceImpl, g_pEEDbgInterfaceImpl); + +#ifndef DACCESS_COMPILE +GVAL_IMPL_INIT(DWORD, g_multicastDelegateTraceActiveCount, 0); +#endif // DACCESS_COMPILE + #endif // DEBUGGING_SUPPORTED #if defined(PROFILING_SUPPORTED_DATA) || defined(PROFILING_SUPPPORTED) diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 528d513e9d7b3f..f97b4fa5831247 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -411,6 +411,11 @@ GPTR_DECL(DebugInterface, g_pDebugInterface); GVAL_DECL(DWORD, g_CORDebuggerControlFlags); #ifdef DEBUGGING_SUPPORTED GPTR_DECL(EEDbgInterfaceImpl, g_pEEDbgInterfaceImpl); + +#ifndef DACCESS_COMPILE +GVAL_DECL(DWORD, g_multicastDelegateTraceActiveCount); +#endif // DACCESS_COMPILE + #endif // DEBUGGING_SUPPORTED #ifdef PROFILING_SUPPORTED