동적 핀 보크 프로파일 링
MSIL 프로파일 러에서 작업 중이며 인터페이스 ManagedToUnmanagedTransition와 관련된 문제와 UnmanagedToManagedTransition콜백이 발생했습니다 ICorProfilerCallback.
내가 검색하고 싶은 것은 호출되는 메서드에 대한 정보 (상주하는 이름 및 모듈 이름)입니다.
지금까지는 잘 작동했습니다. 소위 동적 pinvoke가 발생할 때까지 (자세히 설명 : http://blogs.msdn.com/b/jonathanswift/archive/2006/10/03/dynamically-calling-an-unmanaged-dll-from-.net-_2800_c_23002900_ .aspx )
이 시나리오에서는 IMetaDataImport::GetPinvokeMap실패합니다. 또한 IMetaDataAssemblyImport::GetAssemblyProps어셈블리 이름으로 "dynamic_pinvoke"를 반환합니다.
profiler_1_0->GetTokenAndMetaDataFromFunction(function_id, IID_IMetaDataImport, (IUnknown**) &imd_import, &md_token);
imd_import->GetPinvokeMap(md_token, &mapping, module_name, buffer_size, &chars_read, &md_module_ref);
// here the fail occurs
profiler_1_0->GetTokenAndMetaDataFromFunction(function_id, IID_IMetaDataAssemblyImport, (IUnknown**) &imd_assembly_import, &md_token);
imd_assembly_import->GetAssemblyFromScope(&md_assembly);
imd_assembly_import->GetAssemblyProps(md_assembly, 0, 0, 0, assembly_name, buffer_size, &chars_read, 0, 0);
// assembly_name is set to "dynamic_pinvoke"
모듈 이름 (.dll)과 동적 pinvoke를 통해 pinvok되는 함수 이름을 얻는 방법은 무엇입니까?
프로파일 러 API는 일반적으로 DllImportAttribute 를 통해 관리 코드에 지정된 메타 데이터를 반환합니다 . Marshal.GetDelegateForFunctionPointer 메서드 를 사용하는 'dynamic pinvoke'의 경우 모듈 및 함수 이름이 메타 데이터로 지정되지 않았으며 사용할 수 없습니다. 필수 메타 데이터를 포함하는 동적 pinvoke 선언에 대한 대체 접근 방식은이 문제를 방지 할 수 있습니다. TypeBuilder.DefinePInvokeMethod 와 같은 System.Reflection.Emit API 를 하나의 솔루션 으로 사용해보십시오 .
다음은 프로파일 러 API와 함께 작동하는 System.Reflection.Emit을 사용하는 예제입니다.
using System;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Reflection;
namespace DynamicCodeCSharp
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
private delegate int MessageBoxFunc(IntPtr hWnd, string text, string caption, int options);
static readonly Type[] MessageBoxArgTypes = new Type[] { typeof(IntPtr), typeof(string), typeof(string), typeof(int)};
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
static MethodInfo BuildMessageBoxPInvoke(string module, string proc)
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(module), AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(module);
TypeBuilder typeBuilder = moduleBuilder.DefineType(proc);
typeBuilder.DefinePInvokeMethod(proc, module, proc,
MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard, typeof
(int), MessageBoxArgTypes,
CallingConvention.StdCall, CharSet.Auto);
Type type = typeBuilder.CreateType();
return type.GetMethod(proc, BindingFlags.Static | BindingFlags.NonPublic); ;
}
static MessageBoxFunc CreateFunc()
{
MethodInfo methodInfo = BuildMessageBoxPInvoke("user32.dll", "MessageBox");
return (MessageBoxFunc)Delegate.CreateDelegate(typeof(MessageBoxFunc), methodInfo);
}
static void Main(string[] args)
{
MessageBoxFunc func = CreateFunc();
func(IntPtr.Zero, "Hello World", "From C#", 0);
}
}
}
현재 접근 방식의 문제를 보여주는 몇 가지 예입니다.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, int options);
static void Main(string[] args)
{
MessageBox(IntPtr.Zero, "Hello World", "From C#", 0);
}
There is no MessageBox function exported from user32.dll. It only contains MessageBoxA and MessageBoxW. As we did not specify the ExactSpelling=false in the DllImport attribute and our CharSet is Unicode, .Net will also search user32.dll for our entry point appended with a W. This means MessageBoxW is in fact the native function we are calling. However, GetPinvokeMap returns 'MessageBox' as the function name (module_name variable in your code).
Now lets instead invoke the function via ordinal number rather than name. Using the dumpbin program in the Windows SDK:
dumpbin /exports C:\Windows\SysWOW64\user32.dll
...
2046 215 0006FD3F MessageBoxW
...
2046 is the ordinal number for MessageBoxW. Adjusting our DllImport declaration to use the EntryPoint field we get:
[DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "#2046")]
public static extern int MessageBox(IntPtr hWnd, string text, string caption, int options);
This time GetPInvokeMap returns "#2046". We can see the profiler knows nothing about the 'name' of the native function being invoked.
Going even further, the native code being called may not even have a name. In the following example, an 'Add' function is created in executable memory at runtime. No function name or library has ever been associated with the native code being executed.
using System;
using System.Runtime.InteropServices;
namespace DynamicCodeCSharp
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int AddFunc(int a, int b);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr VirtualAlloc(IntPtr addr, IntPtr size, int allocType, int protectType);
const int MEM_COMMIT = 0x1000;
const int MEM_RESERVE = 0x2000;
const int PAGE_EXECUTE_READWRITE = 0x40;
static readonly byte[] buf =
{
// push ebp
0x55,
// mov ebp, esp
0x8b, 0xec,
// mov eax, [ebp + 8]
0x8b, 0x45, 0x08,
// add eax, [ebp + 8]
0x03, 0x45, 0x0c,
// pop ebp
0x5d,
// ret
0xc3
};
static AddFunc CreateFunc()
{
// allocate some executable memory
IntPtr code = VirtualAlloc(IntPtr.Zero, (IntPtr)buf.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// copy our add function implementation into the memory
Marshal.Copy(buf, 0, code, buf.Length);
// create a delegate to this executable memory
return (AddFunc)Marshal.GetDelegateForFunctionPointer(code, typeof(AddFunc));
}
static void Main(string[] args)
{
AddFunc func = CreateFunc();
int value = func(10, 20);
Console.WriteLine(value);
}
}
}
참고URL : https://stackoverflow.com/questions/10933370/profiling-a-dynamic-pinvoke
'IT TIP' 카테고리의 다른 글
| 처리 도관 1 개, 동일한 유형의 IO 소스 2 개 (0) | 2020.11.28 |
|---|---|
| ASP.NET MVC 3에서 사용자 지정 편집기 / 디스플레이 템플릿을 만드는 방법은 무엇입니까? (0) | 2020.11.28 |
| Xcode가 다시 시작될 때마다 잘못 배치 된 뷰 (0) | 2020.11.28 |
| 제어 문자의 Socket.IO 문제 (0) | 2020.11.28 |
| kubernetes 서비스 정의에서 targetPort와 포트의 차이점 (0) | 2020.11.28 |