my raw header!
I didn't post to this blog during many months, mainly because I moved from my Escalation Engineer position to an Application Development Consultant position (aka Technical Account Manager Dev).I missed some free time for that kind of leisure, and as many other interesting blogs now spread over the web, I felt unuseful to post things that may not really help someone.
That's why I come back today, to post a debugger extension I wrote some months ago to help me to automate my debugging sessions.I always felt a lack in windbg to easily filter other debugger extensions outputs and automate recursing commands with previous results.
Others like Doug & Tess are able to use both !foreach, .shell - -ci or even logparser to filter outputs, but I'm too bad/lazy for that and preferred having my own debugger syntax :)After having shown this extension to some debugging class I held in France, I decided to share it publicly.
The binary version I'm posting here is the initial version of this extension, that I wanted to improve before posting, but as I never had time I'm posting it here as-is..It contains in this version only 1 debugger command called !sosexec, with this awful syntax:
!sosexec /c “command1|filter1”->”command2 [tokenID1]|filter2”->”command3 [tokenID2]”->....
The parameter [tokenID1] is the column index for the token you’re looking for, starting from 0.For example in the bellow output, 0 is the ‘MT’ token, 1 is the ‘Field’ token, and thus 6 is the tokenID for ‘Value’. Note those indexes are changing depending on sos version so take care to check them first.
0:021> !do 0acca994
Size: 168(0xa8) bytes
MT Field Offset Type VT Attr Value Name
663ad210 4000fc7 4 ...IHttpAsyncHandler 0 instance 08a308d0 _asyncAppHandler
663a206c 4000fc8 8 ...b.HttpApplication 0 instance 08a308d0 _appInstance
663a3a9c 4000fc9 c ....Web.IHttpHandler 0 instance 0accb490 _handler
663a2ba0 4000fca 10 ...m.Web.HttpRequest 0 instance 0accaa3c _request
A real world example for ASP.NET 2.0 application could be the one bellow to list the current ASPX pages easily (note1 663a2750 was my methodtable for HttpContext) (note2 that’s just a sample, Tess debugging script makes it lots better)
0:021> !sosexec /c "!dumpheap -mt 663a2750 -short"->"!do |_request"->"!do |_path"->"!do |String:"
Executing !do 06c35cb0
Executing !do 06c35d58
Executing !do 06c34538
String: E:\Applications.Net\CRM Cog Integration Web\coghierarchy.aspx
Executing !do 0acca994
Executing !do 0acc91e4
String: E:\Applications.Net\CRM Cog Integration Web\cogcompanyinformation.aspx
Executing !do 0ca32e98
Executing !do 0ca32f40
Executing !do 0ca31310
Executing !do 0caa95fc
Executing !do 0caa96a4
Executing !do 0caa7e4c
This command will:
1. Execute !dumpheap -mt 663a2750 -short (I got MT from an earlier !dumpheap –stat)
3. Execute !do with the 1th token (ID 0) for each output lines of step 1
4. Filter this output for lines containing string “_request”
5. Execute !do again with the 7th token (ID 6) of each filtered line of step 4 (the ‘Value’ token)
6. Filter output with lines containing the string ‘_path’
7. Execute !do with again the 7th token (ID 6) of each filtered line of step 6
8. Filter output from step 7. to only show the string content, that starts with “String:”
Another example bellow will list SQL commands executed by current threads:
!sosexec /c "~*e !dso|System.Data.SqlClient.SqlCommand"->"!do |cmdText"->"!do "
Executing !do 0x2645ab0c
Executing !do 0x143f9908
Executing !do 0x111bbc18
Executing !do 0x1c442bdc
Executing !do 0x14efddc0
Executing !do 0x143f5f44
The nice thing is that it works for both user (native & managed) and kernel debugging (live or postmortem).
Another example will dump all ASP templates compiled in an IIS process using the iisinfo.dll debugger extension brought by DebugDiag.
!sosexec /c "!iisinfo.templates -v|C:\"->"!templatecode "
You can also simply use it to filter your debugger output, for example listing all DLLs named ora* (don’t ask me why :-p)
0:029> !sosexec /c "lmnt|ora"
03f70000 041c7000 orageneric9 orageneric9.dll Mon May 06 02:23:24 2002 (3CD5CCFC)
60500000 60590000 oracommon9 oracommon9.dll Mon Apr 29 01:12:14 2002 (3CCC81CE)
60800000 60806000 oravsn9 oravsn9.dll Mon Apr 29 01:13:48 2002 (3CCC822C)
60810000 60816000 orawtc9 orawtc9.dll Mon Apr 29 01:13:50 2002 (3CCC822E)
61400000 6142c000 oranl9 oranl9.dll Sat Apr 27 04:30:17 2002 (3CCA0D39)
61480000 61534000 oran9 oran9.dll Sat Apr 27 04:31:08 2002 (3CCA0D6C)
I highly recommend to write and test those commands step by step, as a simple mistake can make this version of the extension loop infinitely executing wrong commands and thus looking for unknown symbols… J
When I'll have a better version, I'll post it with source to codeplex to also let other people improve it, as it exposes lightweight framework of C++ objects to allow to be reused in other debugger extensions, such as my only !sosexec command is only made of:
sosexec(PDEBUG_CLIENT4 Client, PCSTR args)
// Read arguments command line
CArgs* oArgs = new CArgs(args);
vector<string> sCommands = oArgs->getCommands();
// Split args into commands/filters/tokens
vector<string> sFilters = oArgs->getFilters();
vector<int> iTokens = oArgs->getTokens();
// Recursively execute commands
CExecutor *oExec1 = new CExecutor(Client, sCommands,sFilters,iTokens);
On the feature list there is currently some more switches like /unique, /silent, ability to use multiple filters, and skip headers or footer lines.As I’ll try to improve it and post source code for good, feel free to share ideas, feedbacks or sample commands that you find useful to share.