Почему я не могу войти в инструкцию Call во время отладки / разборки?

Разборка выглядит так:

                methShort( ref x, ref y );
000007FF00163F67  lea         r8,[rsp+34h]  
000007FF00163F6C  lea         rdx,[rsp+30h]  
000007FF00163F71  mov         rcx,qword ptr [rsp+20h]  
000007FF00163F76  mov         rcx,qword ptr [rcx+8]  
000007FF00163F7A  mov         rax,qword ptr [rsp+20h]  
000007FF00163F7F  call        qword ptr [rax+18h]  

Метод "methShort" динамически создается в.NET с использованием Reflection.Emit. Он принимает два параметра Int32 в качестве значений byRef. Это отлаживается как сборка в режиме релиза.

Я могу пройтись по сборке прямо до инструкции "call". Содержимое памяти, на которую указывают R8 и RDX (параметры), выглядит хорошо. Я не знаю, какая магия позволила JIT использовать регистры для вызова вместо стека, но это не относится к делу.

Когда я пытаюсь "шагнуть в" инструкцию вызова, отладчик "переступает" ее. Процедура действительно называется - метод выполнял свою функцию правильно. Но я не могу разобрать или вступить в метод.

В точке непосредственно перед вызовом RAX содержит значение 00000000025C67A8h. Когда к этому добавляется 18h, адрес для переадресации становится 00000000025C67C0h. QWORD по этому адресу 000000001b64dc48h.

Если я пытаюсь разобрать этот адрес (000000001b64dc48h), отладчик возвращается с "Указанный адрес не может быть отображен. В указанном месте нет кода".

В качестве попытки Hail Mary я попытался разобрать код в RAX без косвенного обращения, но, как я и ожидал, это также не удалось.

Может кто-нибудь сказать мне, как добраться до того кода, который находится по адресу, или если что-то похожее на LEA должно быть выполнено по адресу (RAX+18h) перед тем, как разбирать код там?

1 ответ

Вы должны помнить, что отладчик пытается спасти вас от потери нескольких часов вашей жизни. methShort() это вызов делегата, но для его завершения еще предстоит проделать большую работу. Вы не будете наслаждаться пошаговым джиттером, компилирующим ваш динамический метод с машинным кодом, CAS, проверяющим требование соединения, CLR, создающим заглушку делегата и связывающим его с сайтом вызова.

Я отвечу на вопрос в том виде, в котором он был опубликован, отладчик не покажет вам целевой код вызова, потому что это неуправляемый код. Вы можете сказать по адресу, удаленному от места вашего закомментированного кода. Чтобы убедить вас в том, что вы хотите увидеть это, нужно несколько хитростей:

  • Project + Properties, вкладка Debug, отметьте опцию "Включить отладку собственного кода"
  • Вы должны переключить отладчик из управляемого в неуправляемый режим. Для этого нет явной команды, самый простой способ, которым я знаю, как это сделать - это использовать окно Call Stack. Дважды щелкните нижнюю рамку (__RtlUserThreadStart@8).
  • Нажмите на ссылку "Показать разборку" во всплывающем окне "Источник недоступен", чтобы вернуться в окно "Разборка". Отладчик теперь находится в неуправляемом режиме. Остерегайтесь, что вы не можете легко сказать больше с новым механизмом отладки, так как теперь он отображает правильные адреса кода.
  • Теперь вы можете ввести адрес, который вы обнаружили в поле Адрес. Не забудьте поставить "0x" перед ним.

В противном случае вряд ли будет полезно отлаживать динамический метод, хотя я довольно быстро бросил полотенце, когда попробовал его. Вы, вероятно, впереди, вызвав метод дважды, чтобы обойти все издержки при втором вызове. Попробуйте добавить в свой метод вызов Debugger.Break().

Другие вопросы по тегам