From c93c89d04b9cff158f0356bf2609ffd25be6239e Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 11 Nov 2023 03:06:55 +0100 Subject: [PATCH] Profiler fixes #2 --- src/coreclr/inc/dacvars.h | 1 + src/coreclr/vm/appdomain.cpp | 1 + src/coreclr/vm/corelib.h | 1 + src/coreclr/vm/exceptionhandling.cpp | 44 ++++++++++++++++++------ src/coreclr/vm/exinfo.cpp | 2 ++ src/coreclr/vm/exinfo.h | 1 + src/coreclr/vm/proftoeeinterfaceimpl.cpp | 25 ++++++++++++++ src/coreclr/vm/vars.cpp | 1 + src/coreclr/vm/vars.hpp | 1 + 9 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index ddb0c40bea6d81..b632887e86d0f8 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -116,6 +116,7 @@ DEFINE_DACVAR(DWORD, dac__g_TlsIndex, g_TlsIndex) #ifdef FEATURE_EH_FUNCLETS DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pEHClass, ::g_pEHClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pExceptionServicesInternalCallsClass, ::g_pExceptionServicesInternalCallsClass) +DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pStackFrameIteratorClass, ::g_pStackFrameIteratorClass) DEFINE_DACVAR(BOOL, dac__g_isNewExceptionHandlingEnabled, ::g_isNewExceptionHandlingEnabled) #endif diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index a08d960869b677..2bfdd6cf29422d 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1402,6 +1402,7 @@ void SystemDomain::LoadBaseSystemClasses() #ifdef FEATURE_EH_FUNCLETS g_pEHClass = CoreLibBinder::GetClass(CLASS__EH); g_pExceptionServicesInternalCallsClass = CoreLibBinder::GetClass(CLASS__EXCEPTIONSERVICES_INTERNALCALLS); + g_pStackFrameIteratorClass = CoreLibBinder::GetClass(CLASS__STACKFRAMEITERATOR); #endif // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper. diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 8840baf59ad398..0517d817312b9e 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1188,6 +1188,7 @@ DEFINE_METHOD(EH, RH_THROW_EX, RhThrowEx, SM_Obj_RefExInfo_RetVoid) DEFINE_METHOD(EH, RH_THROWHW_EX, RhThrowHwEx, SM_UInt_RefExInfo_RetVoid) DEFINE_METHOD(EH, RH_RETHROW, RhRethrow, SM_RefExInfo_RefExInfo_RetVoid) DEFINE_CLASS(EXCEPTIONSERVICES_INTERNALCALLS, ExceptionServices, InternalCalls) +DEFINE_CLASS(STACKFRAMEITERATOR, Runtime, StackFrameIterator) #endif // FEATURE_EH_FUNCLETS #ifndef FOR_ILLINK diff --git a/src/coreclr/vm/exceptionhandling.cpp b/src/coreclr/vm/exceptionhandling.cpp index 74d3d13923da2d..0a34071ac41766 100644 --- a/src/coreclr/vm/exceptionhandling.cpp +++ b/src/coreclr/vm/exceptionhandling.cpp @@ -8200,7 +8200,11 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk else { EEToProfilerExceptionInterfaceWrapper::ExceptionSearchCatcherFound(pMD); - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pMD); + if (pExInfo->m_pMDToReport != NULL) + { + EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pExInfo->m_pMDToReport); + pExInfo->m_pMDToReport = NULL; + } // We don't need to do anything special for continuable exceptions after calling // this callback. We are going to start unwinding anyway. @@ -8233,7 +8237,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk !(pExInfo->m_exception == CLRException::GetPreallocatedStackOverflowException()); pExInfo->m_stackTraceInfo.AppendElement(canAllocateMemory, NULL, GetRegdisplaySP(pExInfo->m_frameIter.m_crawl.GetRegisterSet()), pMD, &pExInfo->m_frameIter.m_crawl); - } + } } } StackWalkAction retVal = pThis->Next(); @@ -8244,6 +8248,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk if (pExInfo->m_passNumber == 1) { EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pMD); + pExInfo->m_pMDToReport = pMD; // Notify the debugger that we are on the first pass for a managed exception. // Note that this callback is made for every managed frame. @@ -8252,6 +8257,7 @@ extern "C" bool QCALLTYPE SfiInit(StackFrameIterator* pThis, CONTEXT* pStackwalk else { EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pMD); + pExInfo->m_pMDToReport = pMD; } pExInfo->m_sfLowBound = GetRegdisplaySP(pThis->m_crawl.GetRegisterSet()); @@ -8296,15 +8302,24 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla ExInfo* pExInfo = pThis->GetNextExInfo(); ExInfo* pTopExInfo = pThread->GetExceptionState()->GetCurrentExInfo(); + bool isCollided = false; MethodDesc *pMD = pThis->m_crawl.GetFunction(); if (pTopExInfo->m_passNumber == 1) { - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pMD); + if (pTopExInfo->m_pMDToReport != NULL) + { + EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionLeave(pTopExInfo->m_pMDToReport); + pTopExInfo->m_pMDToReport = NULL; + } } else { - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pMD); + if (pTopExInfo->m_pMDToReport != NULL) + { + EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionLeave(pTopExInfo->m_pMDToReport); + pTopExInfo->m_pMDToReport = NULL; + } } // Check for reverse pinvoke (but eliminate the case when the caller is managed) or CallDescrWorkerInternal. @@ -8434,6 +8449,7 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla else { *uExCollideClauseIdx = pExInfo->m_idxCurClause; + isCollided = true; pExInfo->m_kind = (ExKind)((uint8_t)pExInfo->m_kind | (uint8_t)ExKind::SupersededFlag); // Unwind until we hit the frame of the prevExInfo @@ -8471,15 +8487,23 @@ extern "C" bool QCALLTYPE SfiNext(StackFrameIterator* pThis, uint* uExCollideCla pMD = pThis->m_crawl.GetFunction(); if (pTopExInfo->m_passNumber == 1) { - EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pMD); - - // Notify the debugger that we are on the first pass for a managed exception. - // Note that this callback is made for every managed frame. - EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, GetControlPC(pThis->m_crawl.GetRegisterSet()), GetRegdisplaySP(pThis->m_crawl.GetRegisterSet())); + // TODO: skip this and the related ...Leave for collided Unwind - maybe move this to the AppendElement above? + if (!isCollided) + { + EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pMD); + pTopExInfo->m_pMDToReport = pMD; + // Notify the debugger that we are on the first pass for a managed exception. + // Note that this callback is made for every managed frame. + EEToDebuggerExceptionInterfaceWrapper::FirstChanceManagedException(pThread, GetControlPC(pThis->m_crawl.GetRegisterSet()), GetRegdisplaySP(pThis->m_crawl.GetRegisterSet())); + } } else { - EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pMD); + if (!isCollided) + { + EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pMD); + pTopExInfo->m_pMDToReport = pMD; + } } Exit:; diff --git a/src/coreclr/vm/exinfo.cpp b/src/coreclr/vm/exinfo.cpp index 7c71ee702c7839..010cd084311792 100644 --- a/src/coreclr/vm/exinfo.cpp +++ b/src/coreclr/vm/exinfo.cpp @@ -113,6 +113,8 @@ void ExInfo::Init() m_StackAddress = this; DestroyExceptionHandle(); m_hThrowable = NULL; + m_ExceptionCode = 0; + m_pMDToReport = NULL; // By default, mark the tracker as not having delivered the first // chance exception notification diff --git a/src/coreclr/vm/exinfo.h b/src/coreclr/vm/exinfo.h index 3bd85f79278dc2..007002dab5188e 100644 --- a/src/coreclr/vm/exinfo.h +++ b/src/coreclr/vm/exinfo.h @@ -254,6 +254,7 @@ struct ExInfo EHClauseInfo m_EHClauseInfo; ExceptionFlags m_ExceptionFlags; DWORD m_ExceptionCode; + MethodDesc *m_pMDToReport; #ifndef TARGET_UNIX EHWatsonBucketTracker m_WatsonBucketTracker; diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 11853acdcf86ee..b3e1010795f014 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -8073,6 +8073,17 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D CONTEXT builtContext; #endif + // + // Skip all managed exception handling functions + // + if (pFunc != NULL && ( + (pFunc->GetMethodTable() == g_pEHClass) || + (pFunc->GetMethodTable() == g_pExceptionServicesInternalCallsClass) || + (pFunc->GetMethodTable() == g_pStackFrameIteratorClass))) + { + return SWA_CONTINUE; + } + // // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want // to return to the profiler as the context seed if it wants to walk the unmanaged @@ -8091,6 +8102,18 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D return SWA_CONTINUE; } + if (g_isNewExceptionHandlingEnabled && !pCf->IsFrameless() && InlinedCallFrame::FrameHasActiveCall(pCf->GetFrame())) + { + // Skip new exception handling helpers + InlinedCallFrame *pInlinedCallFrame = (InlinedCallFrame *)pCf->GetFrame(); + PTR_NDirectMethodDesc pMD = pInlinedCallFrame->m_Datum; + TADDR datum = dac_cast(pMD); + if ((datum & (TADDR)InlinedCallFrameMarker::Mask) == (TADDR)InlinedCallFrameMarker::ExceptionHandlingHelper) + { + return SWA_CONTINUE; + } + } + // // If this is not a transition of any sort and not a managed // method, ignore it. @@ -8114,6 +8137,8 @@ StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_D { frameInfo.funcID = NULL; frameInfo.extraArg = NULL; + // TODO: fixme - intermediate native frames should likely be reported + //return SWA_CONTINUE; } frameInfo.IP = currentIP; diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index fe6bf98bfdb594..b5e9263e35ce03 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -110,6 +110,7 @@ MethodTable* g_pCastHelpers; #ifdef FEATURE_EH_FUNCLETS GPTR_IMPL(MethodTable, g_pEHClass); GPTR_IMPL(MethodTable, g_pExceptionServicesInternalCallsClass); +GPTR_IMPL(MethodTable, g_pStackFrameIteratorClass); GVAL_IMPL(bool, g_isNewExceptionHandlingEnabled); #endif diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 1884efee7a2dc7..ba653f67439285 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -392,6 +392,7 @@ GVAL_DECL(DWORD, g_TlsIndex); #ifdef FEATURE_EH_FUNCLETS GPTR_DECL(MethodTable, g_pEHClass); GPTR_DECL(MethodTable, g_pExceptionServicesInternalCallsClass); +GPTR_DECL(MethodTable, g_pStackFrameIteratorClass); GVAL_DECL(bool, g_isNewExceptionHandlingEnabled); #endif