NetInverse Developers Blog

April 11, 2009
Category: Debugging — Tags: , , , , — admin @ 8:07 pm

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.

Category: Debugging — Tags: , , , , — admin @ 8:01 pm

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
Category: Debugging — Tags: , , , , — admin @ 5:13 pm

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
Category: Debugging — Tags: , , , , — admin @ 5:03 pm

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.

Category: Debugging — Tags: , , , , — admin @ 4:56 pm

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.

Category: Debugging — Tags: , , , , — admin @ 4:19 pm

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
Category: Debugging — Tags: , , , , — admin @ 4:13 pm

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
Category: Debugging — Tags: , , , , — admin @ 4:00 pm

SOS Command: !SyncBlk [-all | <syncblk number>]

A SyncBlock is a holder for extra information that doesn’t need to be created for every object. It can hold COM Interop data, HashCodes, and locking information for thread-safe operations.

When called without arguments, !SyncBlk will print the list of SyncBlocks corresponding to objects that are owned by a thread. For example, a

    lock(MyObject)
    {
        ....
    }

statement will set MyObject to be owned by the current thread. A SyncBlock will be created for MyObject, and the thread ownership information stored there (this is an oversimplification, see NOTE below). If another thread tries to execute the same code, they won’t be able to enter the block until the first thread exits.

This makes !SyncBlk useful for detecting managed deadlocks. Consider that the following code is executed by Threads A & B:

    Resource r1 = new Resource();
    Resource r2 = new Resource();
    ...
    lock(r1)                             lock(r2)
    {                                    {
        lock(r2)                             lock(r1)
        {                                    {
            ...                                  ...
        }                                    }
    }                                    }

This is a deadlock situation, as Thread A could take r1, and Thread B r2, leaving both threads with no option but to wait forever in the second lock statement. !SyncBlk will detect this with the following output:

0:003> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info   SyncBlock Owner
  238 001e40ec            3         1 001e4e60   e04   3   00a7a194 Resource
  239 001e4124            3         1 001e5980   ab8   4   00a7a1a4 Resource

It means that Thread e04 owns object 00a7a194, and Thread ab8 owns object 00a7a1a4. Combine that information with the call stacks of the deadlock: (threads 3 and 4 have similar output)

0:003> k

ChildEBP RetAddr
0404ea04 77f5c524 SharedUserData!SystemCallStub+0x4
0404ea08 77e75ee0 ntdll!NtWaitForMultipleObjects+0xc
0404eaa4 5d9de9d6 KERNEL32!WaitForMultipleObjectsEx+0x12c
0404eb38 5d9def80 mscorwks!Thread::DoAppropriateAptStateWait+0x156
0404ecc4 5d9dd8bb mscorwks!Thread::DoAppropriateWaitWorker+0x360
0404ed20 5da628dd mscorwks!Thread::DoAppropriateWait+0xbb
0404ede4 5da4e2e2 mscorwks!CLREvent::Wait+0x29d
0404ee70 5da4dd41 mscorwks!AwareLock::EnterEpilog+0x132
0404ef34 5da4efa3 mscorwks!AwareLock::Enter+0x2c1
0404f09c 5d767880 mscorwks!AwareLock::Contention+0x483
0404f1c4 03f00229 mscorwks!JITutil_MonContention+0x2c0
0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79
...

By looking at the code corresponding to Worker.Work()+0×79 (run “!u 03f00229″), you can see that thread 3 is attempting to acquire the Resource 00a7a1a4, which is owned by thread 4.

NOTE:

It is not always the case that a SyncBlock will be created for every object that is locked by a thread. In version 2.0 of the CLR and above, a mechanism called a ThinLock will be used if there is not already a SyncBlock for the object in question. ThinLocks will not be reported by the !SyncBlk command. You can use “!DumpHeap -thinlock” to list objects locked in this way.

Category: Debugging — Tags: , , , , — admin @ 3:48 pm

SOS Command: !Name2EE <module name> <type or method name>

This function allows you to turn a class name into a MethodTable and EEClass. It turns a method name into a MethodDesc. Here is an example for a method:

0:000> !name2ee unittest.exe MainClass.Main
Module: 001caa38
Token: 0x0600000d
MethodDesc: 00902f40
Name: MainClass.Main()
JITTED Code Address: 03ef00b8

and for a class:

0:000> !name2ee unittest!MainClass
Module: 001caa38
Token: 0x02000005
MethodTable: 009032d8
EEClass: 03ee1424
Name: MainClass

The module you are “browsing” with Name2EE needs to be loaded in the process. To get a type name exactly right, first browse the module with ILDASM. You can also pass * as the <module name> to search all loaded managed modules. <module name> can also be the debugger’s name for a module, such as mscorlib or image00400000.

The Windows Debugger syntax of <module>!<type> is also supported. You can use an asterisk on the left of the !, but the type on the right side needs to be fully qualified.

