MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 2
Hi all,
This post is a continuation of MANAGED DEBUGGING with WINDBG. Breaking on an Exception. Part 1.
BREAKING ON AN EXCEPTION. Part 2
What happens if !PrintException doesn’t return anything, or when we break (i.e. with a breakpoint or manually – Ctrl+Break) we can’t see mscorwks!RaiseTheExceptionInternalOnly in the call stack? What if we already missed the exception when we break?
We could still find the exception near the top of the managed stack of the current thread:
0:000> !DumpStackObjects
...
0:000> !dso
OS Thread Id: 0x15e4 (0)
ESP/REG Object Name
0020eb50 0195fe94 System.IndexOutOfRangeException
0020eb98 0195fe94 System.IndexOutOfRangeException
0020ebdc 01929a04 WindowsApplication1.Form1
0020ebe0 01941958 System.Int32[]
...
0:000> !pe 0x0195fe94
...
If not, we can try to find significant exceptions in the managed heap, as all recent exceptions are stored there:
0:000> !DumpHeap -type Exception
Address MT Size
01991024 790fe044 72
0199106c 790fe0e0 72
019910b4 790fe17c 72
019910fc 790fe284 72
01991144 790fe284 72
0199f848 79103c58 12
0199f860 79103ca4 12
019df490 79117f8c 72
019fc5c8 79117f8c 72
total 9 objects
Statistics:
MT Count TotalSize Class Name
79103ca4 1 12 System.Text.DecoderExceptionFallback
79103c58 1 12 System.Text.EncoderExceptionFallback
790fe17c 1 72 System.ExecutionEngineException
790fe0e0 1 72 System.StackOverflowException
790fe044 1 72 System.OutOfMemoryException
79117f8c 2 144 System.IndexOutOfRangeException
790fe284 2 144 System.Threading.ThreadAbortException
Total 9 objects
0:000> !DumpHeap -mt 79117f8c
Address MT Size
019df490 79117f8c 72
019fc5c8 79117f8c 72
total 2 objects
Statistics:
MT Count TotalSize Class Name
79117f8c 2 144 System.IndexOutOfRangeException
Total 2 objects
0:000> !pe 019df490
...
0:000> !pe 019fc5c8
...
We can also do the following to find all exceptions of a given type in the managed heap:
0:000> .foreach(ex {!dumpheap -type System.IndexOutOfRangeException -short}){!pe ex;.echo *************}
Exception object: 019df490
Exception type: System.IndexOutOfRangeException
Message: Index was outside the bounds of the array.
InnerException: <none>
StackTrace (generated):
SP IP Function
0017EE80 00861AAD WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55
StackTraceString: <none>
HResult: 80131508
*************
Exception object: 019fc5c8
Exception type: System.IndexOutOfRangeException
Message: Index was outside the bounds of the array.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131508
*************
Note that exception objects are normally created when they are needed. But there are a few exception objects which are created when process starts as they can’t be created when they need to be raised: OutOfMemoryException, ExecutionEngineException, StackOverflowException. So we will always see these exceptions in the heap. That doesn’t mean that they were ever raised.
· We can inspect the method where we got the exception:
We can get i.e. the source code line which failed:
0:000> !pe 019df490
Exception object: 019df490
Exception type: System.IndexOutOfRangeException
Message: Index was outside the bounds of the array.
InnerException: <none>
StackTrace (generated):
SP IP Function
0017EE80 00861AAD WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55
StackTraceString: <none>
HResult: 80131508
0:000> !u 00861AAD
Normal JIT generated code
WindowsApplication1.Form1.PlayWithArray(Int32[])
Begin 00861a58, size c0
00861a58 55 push ebp
...
00861aa3 3b5104 cmp edx,dword ptr [ecx+4]
00861aa6 7205 jb WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x55 (00861aad)
00861aa8 e8d67e8c79 call mscorwks!JIT_RngChkFail (7a129983)
>>> 00861aad 03449108 add eax,dword ptr [ecx+edx*4+8]
00861ab1 7105 jno WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x60 (00861ab8)
00861ab3 e8837f8c79 call mscorwks!JIT_Overflow (7a129a3b)
...
00861b16 5d pop ebp
00861b17 c3 ret
0:000> u 00861aa8
WindowsApplication1!WindowsApplication1.Form1.PlayWithArray(Int32[])+0x50 [C:\__WORKSHOP\Demos\BuggyNETApp\Form1.vb @ 135]:
00861aa8 e8d67e8c79 call mscorwks!JIT_RngChkFail (7a129983)
...
Note that not all exceptions we saw have the StackTrace field set. I’ve seen that when the debugger just breaks on an exception, the field is empty. Once we go beyond that point and we i.e. enter the “catch” section of the “try{}catch(){}” statement in the code, that field is set.
But if we just broke on an exception, we can still see the call stack with k, !CLRStack, !DumpStack and related commands as we saw in the Call Stack section before, and get the instruction pointer (IP) we need from there.
· We can stop breaking on CLR exceptions:
If we don’t want to break on any other CLR exception we do the following:
0:000> sxn clr
If we were breaking on specific exception types ( !StopOnException) before, and we stop breaking on all CLR exceptions, we will still see those exceptions in the debugger:
0:000> g
(1728.1f58): C++ EH exception - code e06d7363 (first chance)
(1728.1f58): CLR exception - code e0434f4d (first chance)
'System.IndexOutOfRangeException hit'
Next post: MANAGED DEBUGGING with WINDBG. Locks.
Index: MANAGED DEBUGGING with WINDBG. Introduction and Index.
Regards,
Alex (Alejandro Campos Magencio)
Comments
- Anonymous
June 15, 2012
Really good,thank you