Get MethodInfo from managed function pointer? #46215
-
C# 9.0 starts to support function pointers of managed methods in unsafe context. Although it's designed to be performance-orientated, I think it would still be nice to have an API to find the I am not exactly sure whether this is easy or even possible in .NET Core, but I think the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 19 replies
-
If you don't strictly need a For example: using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Runtime;
using System.Linq;
public static unsafe class Program
{
public static void Main(string[] args)
{
IntPtr user32 = NativeLibrary.Load("User32.dll");
delegate*<void> managed1 = &TestMethod;
delegate*<void> managed2 = &AnotherMethod;
delegate*<void> managed3 = &MessageBoxW;
delegate* unmanaged<void> unmanaged1 = &UnmanagedMethod;
delegate* unmanaged<void> unmanaged2 = (delegate* unmanaged<void>)NativeLibrary.GetExport(user32, "MessageBoxW");
// Note that this means any methods JITted after we create the snapshot won't be available
// You can use AttachToProcess on yourself, but it's not supported.
// https://github.com/microsoft/clrmd/blob/master/doc/FAQ.md#can-i-use-this-api-to-inspect-my-own-process
using DataTarget target = DataTarget.CreateSnapshotAndAttach(Process.GetCurrentProcess().Id);
ClrRuntime runtime = target.ClrVersions.First().CreateRuntime();
void Test(string testName, void* functionPointer)
{
ClrMethod? method = runtime.GetMethodByInstructionPointer((ulong)functionPointer);
if (method is null)
{
Console.WriteLine($"{testName}: Not found");
return;
}
Console.WriteLine($"{testName}: {method.Signature}");
}
Test("managed1", managed1);
Test("managed2", managed2);
Test("managed3", managed3);
Test("unmanaged1", unmanaged1);
Test("unmanaged2", unmanaged2); // This is expected to not be found because it's a native method
}
public static void TestMethod()
{ }
public static void AnotherMethod()
{}
[UnmanagedCallersOnly]
public static void UnmanagedMethod()
{ }
[DllImport("User32.dll")]
public static extern void MessageBoxW(); // Obviously this won't be callable, it's just here so it resolves
} Here's the output you can expect from this:
( If you need a I made a nasty little proof of concept to call it using reflection just to prove it works: using System;
using System.Reflection;
internal static class MethodBaseHelper
{
private static Type? RuntimeMethodHandleInternal;
private static ConstructorInfo? RuntimeMethodHandleInternal_Constructor;
private static Type? RuntimeType;
private static MethodInfo? RuntimeType_GetMethodBase;
public static MethodBase? GetMethodBaseFromHandle(IntPtr handle)
{
RuntimeMethodHandleInternal ??= typeof(RuntimeMethodHandle).Assembly.GetType("System.RuntimeMethodHandleInternal", throwOnError: true)!;
RuntimeMethodHandleInternal_Constructor ??= RuntimeMethodHandleInternal.GetConstructor
(
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DoNotWrapExceptions,
binder: null,
new[] { typeof(IntPtr) },
modifiers: null
) ?? throw new InvalidOperationException("RuntimeMethodHandleInternal constructor is missing!");
RuntimeType ??= typeof(Type).Assembly.GetType("System.RuntimeType", throwOnError: true)!;
RuntimeType_GetMethodBase ??= RuntimeType.GetMethod
(
"GetMethodBase",
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DoNotWrapExceptions,
binder: null,
new[] { RuntimeType, RuntimeMethodHandleInternal },
modifiers: null
) ?? throw new InvalidOperationException("RuntimeType.GetMethodBase is missing!");
// Wrap the handle
object runtimeHandle = RuntimeMethodHandleInternal_Constructor.Invoke(new[] { (object)handle });
return (MethodBase?)RuntimeType_GetMethodBase.Invoke(null, new[] { null, runtimeHandle });
}
} If you add the following after the MethodBase? methodBase = MethodBaseHelper.GetMethodBaseFromHandle((IntPtr)method.MethodDesc);
Console.WriteLine($" MethodBase: {methodBase?.Name ?? "Not Found"}"); You get the following output:
If you only want this for debugging then maybe this is good enough. If not, you'd probably have to open an API request in dotnet/runtime. Not sure how they'll feel about an API to get a If you want to avoid using ClrMD, you could probably loop over all methods using reflection and compare using |
Beta Was this translation helpful? Give feedback.
If you don't strictly need a
MethodInfo
, but rather just information about the method the function pointer refers to, you can use ClrMD for this.For example: