Using WinDbg - Advanced commands
Update 2021: This is a re-post of a post from Johan Straarup - I am posting it here as his blog has been decommissioned
Did you know you can build your own advanced commands using for each, if, etc? The complete list of control tokens are:
- .if
- .else
- .elseif
- .foreach
- .for
- .while
- .do
- .break
- .continue
- .catch
- .leave
- .printf
- .block
Using these command tokes you can send quite advanced instructions to the debugger that not only will make your job a lot easier, but also impress your manager immensely. :)
.foreach
Let’s begin with an easy example. Imagine you want to investigate all strings on the heap that are 6500 bytes or more. To list them you’d simply type !dumpheap -type System.String -min 6500
. This will give you the following information:
0:000> !dumpheap -type System.String -min 6500
------------------------------
Heap 0
Address MT Size
790da154 790f9244 9280
0264c4d0 790f9244 32788
total 2 objects
------------------------------
Heap 1
Address MT Size
total 0 objects
------------------------------
Heap 2
Address MT Size
0b62e790 790f9244 11284
total 1 objects
------------------------------
Heap 3
Address MT Size
0e6839d0 790f9244 32788
0e717904 790f9244 32788
0fb2a320 790f9244 6828
total 3 objects
------------------------------
total 6 objects
Statistics:
MT Count TotalSize Class Name
790f9244 6 125756 System.String
Total 6 objects
So far, so good. The problem is that in order to investigate each string you’d have to run !dumpobject
(!do
) on every address. This might be acceptable now that we’re only dealing with 6 strings, but what if it were 25, or 100? I don’t know if you’re aware of this, but if you pass the -short
argument to !dumpheap
it will give you the minimum information (just the addresses of the objects in question):
0:000> !dumpheap -type System.String -min 6500 -short
790da154
0264c4d0
0b62e790
0e6839d0
0e717904
0fb2a320
------------------------------
Now, let’s use this information in a .foreach
-clause:
0:000> .foreach(myVariable {!dumpheap -type System.String -min 6500 -short}){!do myVariable;.echo *************}
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 9280(0x2440) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWGRkAiEPDxYCHwEFZFhYWFhYWFhYWFhYWFhYWFhYWFhYWF
hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhY
WFhYWFhYWFhYWFhkZAInDw8WCh8CBQFFHwMFCjIyLzExLzIwMDcfBAUBVh8FBQFFHwYFASpkZAIpD2QWBGYPZBYEAg
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 4632 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 4631 m_stringLength
790fad38 4000098 c System.Char 1 instance 3c m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 32786(0x8012) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
g8PFgIfAQUHYWFhYWFhYWRkAgMPDxYCHwEFCWFhYWFhYWFhYWRkAgQPDxYCHwEFCjI4LzEyLzIwMDdkZAIvD2QWAmY
PZBYCZg9kFgICAw8PFgIfAQUFWFhYWFhkZAIxDw8WAh8JZ2QWBGYPZBYEAgEPZBYCZg9kFgQCAQ8WAh8IBQMxcHgWA
gIBDw8WAh8JaGRkAgMPZBYEAgEPDxYCHwEFCkFkZCBSZWNvcmRkZAIDDw8WAh8ABRZ+L0ltYWdlcy9UaXRsZS9OZXc
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 16385 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 10960 m_stringLength
790fad38 4000098 c System.Char 1 instance 3c m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 11282(0x2c12) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWGRkAiEPDxYCHwEFZFhYWFhYWFhYWFhYWFhYWFhYWFhYWFa
YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF
hYWFhYWFhYWFhYWFhYWFhkZAInDw8WCh8CBQFFHwMFCjIyLzExLzIwMDcfBAUBVh8FBQFFHwYFASpkZAIpD2QWBGYPZ
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 5633 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 3092 m_stringLength
790fad38 4000098 c System.Char 1 instance 5b m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 32786(0x8012) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
SRU5UIFBBR0U6IDMgb2YgMTVkZAILD2QWAmYPZBYcAgcPDxYCHwEFZFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWF
hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYW
FhYWFhkZAINDw8WCh4BRQUBRR4CVFQFCjIyLzExLzIwMDceAlRWBQFWHgJURQUBRR4CVFIFASpkZAITDw8WCh8CBQFF
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 16385 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 10960 m_stringLength
790fad38 4000098 c System.Char 1 instance 3c m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 32786(0x8012) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
0b25Ib21lBR9BcHBsaWNhdGlvbk5hdmlnYXRpb246aWJ0TG9nb3V0BTdfY3RsMDpQZXJzb25BcHBsaWNhdGlvbkRlZ3J
lZUxpc3Q6U3lzdGVtVGl0bGU6RWRpdEltYWdlBT5fY3RsMDpQZXJzb25BcHBsaWNhdGlvbkRlZ3JlZURpcGxvbWFMaXN
0OlN5c3RlbVRpdGxlOkVkaXRJbWFnZQVDX2N0bDA6UGVyc29uQXBwbGljYXRpb25PdGhlclF1YWxpZmljYXRpb25MaXN
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 16385 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 10960 m_stringLength
790fad38 4000098 c System.Char 1 instance 3c m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 6826(0x1aaa) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String:
/wEPDwULLTEyMTQ5MDkyMjgPZBYCAgEPZBYGAgcPZBYEAgEPDxYCHghJbWFnZVVybAUrfi9pbWFnZXMvbmF2ZAILD2QW
aWdhdGlvbi9wYWdlcy9QYWdlMlByb2dyZXNzLmdpZmRkAgIPDxYCHgRUZXh0BRVDVVJSRU5UIFBBR0U6IDMgb2YgMTVk
ZAILD2QWAmYPZBYcAgcPDxYCHwEFZFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhY
...
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 1 instance 3405 m_arrayLength
790fdb60 4000097 8 System.Int32 1 instance 3404 m_stringLength
790fad38 4000098 c System.Char 1 instance 2f m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 000d5eb8:790d57b4 000fb4c0:790d57b4 000ca848:790d57b4 1d8334d8:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 000d5eb8:026203f0 000fb4c0:02624504 000ca848:026745f0 1d8334d8:026dcef4 <<
*************
Unknown option: ------------------------------
*************
Let’s analyze the exact syntax. Here’s the command
.foreach(myVariable {!dumpheap -type System.String -min 6500 -short}){!do myVariable;.echo *************}
“myVariable” is, as the name implies, the name of the variable that I wish to use for the data generated by the first set of commands. The second set of commands is what I wish to execute for each token. First I run !do
on the variable, and then I use the .echo-command to print a separator in order to make it a bit easier on the eyes.
There are additional parameters you can use. For example you can choose to skip every n number of variables, or specify a text file to be parsed and used as tokens instead. Take a look at the windbg documentation if you’re interested.
.shell
I first saw this being used by my colleague Doug Stewart, who is a genius with these things.
0:000> .shell -i - -ci "!iisinfo.clientconns" FIND /c "Request active"
40
.shell: Process exited
What it does is, it runs !iisinfo.clientonns
and uses the MS-DOS FIND-command to count the number of times the string “Request active” appears. Off course you could use it to search for certain strings from any type of output, like ".shell -i - -ci "!do 0b62e790" FIND /c /i "<table""
or whatever suits your needs.
Let’s take a quick look at the syntax.
When it comes to .shell
the -i
option is mandatory. It specifies the file we want to use for input. In this scenario we don’t want to use a file, so we add another hyphen, resulting in the following syntax: .shell -i -
We then add the -ci
option, which states that we should treat the following commands as an input file instead. .shell -i - -ci "!iisinfo.clientconns"
Finally we state what shell command we wish to run using this input. .shell -i - -ci "!iisinfo.clientconns" FIND /c "Request active"
.
Naturally we can use any complicated command we wish in the statement, so instead of !iisinfo.clientconns
we could run one of our .foreach
-loops instead.
/ Johan