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..7863cb00d23f15 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,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Text;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System.Diagnostics
{
@@ -50,5 +53,25 @@ private void BuildStackFrame(int skipFrames, bool needFileInfo)
}
private static bool AppendStackFrameWithoutMethodBase(StringBuilder sb) => false;
+
+ [DllImport(RuntimeHelpers.QCall, EntryPoint = "StackFrame_GetMethodDescFromNativeIP")]
+ private static extern RuntimeMethodHandleInternal GetMethodDescFromNativeIP(IntPtr ip);
+
+ ///
+ /// 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 = GetMethodDescFromNativeIP(ip);
+
+ if (method.Value == IntPtr.Zero)
+ return null;
+
+ return RuntimeType.GetMethodBase(null, method);
+ }
}
}
diff --git a/src/coreclr/vm/debugdebugger.cpp b/src/coreclr/vm/debugdebugger.cpp
index fa55f3ed2c2c78..2ade537044abbe 100644
--- a/src/coreclr/vm/debugdebugger.cpp
+++ b/src/coreclr/vm/debugdebugger.cpp
@@ -297,7 +297,6 @@ FCIMPL0(FC_BOOL_RET, DebugDebugger::IsLogging)
}
FCIMPLEND
-
FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
StackFrameHelper* pStackFrameHelperUNSAFE,
INT32 iSkip,
@@ -778,6 +777,28 @@ FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
}
FCIMPLEND
+extern MethodDesc* QCALLTYPE StackFrame_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 3c9fd17cc43570..b559531524336d 100644
--- a/src/coreclr/vm/debugdebugger.h
+++ b/src/coreclr/vm/debugdebugger.h
@@ -171,4 +171,6 @@ class DebugStackTrace
};
+extern "C" MethodDesc* QCALLTYPE StackFrame_GetMethodDescFromNativeIP(LPVOID ip);
+
#endif // __DEBUG_DEBUGGER_h__
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 22327cdc79c80b..472a2c1a962c69 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -115,6 +115,7 @@ static const Entry s_QCall[] =
DllImportEntry(RuntimeModule_GetType)
DllImportEntry(RuntimeModule_GetScopeName)
DllImportEntry(RuntimeModule_GetFullyQualifiedName)
+ DllImportEntry(StackFrame_GetMethodDescFromNativeIP)
DllImportEntry(ModuleBuilder_GetStringConstant)
DllImportEntry(ModuleBuilder_GetTypeRef)
DllImportEntry(ModuleBuilder_GetTokenFromTypeSpec)
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 @@
+
+
+
+