直来直去话人生 发表于 2023-11-8 13:22:14

Net 高级调试之六:对象检查之值类型、引用类型、数组和异常的转储

一、简介
     今天是《Net 高级调试》的第六篇文章。记得我刚接触 Net 框架的时候,还是挺有信心的,对所谓的值类型和引用类型也能说出自己的见解,毕竟,自己一直在努力。当然这些见解都是书本上的,并没有做到眼见为实,所以总是有些东西说不清楚。今天,我们就好好的说说 C# 的类型,是从内存级别、从底层来说一下值类型、引用类型到底是什么,它们在内存中的形态,还有也说说数组的内存形态,如何内部布局的,以及我们如何查找由未捕捉的异常引起的程序崩溃。这些都是基础的,如果这些掌握不好,以后的高级调试的道路,也不好走。自从我过了这一关,很多东西理解起来,比较透彻 了,但是,还必须努力。当然了,第一次看视频或者看书,是很迷糊的,不知道如何操作,还是那句老话,一遍不行,那就再来一遍,还不行,那就再来一遍,俗话说的好,书读千遍,其意自现。
     如果在没有说明的情况下,所有代码的测试环境都是 Net Framewok 4.8,但是,有时候为了查看源码,可能需要使用 Net Core 的项目,我会在项目章节里进行说明。好了,废话不多说,开始我们今天的调试工作。

       调试环境我需要进行说明,以防大家不清楚,具体情况我已经罗列出来。
          操作系统:Windows Professional 10
          调试工具:Windbg Preview(可以去Microsoft Store 去下载)
          开发工具:Visual Studio 2022
          Net 版本:Net Framework 4.8
          CoreCLR源码:源码下载

二、基础知识
    1、对象检查
        1.1、简介
            高级调试的目标就是分析应用程序故障所形成的原因,既然是故障,大多数情况下是对象的某种损坏,这就需要我们深入的了解各种对象的审查方法。

    2、各种检查方法
        2.1、内存转储
              这个方式非常底层,从内存地址上观察地址上的内容,常使用【dp】命令。出来【dp】命令,还有其他一些命令,比如:du,dw,db,da 等,如果想了解更多,可以查看 Windbg 的帮助文档,命令是【.hh】。

        2.2、对值类型的转储
              对值类型的转储非常的简单,一般通过【dp】命令观察内存地址,从内存上提取内容,可以在结束处观察 esp 指针,当然,如果知道栈地址,我们也可以使用【dp】命令查看内容,效果和查看 esp 是一样的。

        2.3、对应用类型的转储
              如果我们想查看引用类型的内容,我们可以使用【!do】命令,查看应用类型的内容。

        2.4、对数组的转储
              C# 数组的内存布局,大概有两种形式,值类型和引用类型。
              1)值类型数组。
                  结构:同步块索引,方法表,数组大小,数组元素1,数组元素2......

              2)引用类型数组。
                  结构:同步块索引,方法表,数组大小,数组元素1,数组元素2......
                                      |      |
                               |------------------+      +--------------------|
                               |                       |
                            同步块索引、方法表、内容        同步块索引、方法表、内容

        2.5、对异常的转储
              有时候,程序存在未处理的异常导致的崩溃,在事后分析 dump 中要是能找到这个异常,对我们分析和解决问题会有很大的帮助。如果我们想查看异常的详情,我们可以使用【!pe(print exception)】命令,打印异常的详情,当然也可以使用【!do】命令查看更详细的异常内容。

三、调试过程
    废话不多说,这一节是具体的调试操作的过程,又可以说是眼见为实的过程,在开始之前,我还是要啰嗦两句,这一节分为两个部分,第一部分是测试的源码部分,没有代码,当然就谈不上测试了,调试必须有载体。第二部分就是根据具体的代码来证实我们学到的知识,是具体的眼见为实。
    1、测试源码
        1.1、Example_6_1_1
1 namespace Example_6_1_1
2 {
3   internal class Program
4   {
5         static void Main(string[] args)
6         {
7             var person = new Person();
8
9             Console.ReadLine();
10         }
11   }
12
13   internal class Person
14   {
15         public int Age = 20;
16
17         public string Name = "jack";
18   }
19 }View Code
        1.2、Example_6_1_2
