New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing the SOS -u command #34

Open
mattwarren opened this Issue Nov 19, 2015 · 5 comments

Comments

Projects
None yet
3 participants
@mattwarren

mattwarren commented Nov 19, 2015

I'm trying to use ClrMD to print out the assembly code of a method, as part of a Benchmarking library I'm working on

At the moment I use code similar to the Machine Code sample to get the memory address, then I use code like this to get the assembly code (where debugControl is of type IDebugControl from IDebugControl.cs):

var bufferSize = 500; // per-line
var lineOfAssembly = new StringBuilder(bufferSize);
ulong startOffset = startAddress, endOffset;
uint disassemblySize;
do
{
    var flags = DEBUG_DISASM.EFFECTIVE_ADDRESS; // DEBUG_DISASM.SOURCE_FILE_NAME | DEBUG_DISASM.SOURCE_LINE_NUMBER;
    var result = debugControl.Disassemble(startOffset, flags, lineOfAssembly, bufferSize, out disassemblySize, out endOffset);
    startOffset = endOffset;
    Console.WriteLine(lineOfAssembly.ToString());
} while (disassemblySize > 0 && endOffset <= endAddress);

That works okay and I get an output like so, but the call instructions aren't resolved to a method name, they just have the memory address:

image

However if I run the -u command in WinDbg, it's able to resolve the method name of the call instruction, even with JIT methods such as mscorwks!JIT_Throw.

Is there a way I can replicate this with ClrMD?

@mattwarren

This comment has been minimized.

Show comment
Hide comment
@mattwarren

mattwarren Nov 19, 2015

Just for reference, if I create a full memory dump of the same process, load it into WinDbg and then run the SOS command -u, I get the following method names resolved, i.e.:

mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)

Here's the full output:

