跟着John Robbins操练SOS

出自SOS: It’s Not Just an ABBA Song Anymore

实验代码:

    enum Days { Sat = 1, Sun, Mon, Tue, Wed, Thu, Fri } ;

    class DoSomething
    {
        public void Doh(String StrParam, Days ValueParam)
        {
            Console.WriteLine(StrParam);
            Console.WriteLine(ValueParam.ToString());
            throw new ArgumentException("Throwing an exception", "x");
        }

        public void Reh(int i, String StrParam)
        {
            Console.WriteLine("Reh = " + i);
            String s = "Tommy can you see me? " + StrParam;
            Days e = Days.Fri;
            Doh(s, e);
        }

        public void Mi(Object o)
        {
            Console.WriteLine("Mi = " + o.ToString());
            String LocalStr = "Can you see me?";
            Reh(0x42, LocalStr);
        }

        public void Fa()
        {
            Mi(this);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                DoSomething x = new DoSomething();
                x.Fa();
            }
            catch
            {
            }
        }
    }

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

This entry was posted in Debug. Bookmark the permalink.

Leave a comment