1 namespace Example_6_1_2
2 {
3   internal class Program
4   {
5         static void Main(string[] args)
6         {
7             Debugger.Break();
8
9             int a = 10;
10             int b = 11;
11             int c = 12;
12             int d = 13;
13         }
14   }
15 }View Code
        1.3、Example_6_1_3
1 namespace Example_6_1_3
2 {
3   internal class Program
4   {
5         static void Main(string[] args)
6         {
7             int[] intArr = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
8
9             string[] stringArr = { "1", "2", "3", "4", "5" };
10
11             Debugger.Break();
12         }
13   }
14 }View Code
        1.4、Example_6_1_4
1 namespace Example_6_1_4
2 {
3   internal class Program
4   {
5         static void Main(string[] args)
6         {
7             Console.WriteLine($"请输入一个能够整除的数字:");
8             var num = Console.ReadLine();
9
10             var ret = 10 / Convert.ToInt32(num);
11         }
12   }
13 }View Code
    2、眼见为实
        项目的所有操作都是一样的,所以就在这里说明一下,但是每个测试例子,都需要重新启动,并加载相应的应用程序,加载方法都是一样的。流程如下:我们编译项目,打开 Windbg,点击【文件】----》【launch executable】附加程序,打开调试器的界面,程序已经处于中断状态。我们需要使用【g】命令,继续运行程序,然后到达指定地点停止后,我们可以点击【break】按钮,就可以调试程序了。有时候可能需要切换到主线程,可以使用【~0s】命令。

        2.1、内存转储
            测试代码:Example_6_1_1
            我们首先去托管堆中查找一下 Person 对象。【dp】命令的 p 是 pointer,指针的意思。
1 0:006> !dumpheap -type Person
2Address       <strong>MT</strong>   Size
3 031424c8 <strong>013d4dec</strong>       16   
4
5 Statistics:
6       MT    Count    TotalSize Class Name
7 013d4dec      1         16 Example_6_1_1.Person
8 Total 1 objects            031424c8(Person 对象的指针地址) 013d4dec(Person 方法表的地址)

1 0:006> !dumpobj /d 031424c8
2 Name:      Example_6_1_1.Person
3 <strong>MethodTable: 013d4dec
</strong> 4 EEClass:   013d12f0
5 Size:      16(0x10) bytes
6 File:      E:\Visual Studio 2022\Source\Projects\....\Example_6_1_1\bin\Debug\Example_6_1_1.exe
7 Fields:
8       MT    Field   Offset               Type VT   Attr    Value Name
9 706342a84000001      8         System.Int321 instance       20 Age
10 706324e44000002      4      System.String0 instance 031424d8 Name 
            上面两段代码,红色标注的就是 Person 对象的方法表的地址,他们是一样的。我们有了对象的地址,对象的地址其实就是类型句柄的地址,也就是知道通过快索引的地址,只要减去 0x4就可以,说明一下,每个引用类型都包含【同步块索引】和【类型句柄】。
 
1 0:006> dp 031424c8-0x4 l4
2 031424c400000000 013d4dec 031424d8 00000014 
             00000000 就是同步块索引,后面的 013d4dec 就是方法表的地址,最后两项就是 Person 具体的值。00000014 就是十进制的20,也就是 Person 对象的 Age 字段的值。031424d8 就是 Person 对象的 Name 的值。我们来验证。
1 0:006> !do 031424d8
2 Name:      System.String
3 MethodTable: 706324e4
4 EEClass:   70737690
5 Size:      22(0x16) bytes
6 File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
7 String:      <strong>jack
</strong> 8 Fields:
9       MT    Field   Offset               Type VT   Attr    Value Name
10 706342a84000283      4         System.Int321 instance      4 m_stringLength
11 70632c9c4000284      8          System.Char1 instance       6a m_firstChar
12 706324e44000288       70      System.String0   shared   static Empty
13   >> Domain:Value01472260:NotInit<<
14
15
16 0:006> ? 00000014
17 Evaluate expression: <strong>20</strong> = 00000014              红色标注的就是具体的值。我们可以继续使用【dp】命令,查看 name 的详情。
1 0:006> dp 031424d8 l4
2 031424d8706324e4 00000004 0061006a 006b0063              031424d8(字符串 Name 的地址) 706324e4(name 的方法表的地址) 00000004(字符串的长度) 0061006a 006b0063(这两项就是具体的值),字符串的长度,我们可以通过 name 的地址加上 0x4,就可以得到字符串的长度。

