Кажется, я не могу найти способ сделать это из Visual Studio (по крайней мере VS2017).Поэтому вам, возможно, повезет больше с использованием WinDbg (доступно как часть Windows SDK).
Чтобы упростить задачу, я предлагаю заставить ваше приложение выводить некоторые полезные данные, которые помогут найти код в памяти с помощью WinDbg.В частности, если вы можете вывести результат вызова Marshal.GetFunctionPointerForDelegate()
для делегата, созданного из вашего динамического метода, это очень приблизит вас к коду метода.Для этого вам нужно будет использовать неуниверсальный делегат, поэтому, например, если вы создаете делегат Func<...>
из своего динамического метода, вам необходимо временно заменить его чем-то неуниверсальным.
Какпример:
private delegate int AddDelegate(int a, int b);
public static void DynamicMethodTest()
{
// Create a DynamicMethod that adds its two int parameters
// Passing "true" as the final (restrictedSkipVisibility) parameter causes the method to be JITted immediately when you call .CreateDelegate()
var dynamicAdd = new DynamicMethod("Add", typeof(int), new[] { typeof(int), typeof(int) }, true);
var il = dynamicAdd.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
// Use the non-generic AddDelegate defined above, rather than a generic one like Func<int, int, int> so that Marshal.GetFunctionPointerForDelegate() works
var addDelegate = (AddDelegate)dynamicAdd.CreateDelegate(typeof(AddDelegate));
Console.WriteLine("Function Pointer: 0x{0:x16}", Marshal.GetFunctionPointerForDelegate(addDelegate).ToInt64());
Debugger.Break();
}
Если мы вызываем этот метод, когда приложение работает под WinDbg, мы должны получить что-то вроде следующего вывода в окне консоли, прежде чем автоматически взломать отладчик:
Function Pointer: 0x0000000012345678
Отсюда было несколько шагов до просмотра кода динамического метода.
Сначала используйте команду u
(unassemble) на выводе указателя функции выше:
0:000> u 0x0000000012345678 L1
00000000`12345678 49ba2143658700000000 mov r10,87654321h
Здесь первая инструкция загружает адрес указателя на действительный код динамического метода в r10
, поэтому мы используем команду dp
(Показать память - указатель), чтобы получить цель указателя:
0:000> dp 0x87654321 L1
00000000`87654321 000007fe`9abcdef0
Запустите u
(дизассемблировать) по этому адресу или введите адрес в окне «Разборка» («Просмотр» -> «Разборка»), чтобы получить код динамического метода:
0:000> u 000007fe`9abcdef0
000007fe`9abcdef0 8d0411 lea eax,[rcx+rdx]
000007fe`9abcdef3 c3 ret
...
По умолчанию команда unassemble выводит 8 инструкций, вы можете добавить спецификатор длины к команде, чтобы изменить это (например, добавление «L20» приведет к выводу 32 (0x20) инструкций) - вы сами должны определить полноеЭкстент функции.
В качестве альтернативы может оказаться проще использовать расширение отладки .NET для WinDbg для выполнения последнего шага дампинга кода динамического метода, и в этом случае вам сначала нужно загрузить расширение (толькотребуется один раз на сеанс отладки), используя .loadby sos clr
, затем вместо кода используйте !u
на кодовом адресе:
0:000> !u 000007fe`9abcdef0
Normal JIT generated code
DynamicClass.Add(Int32, Int32)
Begin 000007fe9abcdef0, size 4
>>> 000007fe`9abcdef0 8d0411 lea eax,[rcx+rdx]
000007fe`9abcdef3 c3 ret
Все приведенные выше примеры работают в 64-битном режиме, но в 32-битном режимеМетод практически идентичен.