SOS Command: !DumpIL
<Managed DynamicMethod object> |
<DynamicMethodDesc pointer> |
<MethodDesc pointer>
!DumpIL prints the IL code associated with a managed method. We added this function specifically to debug DynamicMethod code which was constructed on the fly. Happily it works for non-dynamic code as well.
You can use it in three ways:
- If you have a System.Reflection.Emit.DynamicMethod object, just pass the pointer as the first argument.
- If you have a DynamicMethodDesc pointer you can use that to print the IL associated with the dynamic method.
- If you have an ordinary MethodDesc, you can see the IL for that as well, just pass it as the first argument.
Note that dynamic IL is constructed a bit differently. Rather than referring to metadata tokens, the IL points to objects in a managed object array. Here is a simple example of the output for a dynamic method:
0:000> !dumpil b741dc
This is dynamic IL. Exception info is not reported at this time. If a token is unresolved, run “!do <addr>” on the addr given in parenthesis. You can also look at the token table yourself, by running “!DumpArray 00b77388″.
IL_0000: ldstr 70000002 "Inside invoked method "
IL_0005: call 6000003 System.Console.WriteLine(System.String)
IL_000a: ldc.i4.1
IL_000b: newarr 2000004 "System.Int32"
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: ret
SOS Command: !DumpSig <sigaddr> <moduleaddr>
SOS Command: !DumpMethodSig <sigaddr> <moduleaddr>
SOS Command: !DumpAssembly <Assembly address>
Example output:
0:000>!dumpdomain
...
0:000> !dumpassembly 1ca248
Parent Domain: 0014f000
Name: C:pubunittest.exe
ClassLoader: 001ca060
Module Name
001caa50 C:pubunittest.exe
An assembly can consist of multiple modules, and those will be listed. You can get an Assembly address from the output of !DumpDomain.
SOS Command: !ThreadPool
This command lists basic information about the ThreadPool, including the number of work requests in the queue, number of completion port threads, and number of timers.
!ThreadPool
CPU utilization 0%
Worker Thread: Total: 0 Running: 0 Idle: 0 MaxLimit: 0 MinLimit: 0
Work Request in Queue: 0
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 0 Free: 0 MaxFree: 0 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 0
SOS Command: !DumpModule [-mt] <Module address>
You can get a Module address from !DumpDomain, !DumpAssembly and other functions. Here is sample output:
0:000> !dumpmodule 1caa50
Name: C:pubunittest.exe
Attributes: PEFile
Assembly: 001ca248
LoaderHeap: 001cab3c
TypeDefToMethodTableMap: 03ec0010
TypeRefToMethodTableMap: 03ec0024
MethodDefToDescMap: 03ec0064
FieldDefToDescMap: 03ec00a4
MemberRefToDescMap: 03ec00e8
FileReferencesMap: 03ec0128
AssemblyReferencesMap: 03ec012c
MetaData start address: 00402230 (1888 bytes)
The Maps listed map metadata tokens to CLR data structures. Without going into too much detail, you can examine memory at those addresses to find the appropriate structures. For example, the TypeDefToMethodTableMap above can be examined:
0:000> dd 3ec0010
03ec0010 00000000 00000000 0090320c 0090375c
03ec0020 009038ec ...
This means TypeDef token 2 maps to a MethodTable with the value 0090320c. You can run !DumpMT to verify that. The MethodDefToDescMap takes a MethodDef token and maps it to a MethodDesc, which can be passed to !DumpMD.
There is a new option “-mt”, which will display the types defined in a module, and the types referenced by the module. For example:
0:000> !dumpmodule -mt 1aa580
Name: C:pubunittest.exe
...<etc>...
MetaData start address: 0040220c (1696 bytes)
Types defined in this module
MT TypeDef Name
------------------------------------------------------------------------------
030d115c 0x02000002 Funny
030d1228 0x02000003 Mainy
Types referenced in this module
MT TypeRef Name
------------------------------------------------------------------------------
030b6420 0x01000001 System.ValueType
030b5cb0 0x01000002 System.Object
030fceb4 0x01000003 System.Exception
0334e374 0x0100000c System.Console
03167a50 0x0100000e System.Runtime.InteropServices.GCHandle
0336a048 0x0100000f System.GC
SOS Command: !Token2EE <module name> <token>
This function allows you to turn a metadata token into a MethodTable or MethodDesc. Here is an example showing class tokens being resolved:
!token2ee unittest.exe 02000003
Module: 001caa38
Token: 0x02000003
MethodTable: 0090375c
EEClass: 03ee1ae0
Name: Bank
!token2ee image00400000 02000004
Module: 001caa38
Token: 0x02000004
MethodTable: 009038ec
EEClass: 03ee1b84
Name: Customer
The module you are “browsing” with Token2EE needs to be loaded in the process. This function doesn’t see much use, especially since a tool like ILDASM can show the mapping between metadata tokens and types/methods in a friendlier way. But it could be handy sometimes.
You can pass “*” for <module name> to find what that token maps to in every loaded managed module. <module name> can also be the debugger’s name for a module, such as mscorlib or image00400000.
SOS Command: !DumpMD <MethodDesc address>
This command lists information about a MethodDesc. You can use !IP2MD to turn a code address in a managed function into a MethodDesc:
!DumpMD 00933008
Method Name: FindProduct.Program.AppendProduct(System.Collections.Generic.List`1<FindProduct.Product>)
Class: 00931300
MethodTable: 00933024
mdToken: 06000002
Module: 00932c5c
IsJitted: yes
CodeAddr: 00ff00e8
If IsJitted is “yes,” you can run !U on the CodeAddr pointer to see a disassembly of the JITTED code. You can also call !DumpClass, !DumpMT, !DumpModule on the Class, MethodTable and Module fields above.
SOS Command: !DumpClass <EEClass address>
The EEClass is a data structure associated with an object type. !DumpClass will show attributes, as well as list the fields of the type. The output is similar to !DumpObj. Although static field values will be displayed, non-static values won’t because you need an instance of an object for that.
You can get an EEClass to look at from !DumpMT, !DumpObj, !Name2EE, and !Token2EE among others.
!dumpclass 00931300
Class Name: FindProduct.Program
mdToken: 02000002 (C:svnNetInverseFindProductbinDebugFindProduct.exe)
Parent Class: 790c3ef0
Module: 00932c5c
Method Table: 00933024
Vtable Slots: 4
Total Method Slots: 5
Class Attributes: 100000
NumInstanceFields: 0
NumStaticFields: 0
SOS Commmand: !DumpMT [-MD] <MethodTable address>
Examine a MethodTable. Each managed object has a MethodTable pointer at the start. If you pass the “-MD” flag, you’ll also see a list of all the methods defined on the object.
.load sos
...
!clrstack
...
OS Thread Id: 0x6f8 (1784)
ESP EIP
0012f3d4 00ff01b4 FindProduct.Program.AppendProduct(System.Collections.Generic.List`1<FindProduct.Product>)
...
!ip2md 00ff01b4
MethodDesc: 00933008
Method Name: FindProduct.Program.AppendProduct(System.Collections.Generic.List`1<FindProduct.Product>)
Class: 00931300
MethodTable: 00933024
...
!dumpmt 00933024
EEClass: 00931300
Module: 00932c5c
Name: FindProduct.Program
mdToken: 02000002 (C:svnNetInverseFindProductbinDebugFindProduct.exe)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 7