The Disassembly looks like:
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 method "methShort" is dynamically created in .NET using Reflection.Emit. It takes two Int32 parameters as "byRef" values. This is being debugged as a "release-mode" build.
I can step through the assembly right up to the "call" instruction. The contents of the memory pointed to by R8 and RDX (the parameters) look fine. I don't know what sort of magic allowed the JIT to use registers for the call instead of the stack, but that's beside the point.
When I attempt to "Step Into" the call instruction, the debugger "steps over" it instead. The routine is indeed called- the method performed its function correctly. But I cannot seem to disassemble nor step into the method.
At the point immediately before the call, RAX contains the value 00000000025C67A8h. When 18h is added to that, the address for the indirection becomes 00000000025C67C0h. The QWORD at this address is 000000001b64dc48h.
If I try to disassemble this address (000000001b64dc48h), the debugger comes back with "The specified address cannot be displayed. There is no code at the supplied location".
As a Hail Mary attempt, I tried disassembling the code at RAX without the indirection, but as I expected this failed as well.
Can anyone tell me how to get to whatever code is at the address, or if something akin to LEA needs to be performed on the address (RAX+18h) before disassembling the code there?
You need to keep in mind that the debugger is trying to save you from wasting several hours of your life. methShort()
is a delegate call, there still needs to be a lot of work done before that call can complete. You are not going to enjoy single-stepping through the jitter compiling your dynamic method to machine code, CAS checking the link demand, the CLR creating the delegate stub and binding it to the call site.
I'll answer the question as posted, the debugger won't show you the call target code because it is unmanaged code. You can tell from the address, far removed from the location of your jitted code. Convincing it that you want to see it requires several tricks:
Not otherwise likely to be useful to debug a dynamic method, albeit that I pretty quickly threw the towel when I tried it. You are probably ahead by calling the method twice so you can bypass all the overhead on the second call.
A completely different approach is to temporarily emit a call to Debugger.Break() into the method, now it is a lot easier.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With