If you are looking for a way to display a static field of a class (and you don’t have an instance of the class, so !dumpobj won’t help you), note that once you have the EEClass, you can run !DumpClass, which will display the value of all static fields.

There is yet one more way to specify a module name. In the case of modules loaded from an assembly store (such as a SQL db) rather than disk, the module name will look like this: price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null For this kind of module, simply use price as the module name:

0:044> !name2ee price Price
Module: 10f028b0 (price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null)
Token: 0x02000002
MethodTable: 11a47ae0
EEClass: 11a538c8
Name: Price

Where are we getting these module names from? Run !DumpDomain to see a list of all loaded modules in all domains. And remember that you can browse all the types in a module with !DumpModule -mt <module pointer>. Note: Above information is compiled based on the SOS help.

Category: Debugging — Tags: , , , , , — admin @ 3:35 pm

SOS Command: !EEHeap [-gc] [-loader]

!EEHeap enumerates process memory consumed by internal CLR data structures. You can limit the output by passing “-gc” or “-loader”. All information will be displayed otherwise.

The information for the Garbage Collector lists the ranges of each Segment in the managed heap. This can be useful if you believe you have an object pointer. If the pointer falls within a segment range given by “!EEHeap -gc”, then you do have an object pointer, and can attempt to run “!DumpObj” on it.

Here is output for a simple program:

0:000> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x00a71018
generation 1 starts at 0x00a7100c
generation 2 starts at 0x00a71000

 segment    begin allocated     size
00a70000 00a71000  00a7e01c 0000d01c(53276)
Large object heap starts at 0x01a71000

 segment    begin allocated     size
01a70000 01a71000  01a76000 0x00005000(20480)

Total Size   0x1201c(73756)
------------------------------
GC Heap Size   0x1201c(73756)

So the total size of the GC Heap is only 72K. On a large web server, with multiple processors, you can expect to see a GC Heap of 400MB or more. The Garbage Collector attempts to collect and reclaim memory only when required to by memory pressure for better performance. You can also see the notion of “generations,” wherein the youngest objects live in generation 0, and long-lived objects eventually get “promoted” to generation 2. The loader output lists various private heaps associated with AppDomains. It also lists heaps associated with the JIT compiler, and heaps associated with Modules. For example:

0:000> !EEHeap -loader

Loader Heap:
--------------------------------------
System Domain: 5e0662a0
LowFrequencyHeap:008f0000(00002000:00001000) Size: 0x00001000 bytes.
HighFrequencyHeap:008f2000(00008000:00001000) Size: 0x00001000 bytes.
StubHeap:008fa000(00002000:00001000) Size: 0x00001000 bytes.

Total size: 0x3000(12288)bytes
--------------------------------------
Shared Domain: 5e066970
LowFrequencyHeap:00920000(00002000:00001000) 03e30000(00010000:00003000) Size: 0x00004000 bytes.
Wasted: 0x00001000 bytes.
HighFrequencyHeap:00922000(00008000:00001000) Size: 0x00001000 bytes.
StubHeap:0092a000(00002000:00001000) Size: 0x00001000 bytes.

Total size: 0x6000(24576)bytes
--------------------------------------
Domain 1: 14f000
LowFrequencyHeap:00900000(00002000:00001000) 03ee0000(00010000:00003000) Size: 0x00004000 bytes.
Wasted: 0x00001000 bytes.
HighFrequencyHeap:00902000(00008000:00003000) Size: 0x00003000 bytes.
StubHeap:0090a000(00002000:00001000) Size: 0x00001000 bytes.

Total size: 0x8000(32768)bytes
--------------------------------------
Jit code heap:
Normal JIT:03ef0000(00010000:00002000) Size: 0x00002000 bytes.

Total size: 0x2000(8192)bytes
--------------------------------------
Module Thunk heaps:
Module 5ba22410: Size: 0x00000000 bytes.
Module 001c1320: Size: 0x00000000 bytes.
Module 001c03f0: Size: 0x00000000 bytes.
Module 001caa38: Size: 0x00000000 bytes.

Total size: 0x0(0)bytes
--------------------------------------
Module Lookup Table heaps:
Module 5ba22410:Size: 0x00000000 bytes.
Module 001c1320:Size: 0x00000000 bytes.
Module 001c03f0:Size: 0x00000000 bytes.
Module 001caa38:03ec0000(00010000:00002000) Size: 0x00002000 bytes.

Total size: 0x2000(8192)bytes
--------------------------------------
Total LoaderHeap size: 0x15000(86016)bytes
=======================================

By using !EEHeap to keep track of the growth of these private heaps, we are able to rule out or include them as a source of a memory leak. Memory leak will cause OOM(Out of Memory) exception. You can inspect the modules from the above dump by using command !dumpmodule -mt 001c1320.

« Newer PostsOlder Posts »

©2009 NetInverse. All rights reserved. Powered by WordPress