出自SOS: It’s Not Just an ABBA Song Anymore
实验代码:
enum Days { Sat = 1, Sun, Mon, Tue, Wed, Thu, Fri } ; class DoSomething public void Reh(int i, String StrParam) public void Mi(Object o) public void Fa() |
x.Fa();一句会抛出异常,本文演示如何追踪这个异常
1.设置WinDBG截获.NET程序抛出的CLR异常
在WinDBG中点击"Debug"菜单,然后选择"Event Filters",Event Filter 对话框中显示了WinDBG能够识别的所有事件和异常.
添加CLR Exception到Event Filters, Exception Code为0xE0434F4D,
Execution(break status)设置为"Enabled",表明一旦Exception发生,立即Debug
Continue(handling status)设置为"Not Handled",表明Debugger不会把Exception标记为"handled"
参考WinDBG Help中"Controlling Exceptions and Events"一节
用WinDBG打开编译好的exe文件(Ctrl-E),WinDbug会中断在程序的入口.按F5,让程序继续执行,直至Exception被抛出,此时WinDBG显示:
ModLoad: 77dd0000 77e6b000 C:\WINDOWS\system32\ADVAPI32.dll
…
ModLoad: 79060000 790b3000 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorjit.dll
(13d4.104c): CLR exception – code e0434f4d (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0012f278 ebx=00181380 ecx=00000000 edx=00000024 esi=0012f304 edi=e0434f4d
eip=7c812aeb esp=0012f274 ebp=0012f2c8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\KERNEL32.dll –
KERNEL32!RaiseException+0x52:
7c812aeb 5e pop esi
报告这是一个First chance exceptions,发生在KERNEL32!RaiseException
加载SOS
.loadby sos mscorwks
2. 显示进程中的.NET线程(!threads)
0:000> !threads
PDB symbol for mscorwks.dll not loaded
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 104c 00181380 a020 Enabled 00000000:00000000 0014c4f0 0 MTA System.ArgumentException (012f4874)
2 2 f18 001821b0 b220 Enabled 00000000:00000000 0014c4f0 0 MTA (Finalizer)
表明有两个CLR线程.WinDBG Thread ID分别为0和2.
线程2的Exception字段显示"Finalizer",说明这是Finalizer线程,这个字段的值还可能是(Threadpool Worker), (Threadpool Completion Port), or (GC),这些都是CLR系统线程.
线程0中当前的Exception为System.ArgumentException (012f4874)
如果WinDBG当前的命令行提示符不是0, 就需要执行命令~0s,切换到0号线程
执行~,显示当前进程中的所有线程:
0:000> ~
. 0 Id: 13d4.104c Suspend: 1 Teb: 7ffde000 Unfrozen
1 Id: 13d4.9f8 Suspend: 1 Teb: 7ffdd000 Unfrozen
2 Id: 13d4.f18 Suspend: 1 Teb: 7ffdc000 Unfrozen
结果表明有3个线程正在执行,当前线程为0号线程
执行~. 显示当前线程信息
3.显示当前线程的stack信息(!clrstack)
0:000> !clrstack -a
OS Thread Id: 0x104c (0)
ESP EIP
0012f350 7c812aeb [HelperMethodFrame: 0012f350]
0012f3f4 00d202e7 DBG.DoSomething.Doh(System.String, DBG.Days)
PARAMETERS:
this = 0x012f1a24
StrParam = 0x012f3cc0
ValueParam = 0x00000007
0012f418 00d20237 DBG.DoSomething.Reh(Int32, System.String)
PARAMETERS:
this = 0x012f1a24
i = 0x00000042
StrParam = 0x012f1a4c
LOCALS:
<CLR reg> = 0x012f3cc0
0x0012f41c = 0x00000007
0012f438 00d201a0 DBG.DoSomething.Mi(System.Object)
PARAMETERS:
this = 0x012f1a24
o = 0x012f1a24
LOCALS:
0x0012f438 = 0x012f1a4c
0012f450 00d20134 DBG.DoSomething.Fa()
PARAMETERS:
this = 0x012f1a24
0012f458 00d200b8 DBG.Program.Main(System.String[])
PARAMETERS:
args = 0x012f1a14
LOCALS:
0x0012f458 = 0x012f1a24
0012f69c 79e7be1b [GCFrame: 0012f69c]
显示DBG.DoSomething.Doh的传入参数为string和一个值为7的value type
DBG.DoSomething.Reh()有一个局部变量,地址为0x012f3cc0,如何知道它的内容呢?
!clrstack -a的执行结果显示的是函数参数和局部变量的信息,并没有显示有System.ArgumentException, 那么System.ArgumentException从何而来?
命令~* e !clrstack 列出所有线程的callstacks(~e 用来在一个或多个线程上执行命令)
命令!dumpstack 也用于显示线程call stack,如果缺少symbol信息,会提示错误"Use alternate method which may not work"
4.Dump变量的内容(!dumpobj or !do)
0:000> !dumpobj 0x012f3cc0
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 92(0x5c) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Tommy can you see me? Can you see me?
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 0 instance 38 m_arrayLength
790fdb60 4000097 8 System.Int32 0 instance 37 m_stringLength
790fad38 4000098 c System.Char 0 instance 54 m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 0014c4f0:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 0014c4f0:012f15e8 <<
>> Domain:Value 0014c4f0:012f15e8 << 显示了app domain中的静态变量
5.显示当前线程stack中的对象(!dumpstackobjects or !dso)
0:000> !dumpstackobjects
OS Thread Id: 0x104c (0)
ESP/REG Object Name
0012f2e4 012f4874 System.ArgumentException
0012f330 012f4874 System.ArgumentException
0012f340 012f38e4 System.String Reh =
0012f344 012f3cc0 System.String Tommy can you see me? Can you see me?
0012f348 012f1a24 DBG.DoSomething
0012f358 012f3cc0 System.String Tommy can you see me? Can you see me?
0012f364 012f38e4 System.String Reh =
0012f374 012f4874 System.ArgumentException
0012f378 012f2cf8 System.IO.StreamWriter
0012f37c 012f3cc0 System.String Tommy can you see me? Can you see me?
0012f384 012f1a24 DBG.DoSomething
0012f3ac 012f2cf8 System.IO.StreamWriter
0012f3d8 012f4874 System.ArgumentException
0012f3f4 012f48c0 System.String Throwing an exception
0012f3f8 012f4874 System.ArgumentException
0012f3fc 012f4828 System.String Fri
0012f400 012f3d78 DBG.Days
0012f404 012f1a24 DBG.DoSomething
0012f408 012f3cc0 System.String Tommy can you see me? Can you see me?
0012f40c 012f3cc0 System.String Tommy can you see me? Can you see me?
0012f420 012f1a24 DBG.DoSomething
0012f424 012f1b08 System.String DBG.DoSomething
0012f428 012f1b38 System.String Mi = DBG.DoSomething
0012f42c 012f1a24 DBG.DoSomething
0012f434 012f1a4c System.String Can you see me?
0012f438 012f1a4c System.String Can you see me?
0012f444 012f1a24 DBG.DoSomething
0012f450 012f1a24 DBG.DoSomething
0012f458 012f1a24 DBG.DoSomething
0012f45c 012f1a14 System.Object[] (System.String[])
0012f534 012f1a14 System.Object[] (System.String[])
0012f6e0 012f1a14 System.Object[] (System.String[])
0012f708 012f1a14 System.Object[] (System.String[])
Stack中有多个System.ArgumentException对象,但全部都引用了同一个对象:012f4874.
同一对象为什么会显示多次?
–这是由于对象被作为参数传递给多个函数
6.找出Exception
0:000> !dumpobj 012f4874
Name: System.ArgumentException
MethodTable: 7910139c
EEClass: 79101324
Size: 76(0x4c) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
790f9244 40000b5 4 System.String 0 instance 00000000 _className
79107d4c 40000b6 8 …ection.MethodBase 0 instance 00000000 _exceptionMethod
790f9244 40000b7 c System.String 0 instance 00000000 _exceptionMethodString
790f9244 40000b8 10 System.String 0 instance 012f48c0 _message
79112734 40000b9 14 …tions.IDictionary 0 instance 00000000 _data
790f984c 40000ba 18 System.Exception 0 instance 00000000 _innerException
790f9244 40000bb 1c System.String 0 instance 00000000 _helpURL
790f8a7c 40000bc 20 System.Object 0 instance 00000000 _stackTrace
790f9244 40000bd 24 System.String 0 instance 00000000 _stackTraceString
790f9244 40000be 28 System.String 0 instance 00000000 _remoteStackTraceString
790fdb60 40000bf 34 System.Int32 0 instance 0 _remoteStackIndex
790f8a7c 40000c0 2c System.Object 0 instance 00000000 _dynamicMethods
790fdb60 40000c1 38 System.Int32 0 instance -2147024809 _HResult
790f9244 40000c2 30 System.String 0 instance 00000000 _source
790fcfa4 40000c3 3c System.IntPtr 0 instance 0 _xptrs
790fdb60 40000c4 40 System.Int32 0 instance -532459699 _xcode
790f9244 40001e5 44 System.String 0 instance 012f48fc m_paramName
Exception的Message字段包含了重要的信息
0:000> !dumpobj 012f48c0
Name: System.String
MethodTable: 790f9244
EEClass: 790f91a4
Size: 60(0x3c) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Throwing an exception
Fields:
MT Field Offset Type VT Attr Value Name
790fdb60 4000096 4 System.Int32 0 instance 22 m_arrayLength
790fdb60 4000097 8 System.Int32 0 instance 21 m_stringLength
790fad38 4000098 c System.Char 0 instance 54 m_firstChar
790f9244 4000099 10 System.String 0 shared static Empty
>> Domain:Value 0014c4f0:790d57b4 <<
79122994 400009a 14 System.Char[] 0 shared static WhitespaceChars
>> Domain:Value 0014c4f0:012f15e8 <<
附录:
ABBA乐队的那首SOS