summaryrefslogtreecommitdiff
path: root/src/ToolBox/SOS/Strike/sosdocs.txt
diff options
context:
space:
mode:
Diffstat (limited to 'src/ToolBox/SOS/Strike/sosdocs.txt')
-rw-r--r--src/ToolBox/SOS/Strike/sosdocs.txt2600
1 files changed, 0 insertions, 2600 deletions
diff --git a/src/ToolBox/SOS/Strike/sosdocs.txt b/src/ToolBox/SOS/Strike/sosdocs.txt
deleted file mode 100644
index f03d0731f4..0000000000
--- a/src/ToolBox/SOS/Strike/sosdocs.txt
+++ /dev/null
@@ -1,2600 +0,0 @@
--------------------------------------------------------------------------------
-NOTE: THIS FILE CONTAINS SOS DOCUMENTATION. THE FORMAT OF THE FILE IS:
-
-<optional comments>
-COMMAND: <cmd name, all lower case>
-<descriptive text of the command>
-\\ <these are two backslashes, immediately followed by a newline>
-
-<repeat the sequence above>
-
-The first command is "contents" which is the general help screen. The rest
-correspond to SOS command names. This file is embedded as a resource in the SOS
-binary. Be sure to list any new commands here.
--------------------------------------------------------------------------------
-
-
-
-COMMAND: contents.
-SOS is a debugger extension DLL designed to aid in the debugging of managed
-programs. Functions are listed by category, then roughly in order of
-importance. Shortcut names for popular functions are listed in parenthesis.
-Type "!help <functionname>" for detailed info on that function.
-
-Object Inspection Examining code and stacks
------------------------------ -----------------------------
-DumpObj (do) Threads
-DumpArray (da) ThreadState
-DumpAsync IP2MD
-DumpDelegate U
-DumpStackObjects (dso) DumpStack
-DumpHeap EEStack
-DumpVC CLRStack
-GCRoot GCInfo
-ObjSize EHInfo
-FinalizeQueue BPMD
-PrintException (pe) COMState
-TraverseHeap
-
-Examining CLR data structures Diagnostic Utilities
------------------------------ -----------------------------
-DumpDomain VerifyHeap
-EEHeap VerifyObj
-Name2EE FindRoots
-SyncBlk HeapStat
-DumpMT GCWhere
-DumpClass ListNearObj (lno)
-DumpMD GCHandles
-Token2EE GCHandleLeaks
-EEVersion FinalizeQueue (fq)
-DumpModule FindAppDomain
-ThreadPool SaveModule
-DumpAssembly ProcInfo
-DumpSigElem StopOnException (soe)
-DumpRuntimeTypes DumpLog
-DumpSig VMMap
-RCWCleanupList VMStat
-DumpIL MinidumpMode
-DumpRCW AnalyzeOOM (ao)
-DumpCCW
-
-Examining the GC history Other
------------------------------ -----------------------------
-HistInit FAQ
-HistRoot
-HistObj
-HistObjFind
-HistClear
-\\
-
-COMMAND: faq.
->> Where can I get the right version of SOS for my build?
-
-If you are running version 1.1 or 2.0 of the CLR, SOS.DLL is installed in the
-same directory as the main CLR dll (CLR.DLL). Newer versions of the
-Windows Debugger provide a command to make it easy to load the right copy of
-SOS.DLL:
-
- ".loadby sos clr"
-
-That will load the SOS extension DLL from the same place that CLR.DLL is
-loaded in the process. You shouldn't attempt to use a version of SOS.DLL that
-doesn't match the version of CLR.DLL. You can find the version of
-CLR.DLL by running
-
- "lmvm clr"
-
-in the debugger. Note that if you are running CoreCLR (e.g. Silverlight)
-then you should replace "clr" with "coreclr".
-
-If you are using a dump file created on another machine, it is a little bit
-more complex. You need to make sure the mscordacwks.dll file that came with
-that install is on your symbol path, and you need to load the corresponding
-version of sos.dll (typing .load <full path to sos.dll> rather than using the
-.loadby shortcut). Within the Microsoft corpnet, we keep tagged versions
-of mscordacwks.dll, with names like mscordacwks_<architecture>_<version>.dll
-that the Windows Debugger can load. If you have the correct symbol path to the
-binaries for that version of the Runtime, the Windows Debugger will load the
-correct mscordacwks.dll file.
-
->> I have a chicken and egg problem. I want to use SOS commands, but the CLR
- isn't loaded yet. What can I do?
-
-In the debugger at startup you can type:
-
- "sxe clrn"
-
-Let the program run, and it will stop with the notice
-
- "CLR notification: module 'mscorlib' loaded"
-
-At this time you can use SOS commands. To turn off spurious notifications,
-type:
-
- "sxd clrn"
-
->> I got the following error message. Now what?
-
- 0:000> .loadby sos clr
- 0:000> !DumpStackObjects
- Failed to find runtime DLL (clr.dll), 0x80004005
- Extension commands need clr.dll in order to have something to do.
- 0:000>
-
-This means that the CLR is not loaded yet, or has been unloaded. You need to
-wait until your managed program is running in order to use these commands. If
-you have just started the program a good way to do this is to type
-
- bp clr!EEStartup "g @$ra"
-
-in the debugger, and let it run. After the function EEStartup is finished,
-there will be a minimal managed environment for executing SOS commands.
-
->> I have a partial memory minidump, and !DumpObj doesn't work. Why?
-
-In order to run SOS commands, many CLR data structures need to be traversed.
-When creating a minidump without full memory, special functions are called at
-dump creation time to bring those structures into the minidump, and allow a
-minimum set of SOS debugging commands to work. At this time, those commands
-that can provide full or partial output are:
-
-CLRStack
-Threads
-Help
-PrintException
-EEVersion
-
-For a minidump created with this minimal set of functionality in mind, you
-will get an error message when running any other commands. A full memory dump
-(obtained with ".dump /ma <filename>" in the Windows Debugger) is often the
-best way to debug a managed program at this level.
-
->> What other tools can I use to find my bug?
-
-Turn on Managed Debugging Assistants. These enable additional runtime diagnostics,
-particularly in the area of PInvoke/Interop. Adam Nathan has written some great
-information about that:
-
-http://blogs.msdn.com/adam_nathan/
-
->> Does SOS support DML?
-
-Yes. SOS respects the .prefer_dml option in the debugger. If this setting is
-turned on, then SOS will output DML by default. Alternatively, you may leave
-it off and add /D to the beginning of a command to get DML based output for it.
-Not all SOS commands support DML output.
-
-\\
-
-COMMAND: stoponexception.
-!StopOnException [-derived]
- [-create | -create2]
- <Exception>
- [<Pseudo-register number>]
-
-!StopOnException helps when you want the Windows Debugger to stop on a
-particular managed exception, say a System.OutOfMemoryException, but continue
-running if other exceptions are thrown. The command can be used in two ways:
-
-1) When you just want to stop on one particular CLR exception
-
- At the debugger prompt, anytime after loading SOS, type:
-
- !StopOnException -create System.OutOfMemoryException 1
-
- The pseudo-register number (1) indicates that SOS can use register $t1 for
- maintaining the breakpoint. The -create parameter allows SOS to go ahead
- and set up the breakpoint as a first-chance exception. -create2 would set
- it up as a 2nd-chance exception.
-
-2) When you need more complex logic for stopping on a CLR exception
-
- !StopOnException can be used purely as a predicate in a larger expression.
- If you type:
-
- !StopOnException System.OutOfMemoryException 3
-
- then register $t3 will be set to 1 if the last thrown exception on the
- current thread is a System.OutOfMemoryException. Otherwise, $t3 will be set
- to 0. Using the Windows Debugger scripting language, you could chain
- such calls together to stop on various exception types. You'll have to
- manually create such predicates, for example:
-
- sxe -c "!soe System.OutOfMemoryException 3;
- !soe -derived System.IOException 4;
- .if(@$t3==1 || @$t4==1) { .echo 'stop' } .else {g}"
-
-The -derived option will cause StopOnException to set the pseudo-register to
-1 even if the thrown exception type doesn't exactly match the exception type
-given, but merely derives from it. So, "-derived System.Exception" would catch
-every exception in the System.Exception heirarchy.
-
-The pseudo-register number is optional. If you don't pass a number, SOS will
-use pseudo-register $t1.
-
-Note that !PrintException with no parameters will print out the last thrown
-exception on the current thread (if any). You can use !soe as a shortcut for
-!StopOnException.
-\\
-
-COMMAND: minidumpmode.
-!MinidumpMode <0 or 1>
-
-Minidumps created with ".dump /m" or ".dump" have a very small set of
-CLR-specific data, just enough to run a subset of SOS commands correctly. You
-are able to run other SOS commands, but they may fail with unexpected errors
-because required areas of memory are not mapped in or only partially mapped
-in. At this time, SOS cannot reliably detect if a dump file is of this type
-(for one thing, custom dump commands can map in additional memory, but there
-is no facility to read meta-information about this memory). You can turn this
-option on to protect against running unsafe commands against small minidumps.
-
-By default, MinidumpMode is 0, so there is no restriction on commands that will
-run against a minidump.
-\\
-
-COMMAND: dumpobj.
-!DumpObj [-nofields] <object address>
-
-This command allows you to examine the fields of an object, as well as learn
-important properties of the object such as the EEClass, the MethodTable, and
-the size.
-
-You might find an object pointer by running !DumpStackObjects and choosing
-from the resultant list. Here is a simple object:
-
- 0:000> !DumpObj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type VT Attr Value Name
- 009038ec 4000008 4 Customer 0 instance 00a79ce4 name
- 009038ec 4000009 8 Bank 0 instance 00a79d2c bank
-
-Note that fields of type Customer and Bank are themselves objects, and you can
-run !DumpObj on them too. You could look at the field directly in memory using
-the offset given. "dd a79d40+8 l1" would allow you to look at the bank field
-directly. Be careful about using this to set memory breakpoints, since objects
-can move around in the garbage collected heap.
-
-What else can you do with an object? You might run !GCRoot, to determine what
-roots are keeping it alive. Or you can find all objects of that type with
-"!DumpHeap -type Customer".
-
-The column VT contains the value 1 if the field is a valuetype structure, and
-0 if the field contains a pointer to another object. For valuetypes, you can
-take the MethodTable pointer in the MT column, and the Value and pass them to
-the command !DumpVC.
-
-The abbreviation !do can be used for brevity.
-
-The arguments in detail:
--nofields: do not print fields of the object, useful for objects like
- String
-\\
-
-COMMAND: dumparray.
-!DumpArray
- [-start <startIndex>]
- [-length <length>]
- [-details]
- [-nofields]
- <array object address>
-
-This command allows you to examine elements of an array object.
-The arguments in detail:
- -start <startIndex>: optional, only supported for single dimension array.
- Specify from which index the command shows the elements.
- -length <length>: optional, only supported for single dimension array.
- Specify how many elements to show.
- -details: optional. Ask the command to print out details
- of the element using !DumpObj and !DumpVC format.
- -nofields: optional, only takes effect when -details is used. Do
- not print fields of the elements. Useful for arrays of
- objects like String
-
- Example output:
-
- 0:000> !dumparray -start 2 -length 3 -details 00ad28d0
- Name: Value[]
- MethodTable: 03e41044
- EEClass: 03e40fc0
- Size: 132(0x84) bytes
- Array: Rank 1, Number of elements 10, Type VALUETYPE
- Element Type: Value
- [2] 00ad28f0
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 2 x
- 5b9a628c 4000002 4 System.Int32 instance 4 y
- 5b9a628c 4000003 8 System.Int32 instance 6 z
- [3] 00ad28fc
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 3 x
- 5b9a628c 4000002 4 System.Int32 instance 6 y
- 5b9a628c 4000003 8 System.Int32 instance 9 z
- [4] 00ad2908
- Name: Value
- MethodTable 03e40f4c
- EEClass: 03ef1698
- Size: 20(0x14) bytes
- (C:\bugs\225271\arraytest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 5b9a628c 4000001 0 System.Int32 instance 4 x
- 5b9a628c 4000002 4 System.Int32 instance 8 y
- 5b9a628c 4000003 8 System.Int32 instance 12 z
-
-\\
-
-COMMAND: dumpasync.
-!DumpAsync [-addr <Object Address>]
- [-mt <MethodTable address>]
- [-type <partial type name>]
- [-tasks]
- [-completed]
- [-fields]
- [-stacks]
- [-roots]
-
-!DumpAsync traverses the garbage collected heap, looking for objects representing
-async state machines as created when an async method's state is transferred to the
-heap. This command recognizes async state machines defined as "async void", "async Task",
-"async Task<T>", "async ValueTask", and "async ValueTask<T>". It also optionally supports
-any other tasks.
-\\
-
-COMMAND: dumpstackobjects.
-!DumpStackObjects [-verify] [top stack [bottom stack]]
-
-This command will display any managed objects it finds within the bounds of
-the current stack. Combined with the stack tracing commands like K and
-!CLRStack, it is a good aid to determining the values of locals and
-parameters.
-
-If you use the -verify option, each non-static CLASS field of an object
-candidate is validated. This helps to eliminate false positives. It is not
-on by default because very often in a debugging scenario, you are
-interested in objects with invalid fields.
-
-The abbreviation !dso can be used for brevity.
-\\
-
-COMMAND: dumpdelegate.
-!DumpDelegate <delegate address>
-
-!DumpDelegate finds and outputs the one or more method descriptors associated with a delegate object.
-
-For example:
-
- 0:000> !dumpdelegate
- Target Method Name
- 000001461bacb0d8 00007ffc5c894b80 ConsoleApp16.Program.InstanceMethod()
- 000001461bacb098 00007ffc5c894b68 ConsoleApp16.Program.StaticMethod()
-\\
-
-COMMAND: dumpheap.
-!DumpHeap [-stat]
- [-strings]
- [-short]
- [-min <size>]
- [-max <size>]
- [-live]
- [-dead]
- [-thinlock]
- [-startAtLowerBound]
- [-mt <MethodTable address>]
- [-type <partial type name>]
- [start [end]]
-
-!DumpHeap is a powerful command that traverses the garbage collected heap,
-collection statistics about objects. With it's various options, it can look for
-particular types, restrict to a range, or look for ThinLocks (see !SyncBlk
-documentation). Finally, it will provide a warning if it detects excessive
-fragmentation in the GC heap.
-
-When called without options, the output is first a list of objects in the heap,
-followed by a report listing all the types found, their size and number:
-
- 0:000> !dumpheap
- Address MT Size
- 00a71000 0015cde8 12 Free
- 00a7100c 0015cde8 12 Free
- 00a71018 0015cde8 12 Free
- 00a71024 5ba58328 68
- 00a71068 5ba58380 68
- 00a710ac 5ba58430 68
- 00a710f0 5ba5dba4 68
- ...
- total 619 objects
- Statistics:
- MT Count TotalSize Class Name
- 5ba7607c 1 12 System.Security.Permissions.HostProtectionResource
- 5ba75d54 1 12 System.Security.Permissions.SecurityPermissionFlag
- 5ba61f18 1 12 System.Collections.CaseInsensitiveComparer
- ...
- 0015cde8 6 10260 Free
- 5ba57bf8 318 18136 System.String
- ...
-
-"Free" objects are simply regions of space the garbage collector can use later.
-If 30% or more of the heap contains "Free" objects, the process may suffer from
-heap fragmentation. This is usually caused by pinning objects for a long time
-combined with a high rate of allocation. Here is example output where !DumpHeap
-provides a warning about fragmentation:
-
- <After the Statistics section>
- Fragmented blocks larger than 1MB:
- Addr Size Followed by
- 00a780c0 1.5MB 00bec800 System.Byte[]
- 00da4e38 1.2MB 00ed2c00 System.Byte[]
- 00f16df0 1.2MB 01044338 System.Byte[]
-
-The arguments in detail:
-
--stat Restrict the output to the statistical type summary
--strings Restrict the output to a statistical string value summary
--short Limits output to just the address of each object. This allows you
- to easily pipe output from the command to another debugger
- command for automation.
--min Ignore objects less than the size given in bytes
--max Ignore objects larger than the size given in bytes
--live Only print live objects
--dead Only print dead objects (objects which will be collected in the
- next full GC)
--thinlock Report on any ThinLocks (an efficient locking scheme, see !SyncBlk
- documentation for more info)
--startAtLowerBound
- Force heap walk to begin at lower bound of a supplied address range.
- (During plan phase, the heap is often not walkable because objects
- are being moved. In this case, DumpHeap may report spurious errors,
- in particular bad objects. It may be possible to traverse more of
- the heap after the reported bad object. Even if you specify an
- address range, !DumpHeap will start its walk from the beginning of
- the heap by default. If it finds a bad object before the specified
- range, it will stop before displaying the part of the heap in which
- you are interested. This switch will force !DumpHeap to begin its
- walk at the specified lower bound. You must supply the address of a
- good object as the lower bound for this to work. Display memory at
- the address of the bad object to manually find the next method
- table (use !dumpmt to verify). If the GC is currently in a call to
- memcopy, You may also be able to find the next object's address by
- adding the size to the start address given as parameters.)
--mt List only those objects with the MethodTable given
--type List only those objects whose type name is a substring match of the
- string provided.
-start Begin listing from this address
-end Stop listing at this address
-
-A special note about -type: Often, you'd like to find not only Strings, but
-System.Object arrays that are constrained to contain Strings. ("new
-String[100]" actually creates a System.Object array, but it can only hold
-System.String object pointers). You can use -type in a special way to find
-these arrays. Just pass "-type System.String[]" and those Object arrays will
-be returned. More generally, "-type <Substring of interesting type>[]".
-
-The start/end parameters can be obtained from the output of !EEHeap -gc. For
-example, if you only want to list objects in the large heap segment:
-
- 0:000> !eeheap -gc
- Number of GC Heaps: 1
- generation 0 starts at 0x00c32754
- generation 1 starts at 0x00c32748
- generation 2 starts at 0x00a71000
- segment begin allocated size
- 00a70000 00a71000 010443a8 005d33a8(6108072)
- Large object heap starts at 0x01a71000
- segment begin allocated size
- 01a70000 01a71000 01a75000 0x00004000(16384)
- Total Size 0x5d73a8(6124456)
- ------------------------------
- GC Heap Size 0x5d73a8(6124456)
-
- 0:000> !dumpheap 1a71000 1a75000
- Address MT Size
- 01a71000 5ba88bd8 2064
- 01a71810 0019fe48 2032 Free
- 01a72000 5ba88bd8 4096
- 01a73000 0019fe48 4096 Free
- 01a74000 5ba88bd8 4096
- total 5 objects
- Statistics:
- MT Count TotalSize Class Name
- 0019fe48 2 6128 Free
- 5ba88bd8 3 10256 System.Object[]
- Total 5 objects
-
-Finally, if GC heap corruption is present, you may see an error like this:
-
- 0:000> !dumpheap -stat
- object 00a73d24: does not have valid MT
- curr_object : 00a73d24
- Last good object: 00a73d14
- ----------------
-
-That indicates a serious problem. See the help for !VerifyHeap for more
-information on diagnosing the cause.
-\\
-
-COMMAND: dumpvc.
-!DumpVC <MethodTable address> <Address>
-
-!DumpVC allows you to examine the fields of a value class. In C#, this is a
-struct, and lives on the stack or within an Object on the GC heap. You need
-to know the MethodTable address to tell SOS how to interpret the fields, as
-a value class is not a first-class object with it's own MethodTable as the
-first field. For example:
-
- 0:000> !DumpObj a79d98
- Name: Mainy
- MethodTable: 009032d8
- EEClass: 03ee1424
- Size: 28(0x1c) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000010 4 VALUETYPE instance 00a79d9c m_valuetype
- 009032d8 400000f 4 CLASS static 00a79d54 m_sExcep
-
-m_valuetype is a value type. The value in the MT column (0090320c) is the
-MethodTable for it, and the Value column provides the start address:
-
- 0:000> !DumpVC 0090320c 00a79d9c
- Name: Funny
- MethodTable 0090320c
- EEClass: 03ee14b8
- Size: 28(0x1c) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 0090320c 4000001 0 CLASS instance 00a743d8 signature
- 0090320c 4000002 8 System.Int32 instance 2345 m1
- 0090320c 4000003 10 System.Boolean instance 1 b1
- 0090320c 4000004 c System.Int32 instance 1234 m2
- 0090320c 4000005 4 CLASS instance 00a79d98 backpointer
-
-!DumpVC is quite a specialized function. Some managed programs make heavy use
-of value classes, while others do not.
-\\
-
-COMMAND: gcroot.
-!GCRoot [-nostacks] <Object address>
-
-!GCRoot looks for references (or roots) to an object. These can exist in four
-places:
-
- 1. On the stack
- 2. Within a GC Handle
- 3. In an object ready for finalization
- 4. As a member of an object found in 1, 2 or 3 above.
-
-First, all stacks will be searched for roots, then handle tables, and finally
-the freachable queue of the finalizer. Some caution about the stack roots:
-!GCRoot doesn't attempt to determine if a stack root it encountered is valid
-or is old (discarded) data. You would have to use !CLRStack and !U to
-disassemble the frame that the local or argument value belongs to in order to
-determine if it is still in use.
-
-Because people often want to restrict the search to gc handles and freachable
-objects, there is a -nostacks option.
-\\
-
-COMMAND: objsize.
-!ObjSize [<Object address>]
-
-With no parameters, !ObjSize lists the size of all objects found on managed
-threads. It also enumerates all GCHandles in the process, and totals the size
-of any objects pointed to by those handles. In calculating object size,
-!ObjSize includes the size of all child objects in addition to the parent.
-
-For example, !DumpObj lists a size of 20 bytes for this Customer object:
-
- 0:000> !do a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 009038ec 4000008 4 CLASS instance 00a79ce4 name
- 009038ec 4000009 8 CLASS instance 00a79d2c bank
- 009038ec 400000a c System.Boolean instance 1 valid
-
-but !ObjSize lists 152 bytes:
-
- 0:000> !ObjSize a79d40
- sizeof(00a79d40) = 152 ( 0x98) bytes (Customer)
-
-This is because a Customer points to a Bank, has a name, and the Bank points to
-an Address string. You can use !ObjSize to identify any particularly large
-objects, such as a managed cache in a web server.
-
-While running ObjSize with no arguments may point to specific roots that hold
-onto large amounts of memory it does not provide information regarding the
-amount of managed memory that is still alive. This is due to the fact that a
-number of roots can share a common subgraph, and that part will be reported in
-the size of all the roots that reference the subgraph.
-
-Please note the -aggregate parameter to !ObjSize has been removed. Please see
-'!DumpHeap -live' and '!DumpHeap -dead' for that functionality.
-
-\\
-
-COMMAND: finalizequeue.
-!FinalizeQueue [-detail] | [-allReady] [-short]
-
-This command lists the objects registered for finalization. Here is output from
-a simple program:
-
- 0:000> !finalizequeue
- SyncBlocks to be cleaned up: 0
- MTA Interfaces to be released: 0
- STA Interfaces to be released: 1
- generation 0 has 4 finalizable objects (0015bc90->0015bca0)
- generation 1 has 0 finalizable objects (0015bc90->0015bc90)
- generation 2 has 0 finalizable objects (0015bc90->0015bc90)
- Ready for finalization 0 objects (0015bca0->0015bca0)
- Statistics:
- MT Count TotalSize Class Name
- 5ba6cf78 1 24 Microsoft.Win32.SafeHandles.SafeFileHandle
- 5ba5db04 1 68 System.Threading.Thread
- 5ba73e28 2 112 System.IO.StreamWriter
- Total 4 objects
-
-The GC heap is divided into generations, and objects are listed accordingly. We
-see that only generation 0 (the youngest generation) has any objects registered
-for finalization. The notation "(0015bc90->0015bca0)" means that if you look at
-memory in that range, you'll see the object pointers that are registered:
-
-0:000> dd 15bc90 15bca0-4
-0015bc90 00a743f4 00a79f00 00a7b3d8 00a7b47c
-
-You could run !DumpObj on any of those pointers to learn more. In this example,
-there are no objects ready for finalization, presumably because they still have
-roots (You can use !GCRoot to find out). The statistics section provides a
-higher-level summary of the objects registered for finalization. Note that
-objects ready for finalization are also included in the statistics (if any).
-
-Specifying -short will inhibit any display related to SyncBlocks or RCWs.
-
-The arguments in detail:
-
--allReady Specifying this argument will allow for the display of all objects
- that are ready for finalization, whether they are already marked by
- the GC as such, or whether the next GC will. The objects that are
- not in the "Ready for finalization" list are finalizable objects that
- are no longer rooted. This option can be very expensive, as it
- verifies whether all the objects in the finalizable queues are still
- rooted or not.
--short Limits the output to just the address of each object. If used in
- conjunction with -allReady it enumerates all objects that have a
- finalizer that are no longer rooted. If used independently it lists
- all objects in the finalizable and "ready for finalization" queues.
--detail Will display extra information on any SyncBlocks that need to be
- cleaned up, and on any RuntimeCallableWrappers (RCWs) that await
- cleanup. Both of these data structures are cached and cleaned up by
- the finalizer thread when it gets a chance to run.
-\\
-
-COMMAND: printexception.
-!PrintException [-nested] [-lines] [-ccw] [<Exception object address>] [<CCW pointer>]
-
-This will format fields of any object derived from System.Exception. One of the
-more useful aspects is that it will format the _stackTrace field, which is a
-binary array. If _stackTraceString field is not filled in, that can be helpful
-for debugging. You can of course use !DumpObj on the same exception object to
-explore more fields.
-
-If called with no parameters, PrintException will look for the last outstanding
-exception on the current thread and print it. This will be the same exception
-that shows up in a run of !Threads.
-
-!PrintException will notify you if there are any nested exceptions on the
-current managed thread. (A nested exception occurs when you throw another
-exception within a catch handler already being called for another exception).
-If there are nested exceptions, you can re-run !PrintException with the
-"-nested" option to get full details on the nested exception objects. The
-!Threads command will also tell you which threads have nested exceptions.
-
-!PrintException can display source information if available, by specifying the
--lines command line argument.
-
-!PrintException prints the exception object corresponding to a given CCW pointer,
-which can be specified using the -ccw option.
-
-The abbreviation !pe can be used for brevity.
-\\
-
-COMMAND: traverseheap.
-!TraverseHeap [-xml] [-verify] <filename>
-
-!TraverseHeap writes out a file in a format understood by the CLR Profiler.
-You can download the CLR Profiler from this link:
-
-http://www.microsoft.com/downloads/details.aspx?FamilyId=86CE6052-D7F4-4AEB-
-9B7A-94635BEEBDDA&displaylang=en
-
-It creates a graphical display of the GC heap to help you analyze the state of
-your application.
-
-If you pass the -verify option it will do more sanity checking of the heap
-as it dumps it. Use this option if heap corruption is suspected.
-
-If you pass the "-xml" flag, the file is instead written out in an easy to
-understand xml format:
-
- <gcheap>
- <types>
- <type id="1" name="System.String">
- ...
- </types>
- <roots>
- <root kind="handle" address="0x00a73ff0"/>
- <root kind="stack" address="0x0069f0e0"/>
- ...
- </roots>
- <objects>
- <object address="0x00b73030" typeid="1" size="300"/>
- <object address="0x00b75054" typeid="5" size="20">
- <member address="0x00b75088" />
- ...
- </object>
- ...
- </objects>
- </gcheap>
-
-You can break into your process, load SOS, take a snapshot of your heap with
-this function, then continue.
-\\
-COMMAND: threadstate.
-!ThreadState value
-
-The !Threads command outputs, among other things, the state of the thread.
-This is a bit field which corresponds to various states the thread is in.
-To check the state of the thread, simply pass that bit field from the
-output of !Threads into !ThreadState.
-
-Example:
- 0:003> !Threads
- ThreadCount: 2
- UnstartedThread: 0
- BackgroundThread: 1
- PendingThread: 0
- DeadThread: 0
- Hosted Runtime: no
- PreEmptive GC Alloc Lock
- ID OSID ThreadOBJ State GC Context Domain Count APT Exception
- 0 1 250 0019b068 a020 Disabled 02349668:02349fe8 0015def0 0 MTA
- 2 2 944 001a6020 b220 Enabled 00000000:00000000 0015def0 0 MTA (Finalizer)
- 0:003> !ThreadState b220
- Legal to Join
- Background
- CLR Owns
- CoInitialized
- In Multi Threaded Apartment
-
-Possible thread states:
- Thread Abort Requested
- GC Suspend Pending
- User Suspend Pending
- Debug Suspend Pending
- GC On Transitions
- Legal to Join
- Yield Requested
- Hijacked by the GC
- Blocking GC for Stack Overflow
- Background
- Unstarted
- Dead
- CLR Owns
- CoInitialized
- In Single Threaded Apartment
- In Multi Threaded Apartment
- Reported Dead
- Fully initialized
- Task Reset
- Sync Suspended
- Debug Will Sync
- Stack Crawl Needed
- Suspend Unstarted
- Aborted
- Thread Pool Worker Thread
- Interruptible
- Interrupted
- Completion Port Thread
- Abort Initiated
- Finalized
- Failed to Start
- Detached
-\\
-COMMAND: threads.
-!Threads [-live] [-special]
-
-!Threads lists all the mananaged threads in the process.
-
--live: optional. Only print threads associated with a live thread.
--special: optional. With this switch, the command will display all the special
- threads created by CLR. Those threads might not be managed threads
- so they might not be shown in the first part of the command's
- output. Example of special threads include: GC threads (in
- concurrent GC and server GC), Debugger helper threads, Finalizer
- threads, AppDomain Unload threads, and Threadpool timer threads.
-
-Each thread has many attributes, many of which can be ignored. The important
-ones are discussed below:
-
-There are three ID columns:
-
-1) The debugger shorthand ID (When the runtime is hosted this column might
- display the special string "<<<<" when this internal thread object is not
- associated with any physical thread - this may happen when the host reuses
- the runtime internal thread object)
-2) The CLR Thread ID
-3) The OS thread ID.
-
-If PreEmptiveGC is enabled for a thread, then a garbage collection
-can occur while that thread is running. For example, if you break in while
-a managed thread is making a PInvoke call to a Win32 function, that thread
-will be in PreEmptive GC mode.
-
-The Domain column indicates what AppDomain the thread is currently executing
-in. You can pass this value to !DumpDomain to find out more.
-
-The APT column gives the COM apartment mode.
-
-Exception will list the last thrown exception (if any) for the thread. More
-details can be obtained by passing the pointer value to !PrintException. If
-you get the notation "(nested exceptions)", you can get details on those
-exceptions by switching to the thread in question, and running
-"!PrintException -nested".
-\\
-
-COMMAND: clrstack.
-!CLRStack [-a] [-l] [-p] [-n] [-f]
-!CLRStack [-a] [-l] [-p] [-i] [variable name] [frame]
-
-CLRStack attempts to provide a true stack trace for managed code only. It is
-handy for clean, simple traces when debugging straightforward managed
-programs. The -p parameter will show arguments to the managed function. The
--l parameter can be used to show information on local variables in a frame.
-SOS can't retrieve local names at this time, so the output for locals is in
-the format <local address> = <value>. The -a (all) parameter is a short-cut
-for -l and -p combined.
-
-The -f option (full mode) displays the native frames intermixing them with
-the managed frames and the assembly name and function offset for the managed
-frames.
-
-If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
-.lines or .symopt commands), SOS will look up the symbols for every managed
-frame and if successful will display the corresponding source file name and
-line number. The -n (No line numbers) parameter can be specified to disable
-this behavior.
-
-When you see methods with the name "[Frame:...", that indicates a transition
-between managed and unmanaged code. You could run !IP2MD on the return
-addresses in the call stack to get more information on each managed method.
-
-On x64 platforms, Transition Frames are not displayed at this time. To avoid
-heavy optimization of parameters and locals one can request the JIT compiler
-to not optimize functions in the managed app by creating a file myapp.ini
-(if your program is myapp.exe) in the same directory. Put the following lines
-in myapp.ini and re-run:
-
-[.NET Framework Debugging Control]
-GenerateTrackingInfo=1
-AllowOptimize=0
-
-The -i option is a new EXPERIMENTAL addition to CLRStack and will use the ICorDebug
-interfaces to display the managed stack and variables. With this option you can also
-view and expand arrays and fields for managed variables. If a stack frame number is
-specified in the command line, CLRStack will show you the parameters and/or locals
-only for that frame (provided you specify -l or -p or -a of course). If a variable
-name and a stack frame number are specified in the command line, CLRStack will show
-you the parameters and/or locals for that frame, and will also show you the fields
-for that variable name you specified. Here are some examples:
- !CLRStack -i -a : This will show you all parameters and locals for all frames
- !CLRStack -i -a 3 : This will show you all parameters and locals, for frame 3
- !CLRStack -i var1 0 : This will show you the fields of 'var1' for frame 0
- !CLRStack -i var1.abc 2 : This will show you the fields of 'var1', and expand
- 'var1.abc' to show you the fields of the 'abc' field,
- for frame 2.
- !CLRStack -i var1.[basetype] 0 : This will show you the fields of 'var1', and
- expand the base type of 'var1' to show you its
- fields.
- !CLRStack -i var1.[6] 0 : If 'var1' is an array, this will show you the element
- at index 6 in the array, along with its fields
-The -i options uses DML output for a better debugging experience, so typically you
-should only need to execute "!CLRStack -i", and from there, click on the DML
-hyperlinks to inspect the different managed stack frames and managed variables.
-\\
-
-COMMAND: ip2md.
-!IP2MD <Code address>
-
-Given an address in managed JITTED code, IP2MD attempts to find the MethodDesc
-associated with it. For example, this output from K:
-
- 0:000> K
- ChildEBP RetAddr
- 00a79c78 03ef02ab image00400000!Mainy.Top()+0xb
- 00a79c78 03ef01a6 image00400000!Mainy.Level(Int32)+0xb
- 00a79c78 5d3725a1 image00400000!Mainy.Main()+0xee
- 0012ea04 5d512f59 clr!CallDescrWorkerInternal+0x30
- 0012ee34 5d7946aa clr!CallDescrWorker+0x109
-
- 0:000> !IP2MD 03ef01a6
- MethodDesc: 00902f40
- Method Name: Mainy.Main()
- Class: 03ee1424
- MethodTable: 009032d8
- mdToken: 0600000d
- Module: 001caa38
- IsJitted: yes
- CodeAddr: 03ef00b8
- Source file: c:\Code\prj.mini\exc.cs @ 39
-
-We have taken a return address into Mainy.Main, and discovered information
-about that method. You could run !U, !DumpMT, !DumpClass, !DumpMD, or
-!DumpModule on the fields listed to learn more.
-
-The "Source line" output will only be present if the debugger can find the
-symbols for the managed module containing the given <code address>, and if the
-debugger is configured to load line number information.
-\\
-
-COMMAND: u.
-!U [-gcinfo] [-ehinfo] [-n] [-o] <MethodDesc address> | <Code address>
-
-Presents an annotated disassembly of a managed method when given a MethodDesc
-pointer for the method, or a code address within the method body. Unlike the
-debugger "U" function, the entire method from start to finish is printed,
-with annotations that convert metadata tokens to names.
-
- <example output>
- ...
- 03ef015d b901000000 mov ecx,0x1
- 03ef0162 ff156477a25b call dword ptr [mscorlib_dll+0x3c7764 (5ba27764)] (System.Console.InitializeStdOutError(Boolean), mdToken: 06000713)
- 03ef0168 a17c20a701 mov eax,[01a7207c] (Object: SyncTextWriter)
- 03ef016d 89442414 mov [esp+0x14],eax
-
-If you pass the -gcinfo flag, you'll get inline display of the GCInfo for
-the method. You can also obtain this information with the !GCInfo command.
-
-If you pass the -ehinfo flag, you'll get inline display of exception info
-for the method. (Beginning and end of try/finally/catch handlers, etc.).
-You can also obtain this information with the !EHInfo command.
-
-If you pass the -o flag, the byte offset of each instruction from the
-beginning of the method will be printed in addition to the absolute address of
-the instruction.
-
-If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
-.lines or .symopt commands), and if symbols are available for the managed
-module containing the method being examined, the output of the command will
-include the source file name and line number corresponding to the
-disassembly. The -n (No line numbers) flag can be specified to disable this
-behavior.
-
- <example output>
- ...
- c:\Code\prj.mini\exc.cs @ 38:
- 001b00b0 8b0d3020ab03 mov ecx,dword ptr ds:[3AB2030h] ("Break in debugger. When done type <Enter> to continue: ")
- 001b00b6 e8d5355951 call mscorlib_ni+0x8b3690 (51743690) (System.Console.Write(System.String), mdToken: 0600091b)
- 001b00bb 90 nop
-
- c:\Code\prj.mini\exc.cs @ 39:
- 001b00bc e863cdc651 call mscorlib_ni+0xf8ce24 (51e1ce24) (System.Console.ReadLine(), mdToken: 060008f6)
- >>> 001b00c1 90 nop
- ...
-\\
-
-COMMAND: dumpstack.
-!DumpStack [-EE] [-n] [top stack [bottom stack]]
-
-[x86 and x64 documentation]
-
-This command provides a verbose stack trace obtained by "scraping." Therefore
-the output is very noisy and potentially confusing. The command is good for
-viewing the complete call stack when "kb" gets confused. For best results,
-make sure you have valid symbols.
-
--EE will only show managed functions.
-
-If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
-.lines or .symopt commands), SOS will look up the symbols for every managed
-frame and if successful will display the corresponding source file name and
-line number. The -n (No line numbers) parameter can be specified to disable
-this behavior.
-
-You can also pass a stack range to limit the output. Use the debugger
-extension !teb to get the top and bottom stack values.
-
-\\
-
-COMMAND: eestack.
-!EEStack [-short] [-EE]
-
-This command runs !DumpStack on all threads in the process. The -EE option is
-passed directly to !DumpStack. The -short option tries to narrow down the
-output to "interesting" threads only, which is defined by
-
-1) The thread has taken a lock.
-2) The thread has been "hijacked" in order to allow a garbage collection.
-3) The thread is currently in managed code.
-
-See the documentation for !DumpStack for more info.
-\\
-
-COMMAND: ehinfo.
-!EHInfo (<MethodDesc address> | <Code address>)
-
-!EHInfo shows the exception handling blocks in a jitted method. For each
-handler, it shows the type, including code addresses and offsets for the clause
-block and the handler block. For a TYPED handler, this would be the "try" and
-"catch" blocks respectively.
-
-Sample output:
-
- 0:000> !ehinfo 33bbd3a
- MethodDesc: 03310f68
- Method Name: MainClass.Main()
- Class: 03571358
- MethodTable: 0331121c
- mdToken: 0600000b
- Module: 001e2fd8
- IsJitted: yes
- CodeAddr: 033bbca0
-
- EHHandler 0: TYPED catch(System.IO.FileNotFoundException)
- Clause: [033bbd2b, 033bbd3c] [8b, 9c]
- Handler: [033bbd3c, 033bbd50] [9c, b0]
-
- EHHandler 1: FINALLY
- Clause: [033bbd83, 033bbda3] [e3, 103]
- Handler: [033bbda3, 033bbdc5] [103, 125]
-
- EHHandler 2: TYPED catch(System.Exception)
- Clause: [033bbd7a, 033bbdc5] [da, 125]
- Handler: [033bbdc5, 033bbdd6] [125, 136]
-
-\\
-
-COMMAND: gcinfo.
-!GCInfo (<MethodDesc address> | <Code address>)
-
-!GCInfo is especially useful for CLR Devs who are trying to determine if there
-is a bug in the JIT Compiler. It parses the GCEncoding for a method, which is a
-compressed stream of data indicating when registers or stack locations contain
-managed objects. It is important to keep track of this information, because if
-a garbage collection occurs, the collector needs to know where roots are so it
-can update them with new object pointer values.
-
-Here is sample output where you can see the change in register state. Normally
-you would print this output out and read it alongside a disassembly of the
-method. For example, the notation "reg EDI becoming live" at offset 0x11 of the
-method might correspond to a "mov edi,ecx" statement.
-
- 0:000> !gcinfo 5b68dbb8 (5b68dbb8 is the start of a JITTED method)
- entry point 5b68dbb8
- preJIT generated code
- GC info 5b9f2f09
- Method info block:
- method size = 0036
- prolog size = 19
- epilog size = 8
- epilog count = 1
- epilog end = yes
- saved reg. mask = 000B
- ebp frame = yes
- fully interruptible=yes
- double align = no
- security check = no
- exception handlers = no
- local alloc = no
- edit & continue = no
- varargs = no
- argument count = 4
- stack frame size = 1
- untracked count = 5
- var ptr tab count = 0
- epilog at 002E
- 36 D4 8C C7 AA |
- 93 F3 40 05 |
-
- Pointer table:
- 14 | [EBP+14H] an untracked local
- 10 | [EBP+10H] an untracked local
- 0C | [EBP+0CH] an untracked local
- 08 | [EBP+08H] an untracked local
- 44 | [EBP-04H] an untracked local
- F1 79 | 0011 reg EDI becoming live
- 72 | 0013 reg ESI becoming live
- 83 | 0016 push ptr 0
- 8B | 0019 push ptr 1
- 93 | 001C push ptr 2
- 9B | 001F push ptr 3
- 56 | 0025 reg EDX becoming live
- 4A | 0027 reg ECX becoming live
- 0E | 002D reg ECX becoming dead
- 10 | 002D reg EDX becoming dead
- E0 | 002D pop 4 ptrs
- F0 31 | 0036 reg ESI becoming dead
- 38 | 0036 reg EDI becoming dead
- FF |
-
-This function is important for CLR Devs, but very difficult for anyone else to
-make sense of it. You would usually come to use it if you suspect a gc heap
-corruption bug caused by invalid GCEncoding for a particular method.
-\\
-
-COMMAND: comstate.
-!COMState
-
-!COMState lists the com apartment model for each thread, as well as a Context
-pointer if provided.
-\\
-
-COMMAND: bpmd.
-!BPMD [-nofuturemodule] <module name> <method name> [<il offset>]
-!BPMD <source file name>:<line number>
-!BPMD -md <MethodDesc>
-!BPMD -list
-!BPMD -clear <pending breakpoint number>
-!BPMD -clearall
-
-!BPMD provides managed breakpoint support. If it can resolve the method name
-to a loaded, jitted or ngen'd function it will create a breakpoint with "bp".
-If not then either the module that contains the method hasn't been loaded yet
-or the module is loaded, but the function is not jitted yet. In these cases,
-!bpmd asks the Windows Debugger to receive CLR Notifications, and waits to
-receive news of module loads and JITs, at which time it will try to resolve
-the function to a breakpoint. -nofuturemodule can be used to suppress
-creating a breakpoint against a module that has not yet been loaded.
-
-Management of the list of pending breakpoints can be done via !BPMD -list,
-!BPMD -clear, and !BPMD -clearall commands. !BPMD -list generates a list of
-all of the pending breakpoints. If the pending breakpoint has a non-zero
-module id, then that pending breakpoint is specific to function in that
-particular loaded module. If the pending breakpoint has a zero module id, then
-the breakpoint applies to modules that have not yet been loaded. Use
-!BPMD -clear or !BPMD -clearall to remove pending breakpoints from the list.
-
-This brings up a good question: "I want to set a breakpoint on the main
-method of my application. How can I do this?"
-
- 1) If you know the full path to SOS, use this command and skip to step 6
- .load <the full path to sos.dll>
-
- 2) If you don't know the full path to sos, its usually next to clr.dll
- You can wait for clr to load and then find it.
- Start the debugger and type:
- sxe -c "" clrn
- 3) g
- 4) You'll get the following notification from the debugger:
- "CLR notification: module 'mscorlib' loaded"
- 5) Now you can load SOS. Type
- .loadby sos clr
-
- 6) Add the breakpoint with command such as:
- !bpmd myapp.exe MyApp.Main
- 7) g
- 8) You will stop at the start of MyApp.Main. If you type "bl" you will
- see the breakpoint listed.
-
-You can specify breakpoints by file and line number if:
- a) You have some version of .NET Framework installed on your machine. Any OS from
- Vista onwards should have .NET Framework installed by default.
- b) You have PDBs for the managed modules that need breakpoints, and your symbol
- path points to those PDBs.
-This is often easier than module and method name syntax. For example:
- !bpmd Demo.cs:15
-
-
-To correctly specify explicitly implemented methods make sure to retrieve the
-method name from the metadata, or from the output of the "!dumpmt -md" command.
-For example:
-
- public interface I1
- {
- void M1();
- }
- public class ExplicitItfImpl : I1
- {
- ...
- void I1.M1() // this method's name is 'I1.M1'
- { ... }
- }
-
- !bpmd myapp.exe ExplicitItfImpl.I1.M1
-
-
-!BPMD works equally well with generic types. Adding a breakpoint on a generic
-type sets breakpoints on all already JIT-ted generic methods and sets a pending
-breakpoint for any instantiation that will be JIT-ted in the future.
-
-Example for generics:
- Given the following two classes:
-
- class G3<T1, T2, T3>
- {
- ...
- public void F(T1 p1, T2 p2, T3 p3)
- { ... }
- }
-
- public class G1<T> {
- // static method
- static public void G<W>(W w)
- { ... }
- }
-
- One would issue the following commands to set breapoints on G3.F() and
- G1.G():
-
- !bpmd myapp.exe G3`3.F
- !bpmd myapp.exe G1`1.G
-
-And for explicitly implemented methods on generic interfaces:
- public interface IT1<T>
- {
- void M1(T t);
- }
-
- public class ExplicitItfImpl<U> : IT1<U>
- {
- ...
- void IT1<U>.M1(U u) // this method's name is 'IT1<U>.M1'
- { ... }
- }
-
- !bpmd bpmd.exe ExplicitItfImpl`1.IT1<U>.M1
-
-Additional examples:
- If IT1 and ExplicitItfImpl are types declared inside another class,
- Outer, the bpmd command would become:
-
- !bpmd bpmd.exe Outer+ExplicitItfImpl`1.Outer.IT1<U>.M1
-
- (note that the fully qualified type name for ExplicitItfImpl became
- Outer+ExplicitItfImpl, using the '+' separator, while the method name
- is Outer.IT1<U>.M1, using a '.' as the separator)
-
- Furthermore, if the Outer class resides in a namespace, NS, the bpmd
- command to use becomes:
-
- !bpmd bpmd.exe NS.Outer+ExplicitItfImpl`1.NS.Outer.IT1<U>.M1
-
-!BPMD does not accept offsets nor parameters in the method name. You can add
-an IL offset as an optional parameter seperate from the name. If there are overloaded
-methods, !bpmd will set a breakpoint for all of them.
-
-In the case of hosted environments such as SQL, the module name may be
-complex, like 'price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.
-For this case, just be sure to surround the module name with single quotes,
-like:
-
-!bpmd 'price, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' Price.M2
-
-\\
-
-COMMAND: dumpdomain.
-!DumpDomain [<Domain address>]
-
-When called with no parameters, !DumpDomain will list all the AppDomains in the
-process. It enumerates each Assembly loaded into those AppDomains as well.
-In addition to your application domain, and any domains it might create, there
-are two special domains: the Shared Domain and the System Domain.
-
-Any Assembly pointer in the output can be passed to !DumpAssembly. Any Module
-pointer in the output can be passed to !DumpModule. Any AppDomain pointer can
-be passed to !DumpDomain to limit output only to that AppDomain. Other
-functions provide an AppDomain pointer as well, such as !Threads where it lists
-the current AppDomain for each thread.
-\\
-
-COMMAND: eeheap.
-!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.
-\\
-
-COMMAND: name2ee.
-!Name2EE <module name> <type or method name>
-!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>.
-\\
-
-COMMAND: syncblk.
-!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 clr!Thread::DoAppropriateAptStateWait+0x156
- 0404ecc4 5d9dd8bb clr!Thread::DoAppropriateWaitWorker+0x360
- 0404ed20 5da628dd clr!Thread::DoAppropriateWait+0xbb
- 0404ede4 5da4e2e2 clr!CLREvent::Wait+0x29d
- 0404ee70 5da4dd41 clr!AwareLock::EnterEpilog+0x132
- 0404ef34 5da4efa3 clr!AwareLock::Enter+0x2c1
- 0404f09c 5d767880 clr!AwareLock::Contention+0x483
- 0404f1c4 03f00229 clr!JITutil_MonContention+0x2c0
- 0404f1f4 5b6ef077 image00400000!Worker.Work()+0x79
- ...
-
-By looking at the code corresponding to Worker.Work()+0x79 (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.
-\\
-
-COMMAND: dumpmt.
-!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.
-\\
-
-COMMAND: dumpclass.
-!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.
-\\
-
-COMMAND: dumpmd.
-!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:
-
- 0:000> !dumpmd 902f40
- Method Name: Mainy.Main()
- Class: 03ee1424
- MethodTable: 009032d8
- mdToken: 0600000d
- Module: 001caa78
- IsJitted: yes
- CodeAddr: 03ef00b8
-
-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.
-\\
-
-COMMAND: token2ee.
-!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:
-
- 0:000> !token2ee unittest.exe 02000003
- Module: 001caa38
- Token: 0x02000003
- MethodTable: 0090375c
- EEClass: 03ee1ae0
- Name: Bank
- 0:000> !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.
-\\
-
-COMMAND: eeversion.
-!EEVersion
-
-This prints the Common Language Runtime version. It also tells you if the code
-is running in "Workstation" or "Server" mode, a distinction which affects the
-garbage collector. The most apparent difference in the debugger is that in
-"Server" mode there is one dedicated garbage collector thread per CPU.
-
-A handy supplement to this function is to also run "lm v m clr". That
-will provide more details about the CLR, including where clr.dll is
-loaded from.
-\\
-
-COMMAND: dumpmodule.
-!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:\pub\unittest.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:\pub\unittest.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
-
-\\
-
-COMMAND: threadpool.
-!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.
-\\
-
-COMMAND: dumpassembly.
-!DumpAssembly <Assembly address>
-
-Example output:
-
- 0:000> !dumpassembly 1ca248
- Parent Domain: 0014f000
- Name: C:\pub\unittest.exe
- ClassLoader: 001ca060
- Module Name
- 001caa50 C:\pub\unittest.exe
-
-An assembly can consist of multiple modules, and those will be listed. You can
-get an Assembly address from the output of !DumpDomain.
-\\
-
-COMMAND: dumpruntimetypes.
-!DumpRuntimeTypes
-
-!DumpRuntimeTypes finds all System.RuntimeType objects in the gc heap and
-prints the type name and MethodTable they refer too. Sample output:
-
- Address Domain MT Type Name
- ------------------------------------------------------------------------------
- a515f4 14a740 5baf8d28 System.TypedReference
- a51608 14a740 5bb05764 System.Globalization.BaseInfoTable
- a51958 14a740 5bb05b24 System.Globalization.CultureInfo
- a51a44 14a740 5bb06298 System.Globalization.GlobalizationAssembly
- a51de0 14a740 5bb069c8 System.Globalization.TextInfo
- a56b98 14a740 5bb12d28 System.Security.Permissions.HostProtectionResource
- a56bbc 14a740 5baf7248 System.Int32
- a56bd0 14a740 5baf3fdc System.String
- a56cfc 14a740 5baf36a4 System.ValueType
- ...
-
-This command will print a "?" in the domain column if the type is loaded into multiple
-AppDomains. For example:
-
- 0:000> !DumpRuntimeTypes
- Address Domain MT Type Name
- ------------------------------------------------------------------------------
- 28435a0 ? 3f6a8c System.TypedReference
- 28435b4 ? 214d6c System.ValueType
- 28435c8 ? 216314 System.Enum
- 28435dc ? 2147cc System.Object
- 284365c ? 3cd57c System.IntPtr
- 2843670 ? 3feaac System.Byte
- 2843684 ? 23a544c System.IEquatable`1[[System.IntPtr, mscorlib]]
- 2843784 ? 3c999c System.Int32
- 2843798 ? 3caa04 System.IEquatable`1[[System.Int32, mscorlib]]
-
-\\
-
-COMMAND: dumpsig.
-!DumpSig <sigaddr> <moduleaddr>
-
-This command dumps the signature of a method or field given by <sigaddr>. This is
-useful when you are debugging parts of the runtime which returns a raw PCCOR_SIGNATURE
-structure and need to know what its contents are.
-
-Sample output for a method:
- 0:000> !dumpsig 0x000007fe`ec20879d 0x000007fe`eabd1000
- [DEFAULT] [hasThis] Void (Boolean,String,String)
-
-The first section of the output is the calling convention. This includes, but is not
-limited to, "[DEFAULT]", "[C]", "[STDCALL]", "[THISCALL]", and so on. The second
-portion of the output is either "[hasThis]" or "[explicit]" for whether the method
-is an instance method or a static method respectively. The third portion of the
-output is the return value (in this case a "void"). Finally, the method's arguments
-are printed as the final portion of the output.
-
-Sample output for a field:
- 0:000> !dumpsig 0x000007fe`eb7fd8cd 0x000007fe`eabd1000
- [FIELD] ValueClass System.RuntimeTypeHandle
-
-!DumpSig will also work with generics. Here is the output for the following
-function:
- public A Test(IEnumerable<B> n)
-
- 0:000> !dumpsig 00000000`00bc2437 000007ff00043178
- [DEFAULT] [hasThis] __Canon (Class System.Collections.Generic.IEnumerable`1<__Canon>)
-
-\\
-
-COMMAND: dumpsigelem.
-!DumpSigElem <sigaddr> <moduleaddr>
-
-This command dumps a single element of a signature object. For most circumstances,
-you should use !DumpSig to look at individual signature objects, but if you find a
-signature that has been corrupted in some manner you can use !DumpSigElem to read out
-the valid portions of it.
-
-If we look at a valid signature object for a method we see the following:
- 0:000> !dumpsig 0x000007fe`ec20879d 0x000007fe`eabd1000
- [DEFAULT] [hasThis] Void (Boolean,String,String)
-
-We can look at the individual elements of this object by adding the offsets into the
-object which correspond to the return value and parameters:
- 0:000> !dumpsigelem 0x000007fe`ec20879d+2 0x000007fe`eabd1000
- Void
- 0:000> !dumpsigelem 0x000007fe`ec20879d+3 0x000007fe`eabd1000
- Boolean
- 0:000> !dumpsigelem 0x000007fe`ec20879d+4 0x000007fe`eabd1000
- String
- 0:000> !dumpsigelem 0x000007fe`ec20879d+5 0x000007fe`eabd1000
- String
-
-We can do something similar for fields. Here is the full signature of a field:
- 0:000> !dumpsig 0x000007fe`eb7fd8cd 0x000007fe`eabd1000
- [FIELD] ValueClass System.RuntimeTypeHandle
-
-Using !DumpSigElem we can find the type of the field by adding the offset of it (1) to
-the address of the signature:
- 0:000> !dumpsigelem 0x000007fe`eb7fd8cd+1 0x000007fe`eabd1000
- ValueClass System.RuntimeTypeHandle
-
-!DumpSigElem will also work with generics. Let a function be defined as follows:
- public A Test(IEnumerable<B> n)
-
-The elements of this signature can be obtained by adding offsets into the signature
-when calling !DumpSigElem:
-
- 0:000> !dumpsigelem 00000000`00bc2437+2 000007ff00043178
- __Canon
- 0:000> !dumpsigelem 00000000`00bc2437+4 000007ff00043178
- Class System.Collections.Generic.IEnumerable`1<__Canon>
-
-The actual offsets that you should add are determined by the contents of the
-signature itself. By trial and error you should be able to find various elements
-of the signature.
-
-\\
-
-COMMAND: rcwcleanuplist.
-!RCWCleanupList [address]
-
-A RuntimeCallableWrapper is an internal CLR structure used to host COM objects
-which are exposed to managed code. This is exposed to managed code through the
-System.__ComObject class, and when objects of this type are collected, and a
-reference to the underlying COM object is no longer needed, the corresponding
-RCW is cleaned up. If you are trying to debug an issue related to one of these
-RCWs, then you can use the !RCWCleanupList function to display which COM objects
-will be released the next time a cleanup occurs.
-
-If given an address, this function will display the RCWCleanupList at that address.
-If no address is specified, it displays the default cleanup list, printing the
-wrapper, the context, and the thread of the object.
-
-Example:
- 0:002> !rcwcleanuplist 001c04d0
- RuntimeCallableWrappers (RCW) to be cleaned:
- RCW CONTEXT THREAD Apartment
- 1d54e0 192008 181180 STA
- 1d4140 192178 0 MTA
- 1dff50 192178 0 MTA
- MTA Interfaces to be released: 2
- STA Interfaces to be released: 1
-
-Note that CLR keeps track of which RCWs are bound to which managed objects through
-the SyncBlock of the object. As such, you can see more information about RCW
-objects through the !SyncBlk command. You can find more information about RCW
-cleanup through the !FinalizeQueue command.
-
-\\
-
-COMMAND: dumpil.
-!DumpIL <Managed DynamicMethod object> |
- <DynamicMethodDesc pointer> |
- <MethodDesc pointer> |
- /i <IL 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 four ways:
-
- 1) If you have a System.Reflection.Emit.DynamicMethod object, just pass
- the pointer as the first argument.
- 2) If you have a DynamicMethodDesc pointer you can use that to print the
- IL associated with the dynamic method.
- 3) If you have an ordinary MethodDesc, you can see the IL for that as well,
- just pass it as the first argument.
- 4) If you have a pointer directly to the IL, specify /i followed by the
- the IL address. This is useful for writers of profilers that instrument
- IL.
-
-
-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
-
-\\
-
-COMMAND: verifyheap.
-!VerifyHeap
-
-!VerifyHeap is a diagnostic tool that checks the garbage collected heap for
-signs of corruption. It walks objects one by one in a pattern like this:
-
- o = firstobject;
- while(o != endobject)
- {
- o.ValidateAllFields();
- o = (Object *) o + o.Size();
- }
-
-If an error is found, !VerifyHeap will report it. I'll take a perfectly good
-object and corrupt it:
-
- 0:000> !DumpObj a79d40
- Name: Customer
- MethodTable: 009038ec
- EEClass: 03ee1b84
- Size: 20(0x14) bytes
- (C:\pub\unittest.exe)
- Fields:
- MT Field Offset Type Attr Value Name
- 009038ec 4000008 4 CLASS instance 00a79ce4 name
- 009038ec 4000009 8 CLASS instance 00a79d2c bank
- 009038ec 400000a c System.Boolean instance 1 valid
-
- 0:000> ed a79d40+4 01 (change the name field to the bogus pointer value 1)
- 0:000> !VerifyHeap
- object 01ee60dc: bad member 00000003 at 01EE6168
- Last good object: 01EE60C4.
-
-If this gc heap corruption exists, there is a serious bug in your own code or
-in the CLR. In user code, an error in constructing PInvoke calls can cause
-this problem, and running with Managed Debugging Assistants is advised. If that
-possibility is eliminated, consider contacting Microsoft Product Support for
-help.
-
-\\
-
-COMMAND: verifyobj.
-!VerifyObj <object address>
-
-!VerifyObj is a diagnostic tool that checks the object that is passed as an
-argument for signs of corruption.
-
- 0:002> !verifyobj 028000ec
- object 0x28000ec does not have valid method table
-
- 0:002> !verifyobj 0680017c
- object 0x680017c: bad member 00000001 at 06800184
-
-\\
-
-COMMAND: findroots.
-!FindRoots -gen <N> | -gen any | <object address>
-
-The "-gen" form causes the debugger to break in the debuggee on the next
-collection of the specified generation. The effect is reset as soon as the
-break occurs, in other words, if you need to break on the next collection you
-would need to reissue the command.
-
-The last form of this command is meant to be used after the break caused by the
-other forms has occurred. Now the debuggee is in the right state for
-!FindRoots to be able to identify roots for objects from the current condemned
-generations.
-
-!FindRoots is a diagnostic command that is meant to answer the following
-question:
-
-"I see that GCs are happening, however my objects have still not been
-collected. Why? Who is holding onto them?"
-
-The process of answering the question would go something like this:
-
-1. Find out the generation of the object of interest using the !GCWhere
-command, say it is gen 1:
- !GCWhere <object address>
-
-2. Instruct the runtime to stop the next time it collects that generation using
-the !FindRoots command:
- !FindRoots -gen 1
- g
-
-3. When the next GC starts, and has proceeded past the mark phase a CLR
-notification will cause a break in the debugger:
- (fd0.ec4): CLR notification exception - code e0444143 (first chance)
- CLR notification: GC - end of mark phase.
- Condemned generation: 1.
-
-4. Now we can use the !FindRoots <object address> to find out the cross
-generational references to the object of interest. In other words, even if the
-object is not referenced by any "proper" root it may still be referenced by an
-older object (from an older generation), from a generation that has not yet been
-scheduled for collection. At this point !FindRoots will search those older
-generations too, and report those roots.
- 0:002> !findroots 06808094
- older generations::Root: 068012f8(AAA.Test+a)->
- 06808094(AAA.Test+b)
-
-
-\\
-
-COMMAND: heapstat.
-!HeapStat [-inclUnrooted | -iu]
-
-This command shows the generation sizes for each heap and the total, how much free
-space there is in each generation on each heap. If the -inclUnrooted option is
-specified the report will include information about the managed objects from the
-GC heap that are not rooted anymore.
-
-Sample output:
-
- 0:002> !heapstat
- Heap Gen0 Gen1 Gen2 LOH
- Heap0 177904 12 306956 8784
- Heap1 159652 12 12 16
- Total 337556 24 306968 8800
-
- Free space: Percentage
- Heap0 28 12 12 64 SOH: 0% LOH: 0%
- Heap1 104 12 12 16 SOH: 0% LOH:100%
- Total 132 24 24 80
-
- 0:002> !heapstat -inclUnrooted
- Heap Gen0 Gen1 Gen2 LOH
- Heap0 177904 12 306956 8784
- Heap1 159652 12 12 16
- Total 337556 24 306968 8800
-
- Free space: Percentage
- Heap0 28 12 12 64 SOH: 0% LOH: 0%
- Heap1 104 12 12 16 SOH: 0% LOH:100%
- Total 132 24 24 80
-
- Unrooted objects: Percentage
- Heap0 152212 0 306196 0 SOH: 94% LOH: 0%
- Heap1 155704 0 0 0 SOH: 97% LOH: 0%
- Total 307916 0 306196 0
-
-The percentage column contains a breakout of free or unrooted bytes to total bytes.
-
-\\
-
-COMMAND: analyzeoom.
-!AnalyzeOOM
-
-!AnalyzeOOM displays the info of the last OOM occurred on an allocation request to
-the GC heap (in Server GC it displays OOM, if any, on each GC heap).
-
-To see the managed exception(s) use the !Threads command which will show you
-managed exception(s), if any, on each managed thread. If you do see an
-OutOfMemoryException exception you can use the !PrintException command on it.
-To get the full callstack use the "kb" command in the debugger for that thread.
-For example, to display thread 3's stack use ~3kb.
-
-OOM exceptions could be because of the following reasons:
-
-1) allocation request to GC heap
- in which case you will see JIT_New* on the call stack because managed code called new.
-2) other runtime allocation failure
- for example, failure to expand the finalize queue when GC.ReRegisterForFinalize is
- called.
-3) some other code you use throws a managed OOM exception
- for example, some .NET framework code converts a native OOM exception to managed
- and throws it.
-
-The !AnalyzeOOM command aims to help you with investigating 1) which is the most
-difficult because it requires some internal info from GC. The only exception is
-we don't support allocating objects larger than 2GB on CLR v2.0 or prior. And this
-command will not display any managed OOM because we will throw OOM right away
-instead of even trying to allocate it on the GC heap.
-
-There are 2 legitimate scenarios where GC would return OOM to allocation requests -
-one is if the process is running out of VM space to reserve a segment; the other
-is if the system is running out physical memory (+ page file if you have one) so
-GC can not commit memory it needs. You can look at these scenarios by using performance
-counters or debugger commands. For example for the former scenario the "!address
--summary" debugger command will show you the largest free region in the VM. For
-the latter scenario you can look at the "Memory\% Committed Bytes In Use" see
-if you are running low on commit space. One important thing to keep in mind is
-when you do this kind of memory analysis it could an aftereffect and doesn't
-completely agree with what this command tells you, in which case the command should
-be respected because it truly reflects what happened during GC.
-
-The other cases should be fairly obvious from the callstack.
-
-Sample output:
-
-0:011> !ao
----------Heap 2 ---------
-Managed OOM occurred after GC #28 (Requested to allocate 1234 bytes)
-Reason: Didn't have enough memory to commit
-Detail: SOH: Didn't have enough memory to grow the internal GC datastructures (800000 bytes) -
- on GC entry available commit space was 500 MB
----------Heap 4 ---------
-Managed OOM occurred after GC #12 (Requested to allocate 100000 bytes)
-Reason: Didn't have enough memory to allocate an LOH segment
-Detail: LOH: Failed to reserve memory (16777216 bytes)
-
-\\
-
-COMMAND: gcwhere.
-!GCWhere <object address>
-
-!GCWhere displays the location in the GC heap of the argument passed in.
-
- 0:002> !GCWhere 02800038
- Address Gen Heap segment begin allocated size
- 02800038 2 0 02800000 02800038 0282b740 12
-
-When the argument lies in the managed heap, but is not a valid *object* address
-the "size" is displayed as 0:
-
- 0:002> !GCWhere 0280003c
- Address Gen Heap segment begin allocated size
- 0280003c 2 0 02800000 02800038 0282b740 0
-
-\\
-
-COMMAND: listnearobj.
-!ListNearObj <object address>
-
-!ListNearObj is a diagnostic tool that displays the object preceeding and
-succeeding the address passed in:
-
-The command looks for the address in the GC heap that looks like a valid
-beginning of a managed object (based on a valid method table) and the object
-following the argument address.
-
- 0:002> !ListNearObj 028000ec
- Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency confirmed.
-
- 0:002> !ListNearObj 028000f0
- Before: 0x28000ec 72 (0x48 ) System.ExecutionEngineException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency confirmed.
-
-The command considers the heap as "locally consistent" if:
- prev_obj_addr + prev_obj_size = arg_addr && arg_obj + arg_size = next_obj_addr
-OR
- prev_obj_addr + prev_obj_size = next_obj_addr
-
-When the condition is not satisfied:
-
- 0:002> !lno 028000ec
- Before: 0x28000a4 72 (0x48 ) System.StackOverflowException
- After: 0x2800134 72 (0x48 ) System.Threading.ThreadAbortException
- Heap local consistency not confirmed.
-
-\\
-
-COMMAND: dumplog.
-!DumpLog [-addr <addressOfStressLog>] [<Filename>]
-
-To aid in diagnosing hard-to-reproduce stress failures, the CLR team added an
-in-memory log capability. The idea was to avoid using locks or I/O which could
-disturb a fragile repro environment. The !DumpLog function allows you to write
-that log out to a file. If no Filename is specified, the file "Stresslog.txt"
-in the current directory is created.
-
-The optional argument addr allows one to specify a stress log other then the
-default one.
-
- 0:000> !DumpLog
- Attempting to dump Stress log to file 'StressLog.txt'
- .................
- SUCCESS: Stress log dumped
-
-To turn on the stress log, set the following registry keys under
-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework:
-
-
-(DWORD) StressLog = 1
-(DWORD) LogFacility = 0xffffffbf (this is a bit mask, almost all logging is on.
- This is also the default value if the key
- isn't specified)
-(DWORD) StressLogSize = 65536 (this is the default value if the key isn't
- specified)
-(DWORD) LogLevel = 6 (this is the default value if the key isn't
- specified. The higher the number the more
- detailed logs are generated. The maximum
- value is decimal 10)
-
-StressLogSize is the size in bytes of the in-memory log allocated for each
-thread in the process. In the case above, each thread gets a 64K log. You
-could increase this to get more logging, but more memory will be required for
-this log in the process. For example, 20 threads with 524288 bytes per thread
-has a memory demand of 10 Megabytes. The stress log is circular so new entries
-will replace older ones on threads which have reached their buffer limit.
-
-The log facilities are defined as follows:
- GC 0x00000001
- GCINFO 0x00000002
- STUBS 0x00000004
- JIT 0x00000008
- LOADER 0x00000010
- METADATA 0x00000020
- SYNC 0x00000040
- EEMEM 0x00000080
- GCALLOC 0x00000100
- CORDB 0x00000200
- CLASSLOADER 0x00000400
- CORPROF 0x00000800
- REMOTING 0x00001000
- DBGALLOC 0x00002000
- EH 0x00004000
- ENC 0x00008000
- ASSERT 0x00010000
- VERIFIER 0x00020000
- THREADPOOL 0x00040000
- GCROOTS 0x00080000
- INTEROP 0x00100000
- MARSHALER 0x00200000
- IJW 0x00400000
- ZAP 0x00800000
- STARTUP 0x01000000
- APPDOMAIN 0x02000000
- CODESHARING 0x04000000
- STORE 0x08000000
- SECURITY 0x10000000
- LOCKS 0x20000000
- BCL 0x40000000
-
-Here is some sample output:
-
- 3560 9.981137099 : `SYNC` RareEnablePremptiveGC: entering.
- Thread state = a030
-
- 3560 9.981135033 : `GC`GCALLOC`GCROOTS` ========== ENDGC 4194 (gen = 2,
- collect_classes = 0) ==========={
-
- 3560 9.981125826 : `GC` Segment mem 00C61000 alloc
- = 00D071F0 used 00D09254 committed 00D17000
-
- 3560 9.981125726 : `GC` Generation 0 [00CED07C, 00000000
- ] cur = 00000000
-
- 3560 9.981125529 : `GC` Generation 1 [00CED070, 00000000
- ] cur = 00000000
-
- 3560 9.981125103 : `GC` Generation 2 [00C61000, 00000000
- ] cur = 00000000
-
- 3560 9.981124963 : `GC` GC Heap 00000000
-
- 3560 9.980618994 : `GC`GCROOTS` GcScanHandles (Promotion Phase = 0)
-
-The first column is the OS thread ID for the thread appending to the log,
-the second column is the timestamp, the third is the facility category for the
-log entry, and the fourth contains the log message. The facility field is
-expressed as `facility1`facility2`facility3`. This facilitates the creation of
-filters for displaying only specific message categories. To make sense of this
-log, you would probably want the Shared Source CLI to find out exactly where
-the log comes from.
-\\
-
-COMMAND: findappdomain.
-!FindAppDomain <Object address>
-
-!FindAppDomain will attempt to resolve the AppDomain of an object. For example,
-using an Object Pointer from the output of !DumpStackObjects:
-
- 0:000> !findappdomain 00a79d98
- AppDomain: 0014f000
- Name: unittest.exe
- ID: 1
-
-You can find out more about the AppDomain with the !DumpDomain command. Not
-every object has enough clues about it's origin to determine the AppDomain.
-Objects with Finalizers are the easiest case, as the CLR needs to be able to
-call those when an AppDomain shuts down.
-\\
-
-COMMAND: savemodule.
-!SaveModule <Base address> <Filename>
-
-This command allows you to take a image loaded in memory and write it to a
-file. This is especially useful if you are debugging a full memory dump, and
-don't have the original DLLs or EXEs. This is most often used to save a managed
-binary to a file, so you can disassemble the code and browse types with ILDASM.
-
-The base address of an image can be found with the "LM" debugger command:
-
- 0:000> lm
- start end module name
- 00400000 00408000 image00400000 (deferred)
- 10200000 102ac000 MSVCR80D (deferred)
- 5a000000 5a0b1000 mscoree (deferred)
- 5a140000 5a29e000 clrjit (deferred)
- 5b660000 5c440000 mscorlib_dll (deferred)
- 5d1d0000 5e13c000 clr (deferred)
- ...
-
-If I wanted to save a copy of clr.dll, I could run:
-
- 0:000> !SaveModule 5d1d0000 c:\pub\out.tmp
- 4 sections in file
- section 0 - VA=1000, VASize=e82da9, FileAddr=400, FileSize=e82e00
- section 1 - VA=e84000, VASize=24d24, FileAddr=e83200, FileSize=ec00
- section 2 - VA=ea9000, VASize=5a8, FileAddr=e91e00, FileSize=600
- section 3 - VA=eaa000, VASize=c183c, FileAddr=e92400, FileSize=c1a00
-
-The diagnostic output indicates that the operation was successful. If
-c:\pub\out.tmp already exists, it will be overwritten.
-\\
-
-COMMAND: gchandles.
-!GCHandles [-type handletype] [-stat] [-perdomain]
-
-!GCHandles provides statistics about GCHandles in the process.
-
-Paremeters:
- stat - Only display the statistics and not the list of handles and
- what they point to.
- perdomain - Break down the statistics by the app domain in which
- the handles reside.
- type - A type of handle to filter it by. The handle types are:
- Pinned
- RefCounted
- WeakShort
- WeakLong
- Strong
- Variable
- AsyncPinned
- SizedRef
-
-Sometimes the source of a memory leak is a GCHandle leak. For example, code
-might keep a 50 Megabyte array alive because a strong GCHandle points to it,
-and the handle was discarded without freeing it.
-
-The most common handles are "Strong Handles," which keep the object they point
-to alive until the handle is explicitly freed. "Pinned Handles" are used to
-prevent the garbage collector from moving an object during collection. These
-should be used sparingly, and for short periods of time. If you don't follow
-that precept, the gc heap can become very fragmented.
-
-Here is sample output from a very simple program. Note that the "RefCount"
-field only applies to RefCount Handles, and this field will contain the
-reference count:
-
- 0:000> !GCHandles
- Handle Type Object Size RefCount Type
- 001611c0 Strong 01d00b58 84 System.IndexOutOfRangeException
- 001611c4 Strong 01d00b58 84 System.IndexOutOfRangeException
- 001611c8 Strong 01d1b48c 40 System.Diagnostics.LogSwitch
- 001611d0 Strong 01cfd2c0 36 System.Security.PermissionSet
- 001611d4 Strong 01cf7484 56 System.Object[]
- 001611d8 Strong 01cf1238 32 System.SharedStatics
- 001611dc Strong 01cf11c8 84 System.Threading.ThreadAbortException
- 001611e0 Strong 01cf1174 84 System.Threading.ThreadAbortException
- 001611e4 Strong 01cf1120 84 System.ExecutionEngineException
- 001611e8 Strong 01cf10cc 84 System.StackOverflowException
- 001611ec Strong 01cf1078 84 System.OutOfMemoryException
- 001611f0 Strong 01cf1024 84 System.Exception
- 001611f8 Strong 01cf2068 48 System.Threading.Thread
- 001611fc Strong 01cf1328 112 System.AppDomain
- 001613ec Pinned 02cf3268 8176 System.Object[]
- 001613f0 Pinned 02cf2258 4096 System.Object[]
- 001613f4 Pinned 02cf2038 528 System.Object[]
- 001613f8 Pinned 01cf121c 12 System.Object
- 001613fc Pinned 02cf1010 4116 System.Object[]
-
- Statistics:
- MT Count TotalSize Class Name
- 563266dc 1 12 System.Object
- 56329708 1 32 System.SharedStatics
- 5632bc38 1 36 System.Security.PermissionSet
- 5635f934 1 40 System.Diagnostics.LogSwitch
- 5632759c 1 48 System.Threading.Thread
- 5632735c 1 84 System.ExecutionEngineException
- 56327304 1 84 System.StackOverflowException
- 563272ac 1 84 System.OutOfMemoryException
- 563270c4 1 84 System.Exception
- 56328914 1 112 System.AppDomain
- 56335f78 2 168 System.IndexOutOfRangeException
- 563273b4 2 168 System.Threading.ThreadAbortException
- 563208d0 5 16972 System.Object[]
- Total 19 objects
-
- Handles:
- Strong Handles: 14
- Pinned Handles: 5
-\\
-
-COMMAND: gchandleleaks.
-!GCHandleLeaks
-
-This command is an aid in tracking down GCHandle leaks. It searches all of
-memory for any references to the Strong and Pinned GCHandles in the process,
-and reports what it found. If a handle is found, you'll see the address of the
-reference. This might be a stack address or a field within an object, for
-example. If a handle is not found in memory, you'll get notification of that
-too.
-
-The command has diagnostic output which doesn't need to be repeated here. One
-thing to keep in mind is that anytime you search all of memory for a value, you
-can get false positives because even though the value was found, it might be
-garbage in that no code knows about the address. You can also get false
-negatives because a user is free to pass that GCHandle to unmanaged code that
-might store the handle in a strange way (shifting bits, for example).
-
-For example, a GCHandle valuetype is stored on the stack with the low bit set
-if it points to a Pinned handle. So !GCHandleLeaks ignores the low bit in it's
-searches.
-
-That said, if a serious leak is going on, you'll get a ever-growing set of
-handle addresses that couldn't be found.
-\\
-
-COMMAND: vmmap.
-!VMMap
-
-!VMMap traverses the virtual address space and lists the type of protection
-applied to each region. Sample output:
-
- 0:000> !VMMap
- Start Stop Length AllocProtect Protect State Type
- 00000000-0000ffff 00010000 NA Free
- 00010000-00011fff 00002000 RdWr RdWr Commit Private
- 00012000-0001ffff 0000e000 NA Free
- 00020000-00020fff 00001000 RdWr RdWr Commit Private
- 00021000-0002ffff 0000f000 NA Free
- 00030000-00030fff 00001000 RdWr Reserve Private
- ...
-\\
-
-COMMAND: vmstat.
-!VMStat
-
-Provides a summary view of the virtual address space, ordered by each type of
-protection applied to that memory (free, reserved, committed, private, mapped,
-image). The TOTAL column is (AVERAGE * BLK COUNT). Sample output below:
-
- 0:000> !VMStat
- ~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~ ~~~~~~~~~ ~~~~~
- TYPE MINIMUM MAXIMUM AVERAGE BLK COUNT TOTAL
- Free:
- Small 4,096 65,536 48,393 27 1,306,611
- Medium 139,264 528,384 337,920 4 1,351,680
- Large 6,303,744 974,778,368 169,089,706 12 2,029,076,472
- Summary 4,096 974,778,368 47,249,646 43 2,031,734,778
-
- Reserve:
- Small 4,096 65,536 43,957 41 1,802,237
- Medium 249,856 1,019,904 521,557 6 3,129,342
- Large 2,461,696 16,703,488 11,956,224 3 35,868,672
- Summary 4,096 16,703,488 816,005 50 40,800,250
-
-\\
-
-COMMAND: procinfo.
-!ProcInfo [-env] [-time] [-mem]
-
-!ProcInfo lists the environment variables for the process, kernel CPU time, as
-well as memory usage statistics.
-\\
-
-COMMAND: histinit.
-!HistInit
-
-Before running any of the Hist - family commands you need to initialize the SOS
-structures from the stress log saved in the debuggee. This is achieved by the
-HistInit command.
-
-Sample output:
-
- 0:001> !HistInit
- Attempting to read Stress log
- STRESS LOG:
- facilitiesToLog = 0xffffffff
- levelToLog = 6
- MaxLogSizePerThread = 0x10000 (65536)
- MaxTotalLogSize = 0x1000000 (16777216)
- CurrentTotalLogChunk = 9
- ThreadsWithLogs = 3
- Clock frequency = 3.392 GHz
- Start time 15:26:31
- Last message time 15:26:56
- Total elapsed time 25.077 sec
- .....................................
- ---------------------------- 2407 total entries -----------------------------
-
-
- SUCCESS: GCHist structures initialized
-
-\\
-
-COMMAND: histobjfind.
-!HistObjFind <obj_address>
-
-To examine log entries related to an object whose present address is known one
-would use this command. The output of this command contains all entries that
-reference the object:
-
- 0:003> !HistObjFind 028970d4
- GCCount Object Message
- ---------------------------------------------------------
- 2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2296 028970d4 Relocation NEWVALUE for root 00223fc4
- 2296 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
- 2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
- 2295 028970d4 Relocation NEWVALUE for root 00223fc4
- 2295 028970d4 Relocation NEWVALUE for root 01e411b8
- ...
-
-\\
-
-COMMAND: histroot.
-!HistRoot <root>
-
-The root value obtained from !HistObjFind can be used to track the movement of
-an object through the GCs.
-
-HistRoot provides information related to both promotions and relocations of the
-root specified as the argument.
-
- 0:003> !HistRoot 01e411b8
- GCCount Value MT Promoted? Notes
- ---------------------------------------------------------
- 2296 028970d4 5b6c5cd8 yes
- 2295 028970d4 5b6c5cd8 yes
- 2294 028970d4 5b6c5cd8 yes
- 2293 028970d4 5b6c5cd8 yes
- 2292 028970d4 5b6c5cd8 yes
- 2291 028970d4 5b6c5cd8 yes
- 2290 028970d4 5b6c5cd8 yes
- 2289 028970d4 5b6c5cd8 yes
- 2288 028970d4 5b6c5cd8 yes
- 2287 028970d4 5b6c5cd8 yes
- 2286 028970d4 5b6c5cd8 yes
- 2285 028970d4 5b6c5cd8 yes
- 322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
- ...
-
-\\
-
-COMMAND: histobj.
-!HistObj <obj_address>
-
-This command examines all stress log relocation records and displays the chain
-of GC relocations that may have led to the address passed in as an argument.
-Conceptually the output is:
-
- GenN obj_address root1, root2, root3,
- GenN-1 prev_obj_addr root1, root2,
- GenN-2 prev_prev_oa root1, root4,
- ...
-
-Sample output:
- 0:003> !HistObj 028970d4
- GCCount Object Roots
- ---------------------------------------------------------
- 2296 028970d4 00223fc4, 01e411b8,
- 2295 028970d4 00223fc4, 01e411b8,
- 2294 028970d4 00223fc4, 01e411b8,
- 2293 028970d4 00223fc4, 01e411b8,
- 2292 028970d4 00223fc4, 01e411b8,
- 2291 028970d4 00223fc4, 01e411b8,
- 2290 028970d4 00223fc4, 01e411b8,
- 2289 028970d4 00223fc4, 01e411b8,
- 2288 028970d4 00223fc4, 01e411b8,
- 2287 028970d4 00223fc4, 01e411b8,
- 2286 028970d4 00223fc4, 01e411b8,
- 2285 028970d4 00223fc4, 01e411b8,
- 322 028970d4 01e411b8,
- 0 028970d4
-
-\\
-
-COMMAND: histclear.
-!HistClear
-
-This command releases any resources used by the Hist-family of commands.
-Generally there's no need to call this explicitly, as each HistInit will first
-cleanup the previous resources.
-
- 0:003> !HistClear
- Completed successfully.
-
-\\
-
-COMMAND: dumprcw.
-!DumpRCW <RCW address>
-
-This command lists information about a Runtime Callable Wrapper. You can use
-!DumpObj to obtain the RCW address corresponding to a managed object.
-
-The output contains all COM interface pointers that the RCW holds on to, which
-is useful for investigating lifetime issues of interop-heavy applications.
-\\
-
-COMMAND: dumpccw.
-!DumpCCW <CCW address or COM IP>
-
-This command lists information about a COM Callable Wrapper. You can use
-!DumpObj to obtain the CCW address corresponding to a managed object or pass
-a COM interface pointer to which the object has been marshaled.
-
-The output contains the COM reference count of the CCW, which is useful for
-investigating lifetime issues of interop-heavy applications.
-\\
-
-