본문 바로가기

.NET/Debugging

.NET Exceptions: Quick WinDbg/SOS tip on how to dump all the .NET exceptions on the heap

출처 :http://blogs.msdn.com/b/tess/archive/2009/04/16/net-exceptions-quick-windbg-sos-tip-on-how-to-dump-all-the-net-exceptions-on-the-heap.aspx


Since a .net exception is a .NET object like any other, it gets stored on the GC heap when you (or some code you call) calls new XXException(). 

This means that if you have a memory dump of a process you can dump out all the recent exceptions that have occurred, or rather all exceptions that have not yet been garbage collected, which will give you a good feel for what exceptions occurred recently. 

Doing this is pretty easy if you have sos loaded (.loadby sos mscorwks) in windbg

0:015> !dumpheap -type Exception 
------------------------------ 
Heap 0 
Address       MT     Size 
02ea6b0c 79330a80       72     
02ea75f0 7930eab4       76     
… 
06f57aa4 7930eab4       76     
06f5829c 7930eab4       76     
06f58a94 7930eab4       76     
06f5928c 7930eab4       76     
06f59a84 7930eab4       76     
06f5a27c 7930eab4       76     
06f5aa74 7930eab4       76     
06f5b26c 7930eab4       76     
06f5ba64 7930eab4       76     
06f5c25c 7930eab4       76     
06f5ca54 7930eab4       76     
06f5d24c 7930eab4       76     
total 319 objects 
------------------------------ 
total 656 objects 
Statistics: 
      MT    Count    TotalSize Class Name 
79333dc0        1           12 System.Text.DecoderExceptionFallback 
79333d7c        1           12 System.Text.EncoderExceptionFallback 
793172f8        2           64 System.UnhandledExceptionEventHandler 
79330c30        1           72 System.ExecutionEngineException 
79330ba0        1           72 System.StackOverflowException 
79330b10        1           72 System.OutOfMemoryException 
79330a80        1           72 System.Exception 
79330cc0        2          144 System.Threading.ThreadAbortException 
7930eab4      646        49096 System.IO.DirectoryNotFoundException 
Total 656 objects

To dump information about a specific exception you can use !pe 02ea6b0c for example which will show you the stack, exception name etc.

The problem is that you have to do this for all the exceptions which can become pretty tedious if there are many of them, so to speed up the process you can use the .foreach command to automate the process

.foreach (ex {!dumpheap -type Exception -short}){.echo "********************************";!pe ${ex} }

This will go through all objects on the heap, where the typename contains the word exception and print them out with !pe (short for !PrintException)

Note that this will also include items that are not really exceptions like the System.Text.DecoderExceptionFallback, but since those are not exceptions it will just try to print them out but fail, so you can ignore those.

The output looks like this:

0:015> .foreach (ex {!dumpheap -type Exception -short}){.echo "********************************";!pe ${ex} } 
******************************** 
Exception object: 02ea6b0c 
Exception type: System.Exception 
Message: The email entered is not a valid email address 
InnerException: <none> 
StackTrace (generated): 
    SP       IP       Function 
    024AF2C8 0FE3125E App_Code_da2s7oyo!BuggyMail.IsValidEmailAddress(System.String)+0x76 
    024AF2E8 0FE31192 App_Code_da2s7oyo!BuggyMail.SendEmail(System.String, System.String)+0x4a

StackTraceString: <none> 
HResult: 80131500 
There are nested exceptions on this thread. Run with -nested for details 
******************************** 
Exception object: 02ea75f0 
Exception type: System.IO.DirectoryNotFoundException 
Message: Could not find a part of the path 'c:\idontexist\log.txt'. 
InnerException: <none> 
StackTrace (generated): 
    SP       IP       Function 
    024AF044 792741F2 mscorlib_ni!System.IO.__Error.WinIOError(Int32, System.String)+0xc2 
    024AF0A0 792EB22B mscorlib_ni!System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean)+0x48b 
    024AF198 792EA882 mscorlib_ni!System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions)+0x42 
    024AF1C0 7927783F mscorlib_ni!System.IO.StreamWriter.CreateFile(System.String, Boolean)+0x3f 
    024AF1D4 792777DB mscorlib_ni!System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32)+0x3b 
    024AF1F4 797EE19F mscorlib_ni!System.IO.StreamWriter..ctor(System.String)+0x1f 
    024AF204 0FE31325 App_Code_da2s7oyo!Utility.WriteToLog(System.String, System.String)+0x5d

StackTraceString: <none> 
HResult: 80070003 
There are nested exceptions on this thread. Run with -nested for details 
******************************** 
Exception object: 02ea7de8 
Exception type: System.IO.DirectoryNotFoundException 
Message: Could not find a part of the path 'c:\idontexist\log.txt'. 
InnerException: <none> 
StackTrace (generated): 
    SP       IP       Function 
    024AEF60 792741F2 mscorlib_ni!System.IO.__Error.WinIOError(Int32, System.String)+0xc2 
    024AEFBC 792EB22B mscorlib_ni!System.IO.FileStream.Init(System.String, System.IO.FileMode, System.IO.FileAccess, Int32, Boolean, System.IO.FileShare, Int32, System.IO.FileOptions, SECURITY_ATTRIBUTES, System.String, Boolean)+0x48b 
    024AF0B4 792EA882 mscorlib_ni!System.IO.FileStream..ctor(System.String, System.IO.FileMode, System.IO.FileAccess, System.IO.FileShare, Int32, System.IO.FileOptions)+0x42 
    024AF0DC 7927783F mscorlib_ni!System.IO.StreamWriter.CreateFile(System.String, Boolean)+0x3f 
    024AF0F0 792777DB mscorlib_ni!System.IO.StreamWriter..ctor(System.String, Boolean, System.Text.Encoding, Int32)+0x3b 
    024AF110 797EE19F mscorlib_ni!System.IO.StreamWriter..ctor(System.String)+0x1f 
    024AF120 0FE31325 App_Code_da2s7oyo!Utility.WriteToLog(System.String, System.String)+0x5d

StackTraceString: <none> 
HResult: 80070003 
There are nested exceptions on this thread. Run with -nested for details

 

If you also want it to print out the nested exceptions you can just change the command a little bit to say

.foreach (ex {!dumpheap -type Exception -short}){.echo "********************************";!pe –nested ${ex} }