The Code Slinger

December 27, 2007

SOSEX – New .NET Extensions for WinDBG

Filed under: .NET,SOS,WinDBG — Pete @ 3:43 pm

Somehow I missed this until today, but Steve Johnson has a nice write-up on some extensions he’s written for debugging managed code with WinDBG/SOS.

I find it easier to debug logic and performance issues using other tools like AntsProfiler, Perfmon logs/counters and VS.NET for the most part, however I do use WinDBG/SOS for occasional issues that only crop up in production environments (such as those caused by heavy load, multi-user deadlocks, etc). 

There is a bit of a learning curve to WinDBG, however once you realize how much information is contained within it (e.g. within a full user stack dump of the aspnet worker process), it is often quite easy to find exactly where the issue in the original managed source lies.

There are already commands like !gcroot and !dumpheap that one could use to track some of these issues down.  However of keen interest to a limited WinDBG user such as myself are the new !refs and !dlk commands.

!refs

Though not a replacement, the !refs command supplements SOS’s !gcroot command by allowing you to view  the immediate references from and to a given object.

0:000> !refs 0000000080000db8
Objects referenced by 0000000080000db8 (System.Threading.Mutex):
0000000080000ef0         32    Microsoft.Win32.SafeHandles.SafeWaitHandle

Objects referencing 0000000080000db8 (System.Threading.Mutex):
0000000080000e08         72    System.Threading.Mutex+<>c__DisplayClass3
0000000080000e50         64    System.Runtime.CompilerServices.RuntimeHelpers+CleanupCode

The sample output above shows only heap references, but !refs will also list all references from handles, stacks, registers and the freachable queues.

 

!dlk

The !dlk command allows you to easily spot deadlocks in your application if you suspect deadlock to be the cause of an application hang. If !dlk detects deadlock, the output will list the sync blocks that are held as well as the sync blocks for which each thread is waiting, as well as the type, method, IL offset, and, if symbols are available, the source code and line number at which each thread is waiting:

0:010> !dlk
Deadlock detected:
CLR thread 4 holds sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
             waits sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
CLR thread 5 holds sync block 00000000024c6928 OBJ:000000007fff0fa8[System.String] STRVAL=SYNC2
             waits sync block 00000000024c6970 OBJ:000000007fff0f80[System.String] STRVAL=SYNC1
CLR Thread 4 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]
CLR Thread 5 is waiting at ConsoleTestApp.ConsoleTestApp.MonitorDeadlockThreadProc()+0xa4(IL) [C:\dev\ConsoleTestApp\ConsoleTestApp.cs, line 195]

1 deadlock detected.

As you can see, !dlk makes it dead simple to troubleshoot this common kind of deadlock in managed code. One important caveat holds true for !dlk: it only works for deadlocks on “sync blocks”. Put more simply, it will only spot locks created by Monitor.Enter (which is used by the C# lock keyword). !dlk will not catch deadlock on other types of synchronization objects, such as mutexes and semaphores.

Very cool stuff.  Thanks Steve!

Create a free website or blog at WordPress.com.