.NET程序包括运行时对象均是自描述的,我们可以从PE文件,以及在Windbg调试时可以得到很多的辅助调试信息,关于运行时对象,1.1版本有一些参考资料。.NET 4.0相关的资料几乎没有找到,如果谁有能发站内的信件告诉我,不胜感激。想了很久,还是把自己最近的调查写出来,留作纪念,待以后补充。错误的地方以后会修改。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace WindbugDemo 7 { 8 public class Person 9 { 10 //认为BMI和21偏差最小的为最健康的 11 private const double BmiHelthConst = 21f; 12 13 public string Name { get; set; } 14 public int Age { get; set; } 15 public double Height { get; set; } 16 public double Weight { get; set; } 17 public double BmiVariance { get;set;} 18 19 public Person(string name,int age,double height,double weight) 20 { 21 this.Name = name; 22 this.Age = age; 23 this.Height = height; 24 this.Weight = weight; 25 this.GetBmiVariance(); 26 } 27 28 public void GetBmiVariance() 29 { 30 double bmi = Math.Round(Weight / Math.Pow(Height, 2),2); 31 BmiVariance = Math.Abs(bmi - BmiHelthConst); 32 } 33 } 34 35 class Health 36 { 37 [STAThread] 38 static void Main(string[] args) 39 { 40 Person person = new Person ("James",35,1.70,70); 41 string text = string.Format("Name:{0} Age:{1} Height:{2} Weight:{3} BMI Variance:{4}", 42 person.Name,person.Age, person.Height, person.Weight, person.BmiVariance); 43 System.Console.WriteLine(text); 44 Console.ReadKey(); 45 /* 46 Name:Tony Age:25 Height:1.65 Weight:60 BMI Variance:1.04 47 */ 48 } 49 } 50 51 }
还是前面的程序,略做改造。Windbg启动EXE程序,在41行打上断点。运行!clrstack命令。
0:000> !clrstack -a OS Thread Id: 0xb70 (0) Child SP IP Call Site 001dee3c 005d00fc WindbugDemo.Health.Main(System.String[]) [d:\source\02Health\Health.cs @ 41] PARAMETERS: args (0x001deebc) = 0x01d72180 LOCALS: 0x001dee7c = 0x01d7222c 0x001dee78 = 0x00000000 0x001dee74 = 0x01d722ec 001df050 67902552 [GCFrame: 001df050] 0:000> dd 0x01d7222c 01d7222c 005638e4 33333333 3ffb3333 00000000 01d7223c 40518000 5c28f5c0 4009c28f 01d72190 01d7224c 00000023 00000000 5d8341b8 00000000 01d7225c 00000000 5d83fe70 00000010 00000000 01d7226c 3ff00000 00000000 40240000 00000000 01d7227c 40590000 00000000 408f4000 00000000 01d7228c 40c38800 00000000 40f86a00 00000000 01d7229c 412e8480 00000000 416312d0 00000000 0:000> dd 005638e4 005638e4 01000000 00000028 00020180 00000004 005638f4 5d8341b8 00562edc 00563920 0056130c 00563904 00000000 00000000 00563910 5d71952c 00563914 5d72ec30 5d72e860 5d72e2a0 00000080 00563924 00000000 00000000 00000000 00000000 00563934 00000000 00000000 00000000 00000000 00563944 00000000 00000000 00000000 00000000 00563954 00000000 00000000 00000000 00000000 0:000> !dumpmt -md 005638e4 EEClass: 0056130c Module: 00562edc Name: WindbugDemo.Person mdToken: 02000002 File: D:\bin\Health.exe BaseSize: 0x28 ComponentSize: 0x0 Slots in VTable: 16 Number of IFaces in IFaceMap: 0 -------------------------------------- MethodDesc Table Entry MethodDe JIT Name 5d71952c 5d43612c PreJIT System.Object.ToString() 5d72ec30 5d436134 PreJIT System.Object.Equals(System.Object) 5d72e860 5d436154 PreJIT System.Object.GetHashCode() 5d72e2a0 5d436168 PreJIT System.Object.Finalize() 0056c02d 00563848 NONE WindbugDemo.Person.get_Name() 005d0310 00563854 JIT WindbugDemo.Person.set_Name(System.String) 0056c035 00563860 NONE WindbugDemo.Person.get_Age() 005d0350 0056386c JIT WindbugDemo.Person.set_Age(Int32) 005d0518 00563878 JIT WindbugDemo.Person.get_Height() 005d0388 00563884 JIT WindbugDemo.Person.set_Height(Double) 005d04d8 00563890 JIT WindbugDemo.Person.get_Weight() 005d03c0 0056389c JIT WindbugDemo.Person.set_Weight(Double) 0056c04d 005638a8 NONE WindbugDemo.Person.get_BmiVariance() 005d0558 005638b4 JIT WindbugDemo.Person.set_BmiVariance(Double) 005d0288 005638c0 JIT WindbugDemo.Person..ctor(System.String, Int32, Double, Double) 005d03f8 005638cc JIT WindbugDemo.Person.GetBmiVariance()0:000> !do 5d8341b8 <Note: this object has an invalid CLASS field> Invalid object 0:000> !dumpmodule 5d8341b8 Fail to fill Module 5d8341b8 0:000> !dumpmt 5d8341b8 EEClass: 5d4339a4 Module: 5d431000 Name: System.Object mdToken: 02000002 File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll BaseSize: 0xc ComponentSize: 0x0 Slots in VTable: 12 Number of IFaces in IFaceMap: 00:000> !dumpclass 0056130c Class Name: WindbugDemo.Person mdToken: 02000002 File: D:\bin\Health.exe Parent Class: 5d4339a4 Module: 00562edc Method Table: 005638e4 Vtable Slots: 4 Total Method Slots: 4 Class Attributes: 100001 Transparency: Critical NumInstanceFields: 5 NumStaticFields: 0 MT Field Offset Type VT Attr Value Name 5d833e18 4000002 1c System.String 0 instance <Name>k__BackingField 5d83560c 4000003 20 System.Int32 1 instance <Age>k__BackingField 5d83fa00 4000004 4 System.Double 1 instance <Height>k__BackingField 5d83fa00 4000005 c System.Double 1 instance <Weight>k__BackingField 5d83fa00 4000006 14 System.Double 1 instance <BmiVariance>k__BackingField
0x01d7222c这个地址是Person对象,使用dd命令转储出来以后,第一个应该是指向改对象的类型句柄,再次使用dd命令进行转储。把上面标的五颜六色的地方,摘出来单独进行解析。
0:000> dd 005638e4 005638e4 01000000 00000028 00020180 00000004 005638f4 5d8341b8 00562edc 00563920 0056130c 00563904 00000000 00000000 00563910 5d71952c 00563914 5d72ec30 5d72e860 5d72e2a0 00000080 00563924 00000000 00000000 00000000 00000000 00563934 00000000 00000000 00000000 00000000 00563944 00000000 00000000 00000000 00000000 00563954 00000000 00000000 00000000 00000000
1、01000000 应该是该对象的枚举值,表示为类。
2、00000028应该是描述该对象的元数据所占的尺寸。
3、5d8341b8为父类的方法表。
4、00562edc 为该对象的Module。
5、0056130c为EEClass指针。
6、5d71952c 5d72ec30 5d72e860 5d72e2a0 为预JIT编译的四个方法的入口。
5d71952c 5d43612c PreJIT System.Object.ToString()
5d72ec30 5d436134 PreJIT System.Object.Equals(System.Object)
5d72e860 5d436154 PreJIT System.Object.GetHashCode()
5d72e2a0 5d436168 PreJIT System.Object.Finalize()
如果要做更详尽的解读的话,要详细看一下SSCLI源码,天书一样,看起来也很费劲,只能慢慢研究了。
参考资料:
1、.NET 高级调试
2、https://www.cnblogs.com/awpatp/archive/2009/11/11/1601397.html