diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs index 948ebd2537230d..3cfc7cc193ec1f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrame.CoreCLR.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text; +using System.Reflection; +using System.Runtime.CompilerServices; namespace System.Diagnostics { @@ -50,5 +52,22 @@ private void BuildStackFrame(int skipFrames, bool needFileInfo) } private static bool AppendStackFrameWithoutMethodBase(StringBuilder sb) => false; + + /// + /// Returns the MethodBase instance for the managed code IP address. + /// + /// Warning: The implementation of this method has race for dynamic and collectible methods. + /// + /// code address + /// MethodBase instance for the method or null if IP not found + internal static MethodBase? GetMethodFromNativeIP(IntPtr ip) + { + RuntimeMethodHandleInternal method = StackTrace.GetMethodDescFromNativeIP(ip); + + if (method.Value == IntPtr.Zero) + return null; + + return RuntimeType.GetMethodBase(null, method); + } } } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreCLR.cs index 9bef9fb72fae58..d82bbaf7e1e342 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackTrace.CoreCLR.cs @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Runtime.CompilerServices; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace System.Diagnostics { @@ -11,6 +12,9 @@ public partial class StackTrace [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, bool fNeedFileInfo, Exception? e); + [DllImport(RuntimeHelpers.QCall)] + internal static extern RuntimeMethodHandleInternal GetMethodDescFromNativeIP(IntPtr ip); + internal static int CalculateFramesToSkip(StackFrameHelper StackF, int iNumFrames) { int iRetVal = 0; diff --git a/src/coreclr/vm/debugdebugger.cpp b/src/coreclr/vm/debugdebugger.cpp index e21939990405c2..f08e5107b13812 100644 --- a/src/coreclr/vm/debugdebugger.cpp +++ b/src/coreclr/vm/debugdebugger.cpp @@ -776,6 +776,28 @@ FCIMPL4(void, DebugStackTrace::GetStackFramesInternal, } FCIMPLEND +MethodDesc* QCALLTYPE DebugStackTrace::GetMethodDescFromNativeIP(LPVOID ip) +{ + QCALL_CONTRACT; + + MethodDesc* pResult = nullptr; + + BEGIN_QCALL; + + // TODO: There is a race for dynamic and collectible methods here between getting + // the MethodDesc here and when the managed wrapper converts it into a MethodBase + // where the method could be collected. + EECodeInfo codeInfo((PCODE)ip); + if (codeInfo.IsValid()) + { + pResult = codeInfo.GetMethodDesc(); + } + + END_QCALL; + + return pResult; +} + FORCEINLINE void HolderDestroyStrongHandle(OBJECTHANDLE h) { if (h != NULL) DestroyStrongHandle(h); } typedef Wrapper, HolderDestroyStrongHandle, NULL> StrongHandleHolder; diff --git a/src/coreclr/vm/debugdebugger.h b/src/coreclr/vm/debugdebugger.h index cba432e3d8e5f2..2673f90717a695 100644 --- a/src/coreclr/vm/debugdebugger.h +++ b/src/coreclr/vm/debugdebugger.h @@ -158,6 +158,8 @@ class DebugStackTrace Object* pException ); + static MethodDesc* QCALLTYPE GetMethodDescFromNativeIP(LPVOID ip); + static void GetStackFramesFromException(OBJECTREF * e, GetStackFramesData *pData, PTRARRAYREF * pDynamicMethodArray = NULL); #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index c83248c00e2d0d..363ae6f6cfa7cc 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -128,6 +128,7 @@ FCFuncEnd() FCFuncStart(gDiagnosticsStackTrace) FCFuncElement("GetStackFramesInternal", DebugStackTrace::GetStackFramesInternal) + QCFuncElement("GetMethodDescFromNativeIP", DebugStackTrace::GetMethodDescFromNativeIP) FCFuncEnd() FCFuncStart(gEnvironmentFuncs) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml index 53a41aff8c935a..ee28b6e38cfe61 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml @@ -4,5 +4,9 @@ + + + +