000007fe`973a6e83 488b4d10        mov     rcx,qword ptr [rbp+10h]
000007fe`973a6e87 488b4908        mov     rcx,qword ptr [rcx+8]
000007fe`973a6e8b 8b11            mov     edx,dword ptr [rcx]
000007fe`973a6e8d 33d2            xor     edx,edx
000007fe`973a6e8f 488d4590        lea     rax,[rbp-70h]
000007fe`973a6e93 c4e17957c0      vxorpd  xmm0,xmm0,xmm0
000007fe`973a6e98 c4e17a7f00      vmovdqu xmmword ptr [rax],xmm0
000007fe`973a6e9d c4e17a7f4010    vmovdqu xmmword ptr [rax+10h],xmm0
000007fe`973a6ea3 48895020        mov     qword ptr [rax+20h],rdx
000007fe`973a6ea7 48894d90        mov     qword ptr [rbp-70h],rcx
000007fe`973a6eab 8b493c          mov     ecx,dword ptr [rcx+3Ch]
000007fe`973a6eae 894d98          mov     dword ptr [rbp-68h],ecx
000007fe`973a6eb1 89559c          mov     dword ptr [rbp-64h],edx
000007fe`973a6eb4 c745a002000000  mov     dword ptr [rbp-60h],2
000007fe`973a6ebb 488d4da8        lea     rcx,[rbp-58h]
000007fe`973a6ebf c4e17957c0      vxorpd  xmm0,xmm0,xmm0
000007fe`973a6ec4 c4e17a7f01      vmovdqu xmmword ptr [rcx],xmm0
000007fe`973a6ec9 c4e17a6f4590    vmovdqu xmm0,xmmword ptr [rbp-70h]
000007fe`973a6ecf c4e17a7f45c8    vmovdqu xmmword ptr [rbp-38h],xmm0
000007fe`973a6ed5 c4e17a6f45a0    vmovdqu xmm0,xmmword ptr [rbp-60h]
000007fe`973a6edb c4e17a7f45d8    vmovdqu xmmword ptr [rbp-28h],xmm0
000007fe`973a6ee1 488b4db0        mov     rcx,qword ptr [rbp-50h]
000007fe`973a6ee5 48894de8        mov     qword ptr [rbp-18h],rcx
000007fe`973a6ee9 488d4dc8        lea     rcx,[rbp-38h]
000007fe`973a6eed 48ba801169f5fe070000 mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
000007fe`973a6ef7 e814510a5e      call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)
000007fe`973a6efc 84c0            test    al,al
000007fe`973a6efe 742a            je      000007fe`973a6f2a
000007fe`973a6f00 488d4de0        lea     rcx,[rbp-20h]
000007fe`973a6f04 488b11          mov     rdx,qword ptr [rcx]
000007fe`973a6f07 488955b8        mov     qword ptr [rbp-48h],rdx
000007fe`973a6f0b 488b4908        mov     rcx,qword ptr [rcx+8]
000007fe`973a6f0f 48894dc0        mov     qword ptr [rbp-40h],rcx
000007fe`973a6f13 488d4dc8        lea     rcx,[rbp-38h]
000007fe`973a6f17 48ba801169f5fe070000 mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
000007fe`973a6f21 e8ea500a5e      call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)
000007fe`973a6f26 84c0            test    al,al
000007fe`973a6f28 75d6            jne     000007fe`973a6f00
000007fe`973a6f2a 488b4c2420      mov     rcx,qword ptr [rsp+20h]
000007fe`973a6f2f e811000000      call    000007fe`973a6f45 (BenchmarkDotNet.Samples.Framework.Framework_DictionaryVsIDictionary.DictionaryEnumeration(), mdToken: 000000000600008f)
``

mattwarren commented Nov 19, 2015

Just for reference, if I create a full memory dump of the same process, load it into WinDbg and then run the SOS command -u, I get the following method names resolved, i.e.:

mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)

Here's the full output:

000007fe`973a6e83 488b4d10        mov     rcx,qword ptr [rbp+10h]
000007fe`973a6e87 488b4908        mov     rcx,qword ptr [rcx+8]
000007fe`973a6e8b 8b11            mov     edx,dword ptr [rcx]
000007fe`973a6e8d 33d2            xor     edx,edx
000007fe`973a6e8f 488d4590        lea     rax,[rbp-70h]
000007fe`973a6e93 c4e17957c0      vxorpd  xmm0,xmm0,xmm0
000007fe`973a6e98 c4e17a7f00      vmovdqu xmmword ptr [rax],xmm0
000007fe`973a6e9d c4e17a7f4010    vmovdqu xmmword ptr [rax+10h],xmm0
000007fe`973a6ea3 48895020        mov     qword ptr [rax+20h],rdx
000007fe`973a6ea7 48894d90        mov     qword ptr [rbp-70h],rcx
000007fe`973a6eab 8b493c          mov     ecx,dword ptr [rcx+3Ch]
000007fe`973a6eae 894d98          mov     dword ptr [rbp-68h],ecx
000007fe`973a6eb1 89559c          mov     dword ptr [rbp-64h],edx
000007fe`973a6eb4 c745a002000000  mov     dword ptr [rbp-60h],2
000007fe`973a6ebb 488d4da8        lea     rcx,[rbp-58h]
000007fe`973a6ebf c4e17957c0      vxorpd  xmm0,xmm0,xmm0
000007fe`973a6ec4 c4e17a7f01      vmovdqu xmmword ptr [rcx],xmm0
000007fe`973a6ec9 c4e17a6f4590    vmovdqu xmm0,xmmword ptr [rbp-70h]
000007fe`973a6ecf c4e17a7f45c8    vmovdqu xmmword ptr [rbp-38h],xmm0
000007fe`973a6ed5 c4e17a6f45a0    vmovdqu xmm0,xmmword ptr [rbp-60h]
000007fe`973a6edb c4e17a7f45d8    vmovdqu xmmword ptr [rbp-28h],xmm0
000007fe`973a6ee1 488b4db0        mov     rcx,qword ptr [rbp-50h]
000007fe`973a6ee5 48894de8        mov     qword ptr [rbp-18h],rcx
000007fe`973a6ee9 488d4dc8        lea     rcx,[rbp-38h]
000007fe`973a6eed 48ba801169f5fe070000 mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
000007fe`973a6ef7 e814510a5e      call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)
000007fe`973a6efc 84c0            test    al,al
000007fe`973a6efe 742a            je      000007fe`973a6f2a
000007fe`973a6f00 488d4de0        lea     rcx,[rbp-20h]
000007fe`973a6f04 488b11          mov     rdx,qword ptr [rcx]
000007fe`973a6f07 488955b8        mov     qword ptr [rbp-48h],rdx
000007fe`973a6f0b 488b4908        mov     rcx,qword ptr [rcx+8]
000007fe`973a6f0f 48894dc0        mov     qword ptr [rbp-40h],rcx
000007fe`973a6f13 488d4dc8        lea     rcx,[rbp-38h]
000007fe`973a6f17 48ba801169f5fe070000 mov rdx,offset mscorlib_ni+0x6b1180 (000007fe`f5691180) (MT: System.Collections.Generic.Dictionary`2+Enumerator[[System.String, mscorlib],[System.String, mscorlib]])
000007fe`973a6f21 e8ea500a5e      call    mscorlib_ni+0x46c010 (000007fe`f544c010) (System.Collections.Generic.Dictionary`2+Enumerator[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].MoveNext(), mdToken: 0000000006006b95)
000007fe`973a6f26 84c0            test    al,al
000007fe`973a6f28 75d6            jne     000007fe`973a6f00
000007fe`973a6f2a 488b4c2420      mov     rcx,qword ptr [rsp+20h]
000007fe`973a6f2f e811000000      call    000007fe`973a6f45 (BenchmarkDotNet.Samples.Framework.Framework_DictionaryVsIDictionary.DictionaryEnumeration(), mdToken: 000000000600008f)
``
@leculver

This comment has been minimized.

Show comment
Hide comment
@leculver

leculver Dec 1, 2015

Contributor

Sorry for the (long) delay in responding. Things tend to be very slow around here from the end of November to January 1st. I have been on vacation.

IDebugControl doesn't know anything about CLR constructs. In fact, the implementation !u in SOS actually captures the output of IDebugControl::Disassemble, runs it through text processing, resolves references to managed code, and does inline text replacement. That's how SOS's !u works under-the-hood. If you want similar functionality you'll need to similarly parse the output of Disassemble and do the inline replacement yourself, mostly using ClrRuntime.GetMethodByAddress.

As for Disassemble resolving mscorwks!JIT_Throw or not: this isn't managed code. Whether Disassemble can resolve it or not depends entirely on whether you have mscorwks.pdb loaded into your instance of IDebugClient or not. This should be indexed on the public symbol server, so doing the equivalent of .sympath http://msdl.microsoft.com/download/symbols; .reload in the IDebug interfaces should get mscorwks!JIT_Throw (and similar).

Does that help at all?

Contributor

leculver commented Dec 1, 2015

Sorry for the (long) delay in responding. Things tend to be very slow around here from the end of November to January 1st. I have been on vacation.

IDebugControl doesn't know anything about CLR constructs. In fact, the implementation !u in SOS actually captures the output of IDebugControl::Disassemble, runs it through text processing, resolves references to managed code, and does inline text replacement. That's how SOS's !u works under-the-hood. If you want similar functionality you'll need to similarly parse the output of Disassemble and do the inline replacement yourself, mostly using ClrRuntime.GetMethodByAddress.

As for Disassemble resolving mscorwks!JIT_Throw or not: this isn't managed code. Whether Disassemble can resolve it or not depends entirely on whether you have mscorwks.pdb loaded into your instance of IDebugClient or not. This should be indexed on the public symbol server, so doing the equivalent of .sympath http://msdl.microsoft.com/download/symbols; .reload in the IDebug interfaces should get mscorwks!JIT_Throw (and similar).

Does that help at all?

@mattwarren

This comment has been minimized.

Show comment
Hide comment
@mattwarren

mattwarren Dec 4, 2015

Thanks for the reply, it's very helpful. It turns out that I'm actually already parsing the output in the same way it that SOS !u (based on your description), so that's cool. Although I was creating a lookup of method address -> name, I somehow missed ClrRuntime.GetMethodByAddress, so thanks for that.

Also thanks for the tips about the symbol paths, for anyone else who finds this issue I'm currently using code like this, which seems to work:

var symbols = dataTarget.DebuggerInterface as IDebugSymbols;
symbols.SetSymbolPath("http://msdl.microsoft.com/download/symbols");
var control = dataTarget.DebuggerInterface as IDebugControl;
control.Execute(DEBUG_OUTCTL.NOT_LOGGED, ".reload", DEBUG_EXECUTE.NOT_LOGGED);

mattwarren commented Dec 4, 2015

Thanks for the reply, it's very helpful. It turns out that I'm actually already parsing the output in the same way it that SOS !u (based on your description), so that's cool. Although I was creating a lookup of method address -> name, I somehow missed ClrRuntime.GetMethodByAddress, so thanks for that.

Also thanks for the tips about the symbol paths, for anyone else who finds this issue I'm currently using code like this, which seems to work:

var symbols = dataTarget.DebuggerInterface as IDebugSymbols;
symbols.SetSymbolPath("http://msdl.microsoft.com/download/symbols");
var control = dataTarget.DebuggerInterface as IDebugControl;
control.Execute(DEBUG_OUTCTL.NOT_LOGGED, ".reload", DEBUG_EXECUTE.NOT_LOGGED);
@ayende

This comment has been minimized.

Show comment
Hide comment
@ayende

ayende Oct 22, 2016

@mattwarren Is the disassembly code available?

ayende commented Oct 22, 2016

@mattwarren Is the disassembly code available?

@mattwarren

This comment has been minimized.

Show comment
Hide comment
@mattwarren

mattwarren Oct 26, 2016

@ayende Unfortunately I never finished the disassembly code, but if you want a working version take a look at the excellent msos library from @goldshtn.

It's built on-top of CLRMD and supports the !u cmd, see here https://github.com/goldshtn/msos/blob/master/msos/Disassemble.cs

mattwarren commented Oct 26, 2016

@ayende Unfortunately I never finished the disassembly code, but if you want a working version take a look at the excellent msos library from @goldshtn.

It's built on-top of CLRMD and supports the !u cmd, see here https://github.com/goldshtn/msos/blob/master/msos/Disassemble.cs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment