Steve Johnson's done it again! He's released a new version of his must have SOSEX extension, which makes your .NET debugging with WinDBG easier than ever. For all you WinDBG aficionados, he's implemented many of the most common native debugging commands such as BP, DV, and others for managed applications, so if you want to see the locals and parameters in .NET you use !mdv. Read all about the updates on Steve's blog entry or by running the !sosexhelp command after loading SOSEX into WinDBG.

My favorite new command in SOSEX is the wonderful !mk command so you can see mixed native and managed call stacks without having to piece them together from the SOS !dumpstack command. While Microsoft accidentally released version 6.7.5.0 with mixed debugging support, we don't need it any more. Here's an example:

0:000> !mk
ESP RetAddr
00:U 0019de84 77a95704 ntdll!KiFastSystemCallRet
01:U 0019de88 77456118 GDI32!NtGdiPatBlt+0xc

<items removed for clarity>

0b:U 0019e328 014a22e1 CLRStub[StubLinkStub]@14a22e1
0c:M 0019e358 6cd4e83d System.Drawing.Graphics.FillRectangle(
                        System.Drawing.Brush, Int32, Int32, Int32, Int32)
                        (+0x26 IL)(+0x32 Native)
0d:M 0019e3b8 003f45fa Bugslayer.SortDisplayGraph.SorterGraph.UpdateSingleFixedElement(
                          Int32, System.Drawing.Graphics, 
                          System.Drawing.Brush)(+0x30 IL)(+0x99 Native)
                          [c:\Test\ \AnimatedAlgorithms\
                       Bugslayer.SortDisplayGraph\SorterGraph.cs, @ 410,13]

What's super cool here is that SOSEX also shows you the source, line, and column for all managed items on the call stack. The first column next to each address (ex: 0d:M) shows the frame number and U for unmanaged (native code) and M (for managed code).

To see the parameters and locals for a particular item on the stack frame, I'll use the UpdateSingleFixedElement method above. To switch to its frame, I'll use the SOSEX !mframe command followed by the !mdv command:

0:000> !mframe 0d
0:000> !mdv
Frame 0xd: (Bugslayer.SortDisplayGraph.SorterGraph.UpdateSingleFixedElement(
            Int32, System.Drawing.Graphics, System.Drawing.Brush)):
[A0]:this:0x589479c (Bugslayer.SortDisplayGraph.SorterGraph)
[A1]:index:0x5f (System.Int32)
[A2]:g:0x19aa514 (System.Drawing.Graphics)
[A3]:brush:0x5895514 (System.Drawing.Brush)
[L0]:currValue:0x7 (System.Int32)
[L1]:rectWidth:0xf (System.Int32)
[L2]:rectYStart:0xbe (System.Int32)

As you can guess, the A indicates arguments and L is for locals. I love how value types, like the rectWidth local variable, which is a value type, is shown as well. !clrstack –a from SOS only shows the address of the locals not its name and type.

Where SOSEX gets really cool is with the !mdt command to look at individual objects. Below, I'll dump out the solid brush and the this pointer.

0:000> !mdt 0x5895514
05895514 (System.Drawing.SolidBrush)
_identity:NULL (System.Object)
nativeBrush:0e5f1cc8 (System.IntPtr)
color:05895524 (System.Drawing.Color) VALTYPE (MT=6cd5ce88, ADDR=05895524)
0:000> !mdt 0x589479c
0589479c (Bugslayer.SortDisplayGraph.SorterGraph)
__identity:NULL (System.Object)
site:NULL (System.ComponentModel.ISite)
events:058949d0 (System.ComponentModel.EventHandlerList)
[s]EventDisposed:<uninitialized>
window:058948cc (System.Windows.Forms.Control+ControlNativeWindow)
parent:05892f84 (Bugslayer.SortDisplayControl.SorterControl)
. . .

While !mdt is very much like the SOS !dumpobj command, the !mdt command has super powers. Say you needed to look deeper at the child references of the this pointer from above? What you'd have to do is execute !dumpobj (or it's short version, !do) on each child object you want to see. This is exactly where carpel tunnel syndrome starts. SOS really falls down when you have to look at multiple objects. The super power in the SOSEX !mdt command, -r:

0:000> !mdt 0x589479c -r
0589479 (Bugslayer.SortDisplayGraph.SorterGraph)
   __identity:NULL (System.Object)
   site:NULL (System.ComponentModel.ISite)
   events:0596b1e0 (System.ComponentModel.EventHandlerList)
      head:0596b2f8 (System.ComponentModel.EventHandlerList+ListEntry)
         next:0596b290 (System.ComponentModel.EventHandlerList+ListEntry)
            <RECURSIVE>
         key:05961bd4 (System.Object)
            <NO FIELDS>
         handler:0596b2d8 (System.EventHandler)
            _target:0596af48 (Bugslayer.SortDisplayGraph.SorterGraph)
               <RECURSIVE>
            _methodBase:NULL (System.Reflection.MethodBase)
            _methodPtr:0016c5d8 (System.IntPtr)
            _methodPtrAux:00000000 (System.IntPtr)
            _invocationList:NULL (System.Object)
            _invocationCount:00000000 (System.IntPtr)
            <NO FIELDS>
      parent:0596af48 (Bugslayer.SortDisplayGraph.SorterGraph)
         <RECURSIVE>

. . .

Adding –r to the !mdt command recursively dumps out all the child objects as you can see. This is a huge timesaver. But there's more magic to the !mdt command. In the examples I've show so far, I've been using the address of the object to dump. If you've got the variable name, which is shown with the SOSEX !mdv command, you can pass the variable name instead of the address. Thus, in my example, !mdt this is identical to !mdt 0x589479c. That will save you a ton of time.

In native code, if you're looking for a particular symbol, you'd use the X command to hunt it down. What SOSEX offers is the !mx command, which does the same thing. In the following example, I wanted to find all the Sort methods that come from my NSORT.DLL:

0:000> !mx nsort!*.Sort
NSort!NSort.ISorter.Sort(IList): void
NSort!NSort.SwapSorter.Sort(IList): void
NSort!NSort.BiDirectionalBubbleSort.Sort(IList): void
NSort!NSort.BubbleSorter.Sort(IList): void
NSort!NSort.ComboSort11.Sort(IList): void
NSort!NSort.DoubleStorageMergeSort.Sort(IList): void
NSort!NSort.DoubleStorageMergeSort.Sort(IList, int, int, object[]): void
NSort!NSort.FastQuickSorter.Sort(IList): void
NSort!NSort.HeapSort.Sort(IList): void
NSort!NSort.InPlaceMergeSort.Sort(IList): void
NSort!NSort.InPlaceMergeSort.Sort(IList, int, int): void
NSort!NSort.InsertionSort.Sort(IList): void
NSort!NSort.OddEvenTransportSorter.Sort(IList): void
NSort!NSort.QuickSorter.Sort(IList): void
NSort!NSort.QuickSorter.Sort(IList, int, int): void
NSort!NSort.QuickSortWithBubbleSort.Sort(IList): void
NSort!NSort.SelectionSort.Sort(IList): void
NSort!NSort.ShakerSort.Sort(IList): void
NSort!NSort.ShearSorter.Sort(IList): void
NSort!NSort.ShellSort.Sort(IList): void

Finally, in SOSEX Steve has implemented all the common breakpoint commands for but for managed debugging. One of my favorite tricks in native debugging is the BM command, which sets a breakpoint on a symbol with wildcard support. Steve implemented !mbm which allows us to do the same thing in managed debugging. All of the SOSEX breakpoint commands are critical if you need to do mixed debugging on x64 systems. Here's my example of setting a breakpoint on all those Sort methods I found earlier:

0:000> !mbm nsort!*.Sort
Breakpoint: Matching method NSort.ISorter.Sort(System.Collections.IList) 
        resolved, but not yet jitted. Setting JIT notification...
Breakpoint: Matching method NSort.SwapSorter.Sort(System.Collections.IList) 
        resolved, but not yet jitted. Setting JIT notification...
. . .

SOSEX has been a huge help for a while, but now it's even better. Thanks, Steve!