1 0:006> dp 031424d8+0x4 l4
2 031424dc00000004 0061006a 006b0063 00000000 
              为什么是加上 0x4,因为我们在使用【!do】命令,查看 name 详情的时候,m_stringLength 的偏移量是4。      
              
              0061006a(看地址,我们是从低地址往高地址看),所以我们先看 006a,然后再查看 0061,006b0063这个地址也是一样的。我们可以使用【du】命令查看它的内容,u就是 Unicode。006a 就是 j,0061就是a,0063就是 c,006b就是k。
1 0:006> du 031424d8+0x8
2 031424e0"jack"              为什么加 0x8,因为偏移量是8。

        2.2、对值类型的转储。
            测试代码:Example_6_1_2
            我们首先找到栈地址,可以使用【!clrstack】命令,有了栈地址,我们可以使用【bp】命令在该地址上设置断点。
1 0:000> !clrstack
2 OS Thread Id: 0x358c (0)
3 Child SP       IP Call Site
4 007af2e0 7566f262 System.Diagnostics.Debugger.BreakInternal()
5 007af35c 7146f195 System.Diagnostics.Debugger.Break()
6 007af384 <strong>029e0879</strong> Example_6_1_2.Program.Main(System.String[])
7 007af504 71daf036             红色标注的【029e0879】就是【Program.Main】方法的栈地址,然后我们设置断点,【g】继续运行。
1 0:000> bp 029e0879
2 0:000> g
3 Breakpoint 0 hit
4 eax=00000000 ebx=007af434 ecx=72227ced edx=00b239b0 esi=00000000 edi=007af3b0
5 eip=029e0879 esp=007af384 ebp=007af398 iopl=0         nv up ei pl zr na pe nc
6 cs=0023ss=002bds=002bes=002bfs=0053gs=002b             efl=00000246
7 Example_6_1_2!COM+_Entry_Point <PERF> (Example_6_1_2+0x23d0879):
8 029e0879 90            nop            在断点处暂停,如图:
            
            然后,使用【g】命令,继续运行。
1 0:000> g
2 Breakpoint 1 hit
3 eax=00000000 ebx=007af434 ecx=72227ced edx=00b239b0 esi=00000000 edi=007af3b0
4 eip=029e0896 esp=007af384 ebp=007af398 iopl=0         nv up ei pl zr na pe nc
5 cs=0023ss=002bds=002bes=002bfs=0053gs=002b             efl=00000246
6 Example_6_1_2!COM+_Entry_Point <PERF> (Example_6_1_2+0x23d0896):
7 029e0896 90            nop            然后,我们使用【dp esp】命令查看详细,当然我们可以可以使用【dp 007af384】,dp 命令后跟的是栈地址,都是可以的。
1 0:000> dp esp
2 007af384<strong>0000000d 0000000c 0000000b 0000000a
</strong>3 007af39402a024bc 007af3a4 71daf036 00b239b0
4 007af3a4007af3f8 71db22da 007af434 007af3e8
5 007af3b471ea23d0 007af504 71db2284 b7ed3afc
6 007af3c4007af544 007af4c8 007af47c 71dbec59
7 007af3d4007af434 00000000 b7ed3afc 007af3b0
8 007af3e4007af4c8 007af574 71ea09b0 c64cea1c
9 007af3f400000001 007af460 71db859b 00000000            红色标注的就是变量赋的值。汇编代码如下:

            
            当然,我们也可以通过【!clrstack -l】命令也可以找到所有局部变量。
