Why can't I enter the call command during debugging / disassembling?

Disassembly is as follows:

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] 

The methShort method is dynamically created in .NET using Reflection.Emit. The "byRef" values ​​require two Int32 parameters. This is being debugged as a release mode assembly.

I can build up to the call statement. The memory contents pointed to by R8 and RDX (parameters) look great. I don't know what magic allowed JIT to use registers to call instead of the stack, but that is not the case.

When I try to execute the "Step Into" command, the debug command "steps over" it. The subroutine is really called - the method performed its function correctly. But I cannot understand and not enter into a method.

At the point immediately before the call, RAX contains the value 00000000025C67A8h. When 18h is added to it, the address for indirection becomes 00000000025C67C0h. QWORD at this address: 000000001b64dc48h.

If I try to parse this address (000000001b64dc48h), the debugger will return with "The specified address cannot be displayed. There is no code at the specified location".

As an attempt by Hail Mary, I tried to parse the code in RAX without indirectness, but, as I expected, this did not work either.

Can someone tell me how to get to any code on the address, or if something similar to LEA should be executed on the address (RAX + 18h) before disassembling the code there?

+8
x86-64 cil disassembly
source share
1 answer

You must remember that the debugger is trying to save you from losing several hours of your life. methShort() is a delegate call, but much work remains to be done to complete it. You will not like jitter step-by-step when compiling a dynamic method with machine code, CAS checking the connection request, CLR creating a delegate stub and linking it to the call site.

I will answer the question in the form in which it was published, the debugger will not show you the target call code, because it is unmanaged code. You can tell at an address remote from the location of your commented code. To convince you that you want to see this, you need a few tricks:

  • Project + Properties, Debug tab, check the option "Enable debugging of native code"
  • You must switch the debugger from managed to unmanaged mode. There is no explicit command for this, the easiest way I know how to do this is to use the Call Stack window. Double-click the bottom frame (__RtlUserThreadStart @ 8).
  • Click on the "View Disassembly" link in the "Source Unavailable" pop-up window to return to the "Disassembly" window. The debugger is now in unmanaged mode. Beware that you cannot easily say more with the new debugging engine, as it now displays the correct code addresses.
  • Now you can enter the address that you found in the Address field. Be sure to prefix it with "0x".

Otherwise, it is unlikely to be useful to debug the dynamic method, although I quickly threw the towel when I tried it. You are probably ahead by calling the method twice to get around all the costs of the second call.

A completely different approach is to temporarily send a call to the Debugger.Break () method to the method, now it is much simpler.

+7
source share

All Articles