Look at WinDbg Commands For Advanced .NET Debugging

This article describes the WinDbg commands helpful for analyzing an ASP.NET memory dump. We need to load SOS.dll or psscor2.dll for .NET 2.0 applications or psscor4.dll for .NET 4.0 applications into WinDbg for analyzing managed code. SOS.dll is available in the .NET Framework folder and psscor2.dll can be downloaded from here and psscor4.dll from here. We might need to collect a memory dump of w3wp.exe in scenarios like crash, hang, High CPU or memory, deadlocks of your website using ProcDump or DebugDiag. After collecting the dump, we need to open it in WinDbg by dragging and dropping or "File" -> "Open Crash Dump". We then need to configure it to point to the Microsoft Symbol server by running .symfix followed by .sympath as shown below:

WinDbg1.jpg

Let's load SOS.dll or psscor2.dll for 2.0 apps or psscor4.dll for 4.0 apps. The psscor extension is a superset of sos.dll and we will load it using the following command:

.load C:\Program Files\DebugDiag\Exts\psscor4.dll (or) .load psscor4 followed by .reload

WinDbg1.5.jpg

We can load sos.dll based on .NET app version using the following command:

.loadby sos clr

We are now ready to analyze the managed code using pscor4.dll. Let's look at commonly used commands.

Command: .help (or) !psscor4.help

Purpose: This command shows all the commands supported by the extension.

Output:

WinDbg2.jpg

Command: !help <command>

Purpose: This command gives information about a specific command like options, purpose and so on.

Output:

WinDbg3.jpg

Command: !runaway

Purpose: This command lists all threads within the w3p.exe along with the time consumed by it.

Output [Here 28, 26, 27 are thread Ids]:

WinDbg4.jpg

Command: !threadpool

Purpose: This command shows ThreadPool information CPU usage, like number of work requests in the queue, timers and completion port threads and so on.

Output:

WinDbg5.jpg

Command: ~<threadId>s

Purpose: This command switches to a specific thread.

Output:

WinDbg6.jpg

Command: !clrstack

Purpose: This command shows a managed stack trace of a thread.

Output:

WinDbg7.jpg

Command: k (or) kp [shows parameters] (or) kn [shows Frame numbers as well]

Purpose: This command shows managed and unmanaged stack traces of a thread.

Output:

WinDbg8.jpg

Command: !dso (or) !DumpStackObjects

Purpose: This command shows all the objects that are on the thread's stack.

Output:

WinDbg9.jpg

Command: !do <object>

Purpose: This command shows object information like Method Table, EEClass, size, fields and so on.

Output:

WinDbg10.jpg

Command: !DumpHeap

Purpose: This command shows objects present on the heap.

Output:

WinDbg11.jpg

Command: !DumpHeap -stat

Purpose: This command shows statistics of all objects in the heap; the number of objects of a given type, type name and so on.

Output:

WinDbg12.jpg

Command: !sam path (or) !SaveAllModules path

Purpose: This command extracts all modules/DLLs from your memory dump to a folder.

Output:

WinDbg13.jpg

There are many more commands available for us, we can explore it using !help <command>. We can use the following procedure as a base for troubleshooting scenarios like crash, hang and so on.

Crash Scenario

  1. WinDbg opens the dump pointing to the thread that crashed the process.
  2. Load sos.dll or psscorX.dll and look at the stack trace using !clrstack. This helps us to determine which method threw the exception.
  3. Use the !analyze –v command to analyze the exceptions.

High CPU (or) Memory

  1. Collect performance counters along with the dump.
  2. Determine the thread running for a long time using the !runaway command.
  3. From performance counters, determine the thread spiking the CPU and analyze its stack trace.
  4. Analyze that thread's stack trace using the kp (or) !clrstack command.
    Analyze heap objects using the !dumpheap command.

Hang

  1. Collect 2-3 sets of dumps with an interval of 4-5 seconds.
  2. Determine the progress of the thread running in each dump from its stack trace. This will helps us to determine whether a thread hang/waiting on something like a DB connection, lock and so on.
  3. Check for any locks using the !SyncBlk (or) !locks command.