1 0:000> !clrstack -l
2 OS Thread Id: 0x358c (0)
3 Child SP       IP Call Site
4 007af384 029e0896 Example_6_1_2.Program.Main(System.String[])
5   LOCALS:
6         0x007af390 = 0x0000000a(a 变量的值,等号前面是栈地址)
7         0x007af38c = 0x0000000b(a 变量的值,等号前面是栈地址,等不 a 的栈地址减去 0x4)
8         0x007af388 = 0x0000000c(a 变量的值,等号前面是栈地址,等不 b 的栈地址减去 0x4)
9         0x007af384 = 0x0000000d(a 变量的值,等号前面是栈地址,等不 c 的栈地址减去 0x4)
10
11 007af504 71daf036             栈地址是由高到低分配的,0x007af384 是变量d 的地址,0x007af384+0x4=0x007af388,这个地址就是c 变量的地址,0x007af388+0x4=0x007af38c,0x007af38c这个地址就是 b 变量的地址,0x007af38c+0x4就是 a 变量的地址,也就是 0x007af390。

        2.3、对应用类型的转储。
            测试代码:Example_6_1_1
1 0:000> !clrstack -l
2 OS Thread Id: 0x38fc (0)
3 Child SP       IP Call Site
4 00aff25c 777110fc
5 00aff258 70d99b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
6
7 ...
8
9 00aff358 0117088e Example_6_1_1.Program.Main(System.String[])
10   LOCALS:
11         0x00aff360 = 0x02bb24c8
12
13 00aff4dc 71daf036             我们查看线程栈了,找到了局部变量。也找到了地址,我们通过【!do】或者【!dumpobj】查看Person 变量。
1 0:000> !DumpObj /d 02bb24c8
2 Name:      Example_6_1_1.Person
3 MethodTable: 00d14dec
4 EEClass:   00d112f0
5 Size:      16(0x10) bytes
6 File:      E:\Visual Studio 2022\Source\Projects\...\Example_6_1_1\bin\Debug\Example_6_1_1.exe
7 Fields:
8       MT    Field   Offset               Type VT   Attr    Value Name
9 708f42a84000001      8         System.Int321 instance       20 Age
10 708f24e44000002      4      System.String0 instance <strong>02bb24d8</strong> Name(红色又是一个地址)            红色的可以在【!do】,我们就可以看到详情。
1 0:000> !DumpObj /d 02bb24d8
2 Name:      System.String
3 MethodTable: 708f24e4
4 EEClass:   709f7690
5 Size:      22(0x16) bytes
6 File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
7 String:      <strong>jack(字符串 name 变量的值)
</strong> 8 Fields:
9       MT    Field   Offset               Type VT   Attr    Value Name
10 708f42a84000283      4         System.Int321 instance      4 m_stringLength
11 708f2c9c4000284      8          System.Char1 instance       6a m_firstChar
12 708f24e44000288       70      System.String0   shared   static Empty
13   >> Domain:Value00d6d780:NotInit<<                我们可以点击栈地址后面的地址,就可以查看详情,相当于【!do】命令。
1 0:000> dp 02bb24c8 l4
2 02bb24c8<strong>00d14dec</strong> <strong>02bb24d8</strong> <strong>00000014</strong> 80000000                使用【dp】命令,查看结果。                
1 0:000> !clrstack -l
2 OS Thread Id: 0x2e54 (0)
3 Child SP       IP Call Site
4 00afeeec 7566f262 System.Diagnostics.Debugger.BreakInternal()
5 00afef68 7146f195 System.Diagnostics.Debugger.Break()
6
7 00afef90 00ce0920 Example_6_1_3.Program.Main(System.String[])
8   LOCALS:
9         <strong>0x00afef9c</strong> = 0x02b82518(int 数组,值类型数组)
10         <strong>0x00afef98</strong> = 0x02b82574(string 数组,引用类型的数组)
11
12 00aff118 71daf036                 00000000 表示的同步块所有,为0就是什么数据都没有,708f426c 就是方法表的地址。0000000b 表示的数组长度,十进制是11,表示有11个元素。此项后面的就是数组元素了。
                  如果想可视化的查看,可以使用命令【!da -details】,内容太多,折叠了。

1 0:000> !DumpObj /d 02b82518
2 Name:      System.Int32[]
3 MethodTable: 708f426c
4 EEClass:   709f805c
5 Size:      56(0x38) bytes
6 Array:       Rank 1, Number of elements 11, Type Int32 (Print Array)
7 Fields:
8 None
9 0:000> !DumpObj /d 02b82574
10 Name:      System.String[]
11 MethodTable: 708f2d74
12 EEClass:   709f7820
13 Size:      32(0x20) bytes
14 Array:       Rank 1, Number of elements 5, Type CLASS (Print Array)
15 Fields:
16 NoneView Code
           2)引用类型数组
              我们定义的数组:string[] stringArr = { "1", "2", "3", "4", "5" };
1 0:000> dp 0x02b82518-0x4 L20(为什么要减去 0x4,因为当前对象的指针指向方法表,每个域是占用4个字节,L20 的l 是不区分大小写的)
2 02b82514<strong>00000000</strong><strong> 708f426c</strong> <strong>0000000b</strong> <strong>0000000a
</strong>3 02b82524<strong>0000000b 0000000c 0000000d 0000000e
</strong>4 02b82534<strong>0000000f</strong> <strong>00000010</strong> <strong>00000011 00000012</strong>
5 02b82544<strong>00000013 00000014</strong> 00000000 708f4354
6 02b8255400000000 00000000 00000000 00000000
7 02b8256400000000 00000000 00c44dd8 00000000
8 02b82574708f2d74 00000005 02b824c8 02b824d8
9 02b8258402b824e8 02b824f8 02b82508 00000000              我们同样使用【dp】命令,查看详情。
1 0:000> !da -details 0x02b82518
2 Name:      System.Int32[]
3 MethodTable: 708f426c
4 EEClass:   709f805c
5 Size:      56(0x38) bytes
6 Array:       Rank 1, Number of elements 11, Type Int32
7 Element Methodtable: 708f42a8
8 02b82520
9   Name:      System.Int32
10   MethodTable: 708f42a8
11   EEClass:   709f8014
12   Size:      12(0xc) bytes
13   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
14   Fields:
15               MT    Field   Offset               Type VT   Attr    Value Name
16         708f42a840005a2      0             System.Int32      1   instance         10   m_value
17 02b82524
18   Name:      System.Int32
19   MethodTable: 708f42a8
20   EEClass:   709f8014
21   Size:      12(0xc) bytes
22   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
23   Fields:
24               MT    Field   Offset               Type VT   Attr    Value Name
25         708f42a840005a2      0             System.Int32      1   instance         11   m_value
26 02b82528
27   Name:      System.Int32
28   MethodTable: 708f42a8
29   EEClass:   709f8014
30   Size:      12(0xc) bytes
31   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
32   Fields:
33               MT    Field   Offset               Type VT   Attr    Value Name
34         708f42a840005a2      0             System.Int32      1   instance         12   m_value
35 02b8252c
36   Name:      System.Int32
37   MethodTable: 708f42a8
38   EEClass:   709f8014
39   Size:      12(0xc) bytes
40   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
41   Fields:
42               MT    Field   Offset               Type VT   Attr    Value Name
43         708f42a840005a2      0             System.Int32      1   instance         13   m_value
44 02b82530
45   Name:      System.Int32
46   MethodTable: 708f42a8
47   EEClass:   709f8014
48   Size:      12(0xc) bytes
49   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
50   Fields:
51               MT    Field   Offset               Type VT   Attr    Value Name
52         708f42a840005a2      0             System.Int32      1   instance         14   m_value
53 02b82534
54   Name:      System.Int32
55   MethodTable: 708f42a8
56   EEClass:   709f8014
57   Size:      12(0xc) bytes
58   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
59   Fields:
60               MT    Field   Offset               Type VT   Attr    Value Name
61         708f42a840005a2      0             System.Int32      1   instance         15   m_value
62 02b82538
63   Name:      System.Int32
64   MethodTable: 708f42a8
65   EEClass:   709f8014
66   Size:      12(0xc) bytes
67   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
68   Fields:
69               MT    Field   Offset               Type VT   Attr    Value Name
70         708f42a840005a2      0             System.Int32      1   instance         16   m_value
71 02b8253c
72   Name:      System.Int32
73   MethodTable: 708f42a8
74   EEClass:   709f8014
75   Size:      12(0xc) bytes
76   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
77   Fields:
78               MT    Field   Offset               Type VT   Attr    Value Name
79         708f42a840005a2      0             System.Int32      1   instance         17   m_value
80 02b82540
81   Name:      System.Int32
82   MethodTable: 708f42a8
83   EEClass:   709f8014
84   Size:      12(0xc) bytes
85   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
86   Fields:
87               MT    Field   Offset               Type VT   Attr    Value Name
88         708f42a840005a2      0             System.Int32      1   instance         18   m_value
89 02b82544
90   Name:      System.Int32
91   MethodTable: 708f42a8
92   EEClass:   709f8014
93   Size:      12(0xc) bytes
94   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
95   Fields:
96               MT    Field   Offset               Type VT   Attr    Value Name
97         708f42a840005a2      0             System.Int32      1   instance         19   m_value
98 02b82548
99   Name:      System.Int32
100   MethodTable: 708f42a8
101   EEClass:   709f8014
102   Size:      12(0xc) bytes
103   File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
104   Fields:
105               MT    Field   Offset               Type VT   Attr    Value Name
106         708f42a840005a2      0             System.Int32      1   instance         20   m_value              我们使用【!do】命令,查看元素详情。
1 0:000> !clrstack -l
2 OS Thread Id: 0x2e54 (0)
3 Child SP       IP Call Site
4 00afeeec 7566f262 System.Diagnostics.Debugger.BreakInternal()
5 00afef68 7146f195 System.Diagnostics.Debugger.Break()
6
7 00afef90 00ce0920 Example_6_1_3.Program.Main(System.String[])
8   LOCALS:
9         0x00afef9c = 0x02b82518
10         0x00afef98 = 0x02b82574(引用类型的数组)
11
12 00aff118 71daf036
13 0:000> !DumpObj /d 02b82574
14 Name:      System.String[]
15 MethodTable: 708f2d74
16 EEClass:   709f7820
17 Size:      32(0x20) bytes
18 Array:       Rank 1, Number of elements 5, Type CLASS (Print Array)
19 Fields:
20 None                我们可以继续使用【!do】命令查看异常对象。
1 0:000> !DumpObj /d 028450c0 2 Name:      System.DivideByZeroException 3 MethodTable: 708fd01c 4 EEClass:   70ad84fc 5 Size:      84(0x54) bytes 6 File:      C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll 7 Fields: 8       MT    Field   Offset               Type VT   Attr    Value Name 9 708f24e440002a4      4      System.String0 instance 0284ce64 _className10 708f6f2840002a5      8 ...ection.MethodBase0 instance 00000000 _exceptionMethod11 708f24e440002a6      c      System.String0 instance 00000000 _exceptionMethodString12 708f24e440002a7       10      System.String0 instance 0284b5d8 _message13 7093f8fc40002a8       14 ...tions.IDictionary0 instance 00000000 _data14 708f25d440002a9       18   System.Exception0 instance 00000000 _innerException15 708f24e440002aa       1c      System.String0 instance 00000000 _helpURL16 708f273440002ab       20      System.Object0 instance 0284b670 _stackTrace17 708f273440002ac       24      System.Object0 instance 0284b6a0 _watsonBuckets18 708f24e440002ad       28      System.String0 instance 00000000 _stackTraceString19 708f24e440002ae       2c      System.String0 instance 00000000 _remoteStackTraceString20 708f42a840002af       3c         System.Int321 instance      0 _remoteStackIndex21 708f273440002b0       30      System.Object0 instance 00000000 _dynamicMethods22 708f42a840002b1       40         System.Int321 instance -2147352558 _HResult23 708f24e440002b2       34      System.String0 instance 00000000 _source24 708f7b1840002b3       44      System.IntPtr1 instance   6fe8a4 _xptrs25 708f42a840002b4       48         System.Int321 instance -1073741676 _xcode26 70903adc40002b5       4c       System.UIntPtr1 instance      0 _ipForWatsonBuckets27 709362d040002b6       38 ...ializationManager0 instance 0284b654 _safeSerializationManager28 708f273440002a3       84      System.Object0   shared   static s_EDILock29   >> Domain:Value00817c30:NotInit
页: [1]
查看完整版本: Net 高级调试之六:对象检查之值类型、引用类型、数组和异常的转储