1 namespace Example_3_1_1 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 int a = 10; 8 long b = 11; 9 short c = 12; 10 Console.ReadLine(); 11 } 12 } 13 }
1 namespace Example_3_1_2 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 var person = new Person() 8 { 9 Name = "jack", 10 Age = 20 11 }; 12 Console.ReadLine(); 13 } 14 } 15 16 public class Person 17 { 18 public string Name { get; set; } 19 20 public int Age { get; set; } 21 } 22 }
1 namespace Example_3_1_3 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 var person = new Person() { Name = "jack", Age = 20 }; 8 var hashcode = person.GetHashCode().ToString("x"); 9 Console.WriteLine($"hashcode={hashcode}"); 10 Debugger.Break(); 11 Console.ReadLine(); 12 } 13 } 14 15 public class Person 16 { 17 public string Name { get; set; } 18 19 public int Age { get; set; } 20 } 21 }
1 namespace Example_3_1_4 2 { 3 internal class Program 4 { 5 public static Person person=new Person(); 6 7 static void Main(string[] args) 8 { 9 Task.Run(() => 10 { 11 lock (person) 12 { 13 Console.WriteLine($"tid={Environment.CurrentManagedThreadId}進入鎖了"); 14 Console.ReadLine(); 15 } 16 }); 17 Task.Run(() => { 18 lock (person) 19 { 20 Console.WriteLine($"tid={Environment.CurrentManagedThreadId}進入鎖了"); 21 Console.ReadLine(); 22 } 23 }); 24 25 Console.ReadLine(); 26 } 27 } 28 29 public class Person 30 { 31 public string Name { get; set; } 32 33 public int Age { get; set; } 34 } 35 }
1.5、Example_3_1_5
1 namespace Example_3_1_5 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 var person = new Person() 8 { 9 Name = "jack", 10 Age = 20 11 }; 12 Console.WriteLine("Hello World!"); 13 Console.ReadLine(); 14 } 15 } 16 public class Person 17 { 18 public string Name { get; set; } 19 20 public int Age { get; set; } 21 } 22 }
1.6、Example_3_1_5_1(這個專案是 Net 7.0版本的)
1 namespace Example_3_1_5_1 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 var person = new Person() 8 { 9 Name = "jack", 10 Age = 20 11 }; 12 Console.WriteLine("Hello World!"); 13 Console.ReadLine(); 14 } 15 } 16 public class Person 17 { 18 public string Name { get; set; } 19 20 public int Age { get; set; } 21 } 22 }
1 0:000> !clrstack -l 2 OS Thread Id: 0x317c (0) 3 Child SP IP Call Site 4 00aff1c4 778e10fc [InlinedCallFrame: 00aff1c4] 5 00aff1c0 6fee9b71 ...(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr) 6 7 ...... 8 9 00aff2c0 00d3089e Example_3_1_1.Program.Main(System.String[]) [E:\...\Example_3_1_1\Program.cs @ 12] 10 LOCALS:【表示區域性變數】 11 0x00aff2d0 = 0x0000000a【0x00aff2d0是棧地址,0x0000000a 是棧上的值,這是十六進位制的】 12 0x00aff2c8 = 0x0000000b【0x00aff2c8是棧地址,0x0000000b 是棧上的值,這是十六進位制的】 13 0x00aff2c4 = 0x0000000c【0x00aff2d0是棧地址,0x0000000c 是棧上的值,這是十六進位制的】 14 15 00aff448 70f1f036 [GCFrame: 00aff448]
以上顯示的紅色部分是最重要的,LOCALS 表示區域性變數,11,12,13 三行是具體的區域性變數,等號前面是 執行緒棧上的變數地址,後面是具體的值,我們可以使用【?】命令檢視具體的值。
1 0:000> ? 0x0000000a 2 Evaluate expression: 10 = 0000000a 3 0:000> ? 0x0000000b 4 Evaluate expression: 11 = 0000000b 5 0:000> ? 0x0000000c 6 Evaluate expression: 12 = 0000000c
1 0:000> dp 0x00aff2c4 l4 2 00aff2c4 0000000c 0000000b 00000000 0000000a
1 0:000> dp 00aff2c4+0x4 l1 2 00aff2c8 0000000b
繼續驗證,【b】的地址加上 0x8,就是【a】變數的值,為什麼是加8呢,因為【b】佔用8個位元組,如下:
1 0:000> dp 00aff2c8+0x8 l1 2 00aff2d0 0000000a
當然,我們可以以【c】變數的地址為基準,算出【b】和【a】的值,如下:
1 0:000> dp 0x00aff2c4+0x4 l1(以c 的地址為基準,找到b的地址,加4) 2 00aff2c8 0000000b 3 0:000> dp 0x00aff2c4+0xc l1(以c 的地址為基準,找到a的地址,加12,十六進位制就是0xc) 4 00aff2d0 0000000a
1 0:000> !clrstack -a 2 OS Thread Id: 0x3930 (0) 3 Child SP IP Call Site 4 0133ee8c 778e10fc [InlinedCallFrame: 0133ee8c] 5 0133ee88 6fee9b71 6 ...... 7 0133ef88 018c08b1 Example_3_1_2.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\......\Example_3_1_2\Program.cs @ 14] 8 PARAMETERS: 9 args (0x0133ef94) = 0x033b24bc 10 LOCALS: 11 0x0133ef90 = 0x033b24e0(0x0133ef90 是棧地址,0x033b24e0 person變數的參照地址) 12 13 0133f108 70f1f036 [GCFrame: 0133f108]
我們可以通過【dp】命令檢視棧地址,值是 033b24e0,這個值就是 person變數參照的地址。
1 0:000> dp 0x0133ef90 l1 2 0133ef90 033b24e0(這個地址就是 person變數的地址)
我們可以使用【!do|!DumpObj】命令,檢視物件的詳情。
1 0:000> !DumpObj /d 033b24e0 2 Name: Example_3_1_2.Person 3 MethodTable: 01874e1c 4 EEClass: 01871314 5 Size: 16(0x10) bytes 6 File: E:\Visual Studio 2022\Source\Projects\......\Example_3_1_2\bin\Debug\Example_3_1_2.exe 7 Fields: 8 MT Field Offset Type VT Attr Value Name 9 6fa424e4 4000001 4 System.String 0 instance 033b24c8 <Name>k__BackingField 10 6fa442a8 4000002 8 System.Int32 1 instance 20 <Age>k__BackingField
033b24c8 <Name>k__BackingField,這個是 string 型別的欄位,033b24c8又是一個參照地址,我們繼續【!do】,檢視詳情。
1 0:000> !DumpObj /d 033b24c8 2 Name: System.String 3 MethodTable: 6fa424e4 4 EEClass: 6fb47690 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: jack(這個就是我們賦值的) 8 Fields: 9 MT Field Offset Type VT Attr Value Name 10 6fa442a8 4000283 4 System.Int32 1 instance 4 m_stringLength 11 6fa42c9c 4000284 8 System.Char 1 instance 6a m_firstChar 12 6fa424e4 4000288 70 System.String 0 shared static Empty 13 >> Domain:Value 0151ca70:NotInit <<
每一個參照型別物件都包含兩個附加欄位,一個是同步塊索引,另外一個就是型別控制程式碼。我們通過 !clrstack -l 獲取的 Program.Main 方法的控制程式碼變數,我們可以通過【dp】命令檢視一下細節,執行如下命令:dp 0x033b24e0-0x4 l4(LOCALS:0x0133ef90 = 0x033b24e0)
1 0:000> dp 0x033b24e0-0x4 l4 2 033b24dc 00000000 01874e1c 033b24c8 00000014
033b24dc 00000000 01874e1c 033b24c8 00000014,033b24dc 這個地址就是同步塊的地址,0x033b24e0 person參照地址只想型別控制程式碼01874e1c,型別控制程式碼再用4個位元組,所以 0x033b24e0-0x4,向前移動4個位元組,就是同步塊的指標地址。033b24c8這個部分就是person變數的範例欄位了。
1 0:000> !do 033b24c8 2 Name: System.String 3 MethodTable: 6fa424e4 4 EEClass: 6fb47690 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: jack 8 Fields: 9 MT Field Offset Type VT Attr Value Name 10 6fa442a8 4000283 4 System.Int32 1 instance 4 m_stringLength 11 6fa42c9c 4000284 8 System.Char 1 instance 6a m_firstChar 12 6fa424e4 4000288 70 System.String 0 shared static Empty 13 >> Domain:Value 0151ca70:NotInit <<
00000014是十六進位制的,表示的就是20。
1 0:000> ? 00000014 2 Evaluate expression: 20 = 00000014
如果我們想檢視型別控制程式碼的詳情,我們可以使用【!dumpmt】命令。
1 0:000> !dumpmt 01874e1c 2 EEClass: 01871314 3 Module: 01874044 4 Name: Example_3_1_2.Person 5 mdToken: 02000003 6 File: E:\Visual Studio 2022\Source\Projects\......\Example_3_1_2\bin\Debug\Example_3_1_2.exe 7 BaseSize: 0x10 8 ComponentSize: 0x0 9 Slots in VTable: 9 10 Number of IFaces in IFaceMap: 0
1 0:000> !clrstack -l 2 OS Thread Id: 0x2600 (0) 3 Child SP IP Call Site 4 00dcef18 7696f262 [HelperMethodFrame: 00dcef18] System.Diagnostics.Debugger.BreakInternal() 5 00dcef94 705bf195 System.Diagnostics.Debugger.Break() [f:\dd\ndp\clr\src\BCL\system\diagnostics\debugger.cs @ 91] 6 7 00dcefbc 02f40905 Example_3_1_3.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\......\Example_3_1_3\Program.cs @ 13] 8 LOCALS: 9 0x00dcefd0 = 0x030b2510 10 0x00dcefcc = 0x030b39ac 11 0x00dcefd8 = 0x02bf8098 12 13 00dcf154 70f1f036 [GCFrame: 00dcf154]
0x00dcefd0 = 0x030b2510,這個地址就是我們宣告的 person 變數。既然由了物件的地址,只要用物件的地址,減去 0x4,就是同步塊的地址,然後使用【dp】命令就可以檢視了。
1 0:000> dp 0x030b2510-0x4 l4 2 030b250c 0ebf8098 01414e1c 030b24c8 00000014
第二行的第二列以前是0,表示沒有任何資料,現在有值了。現在我們用這個值,減去我們得到的雜湊碼,看看是什麼。
1 0:000> ? 0ebf8098-2bf8098 2 Evaluate expression: 201326592 = 0c000000
0c000000它就是一個掩碼,告訴CLR 這個欄位中包含的是雜湊碼的值,起到標識的作用,因為還可以存放其他東西。
1 0:001> !dumpheap -type Person 2 Address MT Size 3 033824c8 014d4e60 16 4 5 Statistics: 6 MT Count TotalSize Class Name 7 014d4e60 1 16 Example_3_1_4.Person 8 Total 1 objects
紅色標記的就是Person 物件的地址,然後我們使用這個地址減去 0x4,就可以獲取同步塊索引了。
1 0:001> dp 033824c8-0x4 l4 2 033824c4 08000007 014d4e60 00000000 00000000
08000007 就是同步塊索引的值,08是一個掩碼,表示是同步塊索引,07就是執行緒 Id。我們可以使用【!syncblk】命令來驗證。
1 0:001> !syncblk 2 Index SyncBlock MonitorHeld Recursion Owning Thread Info SyncBlock Owner 3 6 015670f0 3 1 01512ba8 3d4c 0 03388210 System.IO.TextReader+SyncTextReader 4 7 01567124 3 1 0157c340 f8 9 033824c8 Example_3_1_4.Person(被鎖的物件是 person)
3:(一個執行緒持有鎖,一個等待鎖)
5 ----------------------------- 6 Total 7 7 CCW 1 8 RCW 2 9 ComClassFactory 0 10 Free 0
這裡是9,為什麼我們的程式輸出是3,3是託管執行緒的編號。9是windbg 標識的號碼。
1 0:001> !t 2 ThreadCount: 4 3 UnstartedThread: 0 4 BackgroundThread: 3 5 PendingThread: 0 6 DeadThread: 0 7 Hosted Runtime: no 8 (託管執行緒ID) Lock 9 ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception 10 0 1 3d4c 01512ba8 2a020 Preemptive 03388254:00000000 0150ca30 1 MTA 11 5 2 324c 0154f738 2b220 Preemptive 00000000:00000000 0150ca30 0 MTA (Finalizer) 12 9 3 f8 0157c340 3029220 Preemptive 03387214:00000000 0150ca30 1 MTA (Threadpool Worker) 13 11 4 264 0157cd28 3029220 Preemptive 0338A21C:00000000 0150ca30 0 MTA (Threadpool Worker)
我們可以切換到9好執行緒,看看他的執行緒棧。
1 0:001> ~~[f8]s 2 eax=00000000 ebx=00000001 ecx=00000000 edx=00000000 esi=00000001 edi=00000001 3 eip=778e166c esp=05e2f0e8 ebp=05e2f278 iopl=0 nv up ei pl nz na pe nc 4 cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 5 ntdll!NtWaitForMultipleObjects+0xc: 6 778e166c c21400 ret 14h 7 8 9 0:009> !clrstack 10 OS Thread Id: 0xf8 (9) 11 Child SP IP Call Site 12 05e2f444 778e166c [GCFrame: 05e2f444] 13 05e2f524 778e166c [HelperMethodFrame_1OBJ: 05e2f524] System.Threading.Monitor.Enter(System.Object) 14 05e2f59c 7076377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 15 05e2f5ac 705c1845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 16 05e2f5b4 016f0ae8 Example_3_1_4.Program+c.b__1_0() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_4\Program.cs @ 17] 17 05e2f600 6fe8d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884] 18 05e2f60c 6fe8b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498] 19 05e2f630 6fe8b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861] 20 05e2f634 6fe28604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980] 21 05e2f6a0 6fe28537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928] 22 05e2f6b4 6fe8b4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827] 23 05e2f718 6fe8b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767] 24 05e2f728 6fe8b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704] 25 05e2f72c 6fdfeb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820] 26 05e2f77c 6fdfe9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161] 27 05e2f99c 70f1f036 [DebuggerU2MCatchHandlerFrame: 05e2f99c]
1 0:000> !dumpheap -type Person 2 Address MT Size 3 02d72508 01004e1c 16 4 5 Statistics: 6 MT Count TotalSize Class Name 7 01004e1c 1 16 Example_3_1_5.Person 8 Total 1 objects
我們由了 Person 物件的指標地址,就可以通過這個地址檢視它的方法表的資訊了。
1 0:000> !DumpObj /d 02d72508 2 Name: Example_3_1_5.Person 3 MethodTable: 01004e1c 4 EEClass: 01001318 5 Size: 16(0x10) bytes 6 File: E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_5\bin\Debug\Example_3_1_5.exe 7 Fields: 8 MT Field Offset Type VT Attr Value Name 9 6fa424e4 4000001 4 System.String 0 instance 02d724c8 <Name>k__BackingField 10 6fa442a8 4000002 8 System.Int32 1 instance 20 <Age>k__BackingField
當然,我們通過【dp】命令也能證明型別控制程式碼的資訊。標紅的 01004e1c 就是方法表的地址。
1 0:000> dp 02d72508 l4 2 02d72508 01004e1c 02d724c8 00000014 00000000
我們可以【!dumpmt -md】列出所有的方法描述資訊。
1 0:000> !dumpmt -md 01004e1c 2 EEClass: 01001318 3 Module: 01004044 4 Name: Example_3_1_5.Person 5 mdToken: 02000003 6 File: E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_5\bin\Debug\Example_3_1_5.exe 7 BaseSize: 0x10 8 ComponentSize: 0x0 9 Slots in VTable: 9 10 Number of IFaces in IFaceMap: 0 11 -------------------------------------- 12 MethodDesc Table 13 Entry MethodDe JIT Name 14 6fe397b8 6fa3c838 PreJIT System.Object.ToString() 15 6fe396a0 6fb78978 PreJIT System.Object.Equals(System.Object) 16 6fe421f0 6fb78998 PreJIT System.Object.GetHashCode() 17 6fdf4f2c 6fb789a0 PreJIT System.Object.Finalize() 18 02c008d8 01004e08 JIT Example_3_1_5.Person..ctor() 19 02c0044d 01004dd8 NONE Example_3_1_5.Person.get_Name() 20 02c00910 01004de4 JIT Example_3_1_5.Person.set_Name(System.String) 21 02c00455 01004df0 NONE Example_3_1_5.Person.get_Age() 22 02c00950 01004dfc JIT Example_3_1_5.Person.set_Age(Int32)
1 0:006> !dumpheap -type Person 2 Address MT Size 3 026828409f60 7ffb8a239c50 32 4 5 Statistics: 6 MT Count TotalSize Class Name 7 7ffb8a239c50 1 32 Example_3_1_5_1.Person 8 Total 1 objects, 32 bytes
我們知道了物件的地址,可以執行【!do】命令,檢視 Person 物件的詳情。紅色標註的就是方法表,我們可以使用【dt】命令檢視結構。
1 0:006> !do 026828409f60 2 Name: Example_3_1_5_1.Person 3 MethodTable: 00007ffb8a239c50 4 EEClass: 00007ffb8a222578 5 Tracked Type: false 6 Size: 32(0x20) bytes 7 File: E:\Visual Studio 2022\Source\Projects\.....\Example_3_1_5_1\bin\Debug\net7.0\Example_3_1_5_1.dll 8 Fields: 9 MT Field Offset Type VT Attr Value Name 10 00007ffb8a12fd10 4000004 8 System.String 0 instance 0000026828409f10 <Name>k__BackingField 11 00007ffb8a0ae8d0 4000005 10 System.Int32 1 instance 20 <Age>k__BackingField
執行命令 【dt coreclr!MethodTable 00007ffb8a239c50】,00007ffb8a239c50就是方法表的地址。
1 0:006> dt coreclr!MethodTable 00007ffb8a239c50 2 =00007ffb`e9f688a8 s_pMethodDataCache : 0x00000268`2424c440 MethodDataCache 3 =00007ffb`e9f688b0 s_fUseParentMethodData : 0n1 4 =00007ffb`e9f688a0 s_fUseMethodDataCache : 0n1 5 +0x000 m_dwFlags : 0x1000200 6 +0x004 m_BaseSize : 0x20 7 +0x008 m_wFlags2 : 0x4088 8 +0x00a m_wToken : 7 9 +0x00c m_wNumVirtuals : 4 10 +0x00e m_wNumInterfaces : 0 11 +0x010 m_pParentMethodTable : 0x00007ffb`89f893b8 MethodTable 12 +0x018 m_pLoaderModule : 0x00007ffb`8a20cf48 Module 13 +0x020 m_pWriteableData : 0x00007ffb`8a239cb8 MethodTableWriteableData 14 +0x028 m_pEEClass : 0x00007ffb`8a222578 EEClass 15 +0x028 m_pCanonMT : 0x00007ffb`8a222578 16 +0x030 m_pPerInstInfo : 0x00007ffb`8a24a2d0 -> 0x8b4c0000`0ffa25ff Dictionary 17 +0x030 m_ElementTypeHnd : 0x00007ffb`8a24a2d0 18 +0x030 m_pMultipurposeSlot1 : 0x00007ffb`8a24a2d0 19 +0x038 m_pInterfaceMap : (null) 20 +0x038 m_pMultipurposeSlot2 : 0 21 =00007ffb`e9ea9fb8 c_DispatchMapSlotOffsets : [0] "080@" 22 =00007ffb`e9ea9fb0 c_NonVirtualSlotsOffsets : [0] "080@8@@H080@" 23 =00007ffb`e9ea9fa0 c_ModuleOverrideOffsets : [0] "080@8@@H8@@H@HHP080@8@@H080@" 24 =00007ffb`e9ebb648 c_OptionalMembersStartOffsets : [0] "@@@@@@@H@@@H@HHP@@@H@HHP@HHPHPPX"
以上就是 MethodTable 在 CLR 級別的結構。
2.7、檢視方法描述符 MethodDesc。1 0:006> !dumpheap -type Person 2 Address MT Size 3 026828409f60 7ffb8a239c50 32 4 5 Statistics: 6 MT Count TotalSize Class Name 7 7ffb8a239c50 1 32 Example_3_1_5_1.Person 8 Total 1 objects, 32 bytes
我們得到了紅色標記的 Person 物件的地址,然後執行【!do】命令檢視 Person 物件的詳情。
1 0:006> !do 026828409f60 2 Name: Example_3_1_5_1.Person 3 MethodTable: 00007ffb8a239c50 4 EEClass: 00007ffb8a222578 5 Tracked Type: false 6 Size: 32(0x20) bytes 7 File: E:\Visual Studio 2022\Source\Projects\......\Example_3_1_5_1\bin\Debug\net7.0\Example_3_1_5_1.dll 8 Fields: 9 MT Field Offset Type VT Attr Value Name 10 00007ffb8a12fd10 4000004 8 System.String 0 instance 0000026828409f10 <Name>k__BackingField 11 00007ffb8a0ae8d0 4000005 10 System.Int32 1 instance 20 <Age>k__BackingField
執行以上命令,我們得到了 Person 物件的方法表,然後我們使用【!dumpmt】檢視方法表詳情。
1 0:006> !dumpmt -md 00007ffb8a239c50 2 EEClass: 00007ffb8a222578 3 Module: 00007ffb8a20cf48 4 Name: Example_3_1_5_1.Person 5 mdToken: 0000000002000007 6 File: E:\Visual Studio 2022\Source\Projects\.....\Example_3_1_5_1\bin\Debug\net7.0\Example_3_1_5_1.dll 7 AssemblyLoadContext: Default ALC - The managed instance of this context doesn't exist yet. 8 BaseSize: 0x20 9 ComponentSize: 0x0 10 DynamicStatics: false 11 ContainsPointers: true 12 Slots in VTable: 9 13 Number of IFaces in IFaceMap: 0 14 -------------------------------------- 15 MethodDesc Table 16 Entry MethodDesc JIT Name 17 00007FFB8A0B0048 00007ffb89f89348 NONE System.Object.Finalize() 18 00007FFB8A0B0060 00007ffb89f89358 NONE System.Object.ToString() 19 00007FFB8A0B0078 00007ffb89f89368 NONE System.Object.Equals(System.Object) 20 00007FFB8A0B00C0 00007ffb89f893a8 NONE System.Object.GetHashCode() 21 00007FFB8A24A2D0 00007ffb8a239c28 JIT Example_3_1_5_1.Person..ctor() 22 00007FFB8A24A270 00007ffb8a239bc8 NONE Example_3_1_5_1.Person.get_Name() 23 00007FFB8A24A288 00007ffb8a239be0 JIT Example_3_1_5_1.Person.set_Name(System.String) 24 00007FFB8A24A2A0 00007ffb8a239bf8 NONE Example_3_1_5_1.Person.get_Age() 25 00007FFB8A24A2B8 00007ffb8a239c10 JIT Example_3_1_5_1.Person.set_Age(Int32)
執行命令後,紅色標記的就是方法描述符,我們可以點選去檢視 MethodDesc 詳情。我們執行【!dumpmd】命令,檢視 MethodDesc。
1 0:006> !DumpMD /d 00007ffb8a239be0 2 Method Name: Example_3_1_5_1.Person.set_Name(System.String) 3 Class: 00007ffb8a222578 4 MethodTable: 00007ffb8a239c50 5 mdToken: 0000000006000009 6 Module: 00007ffb8a20cf48 7 IsJitted: yes 8 Current CodeAddr: 00007ffb8a1407c0 9 Version History: 10 ILCodeVersion: 0000000000000000 11 ReJIT ID: 0 12 IL Addr: 00000268240a20ef 13 CodeAddr: 00007ffb8a1407c0 (MinOptJitted) 14 NativeCodeVersion: 0000000000000000
由於程式碼已經編譯了,所以是有地址的,我們可以執行【!u】命令檢視set_Name()方法的組合程式碼。
1 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_5_1\Program.cs @ 18: 2 >>> 00007ffb`8a1407c0 55 push rbp 3 00007ffb`8a1407c1 57 push rdi 4 00007ffb`8a1407c2 4883ec28 sub rsp,28h 5 00007ffb`8a1407c6 488d6c2430 lea rbp,[rsp+30h] 6 00007ffb`8a1407cb 48894d10 mov qword ptr [rbp+10h],rcx 7 00007ffb`8a1407cf 48895518 mov qword ptr [rbp+18h],rdx 8 00007ffb`8a1407d3 833d16ca0c0000 cmp dword ptr [00007ffb`8a20d1f0],0 9 00007ffb`8a1407da 7405 je 00007ffb`8a1407e1 10 00007ffb`8a1407dc e8ef6bc15f call coreclr!JIT_DbgIsJustMyCode (00007ffb`e9d573d0) 11 00007ffb`8a1407e1 488b5510 mov rdx,qword ptr [rbp+10h] 12 00007ffb`8a1407e5 488d4a08 lea rcx,[rdx+8] 13 00007ffb`8a1407e9 488b5518 mov rdx,qword ptr [rbp+18h] 14 00007ffb`8a1407ed e81ef8e2ff call 00007ffb`89f70010 (JitHelp: CORINFO_HELP_ASSIGN_REF) 15 00007ffb`8a1407f2 90 nop 16 00007ffb`8a1407f3 4883c428 add rsp,28h 17 00007ffb`8a1407f7 5f pop rdi 18 00007ffb`8a1407f8 5d pop rbp 19 00007ffb`8a1407f9 c3 ret
1 0:006> !token2ee Example_3_1_5 06000001 2 Module: 00e64044 3 Assembly: Example_3_1_5.exe 4 Token: 06000001 5 MethodDesc: 00e64d58 6 Name: Example_3_1_5.Program.Main(System.String[]) 7 JITTED Code Address: 02990848
1 0:006> !dumpheap -type Person 2 Address MT Size 3 029d2508 00e64e1c 16 4 5 Statistics: 6 MT Count TotalSize Class Name 7 00e64e1c 1 16 Example_3_1_5.Person 8 Total 1 objects 9 10 11 0:006> !do 029d2508 12 Name: Example_3_1_5.Person 13 MethodTable: 00e64e1c 14 EEClass: 00e61318 15 Size: 16(0x10) bytes 16 File: E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_5\bin\Debug\Example_3_1_5.exe 17 Fields: 18 MT Field Offset Type VT Attr Value Name 19 6fa424e4 4000001 4 System.String 0 instance 029d24c8 <Name>k__BackingField 20 6fa442a8 4000002 8 System.Int32 1 instance 20 <Age>k__BackingField 21 22 23 0:006> !DumpClass /d 00e61318 24 Class Name: Example_3_1_5.Person 25 mdToken: 02000003 26 File: E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_3_1_5\bin\Debug\Example_3_1_5.exe 27 Parent Class: 6fa315c8 28 Module: 00e64044 29 Method Table: 00e64e1c 30 Vtable Slots: 4 31 Total Method Slots: 5 32 Class Attributes: 100001 33 Transparency: Critical 34 NumInstanceFields: 2 35 NumStaticFields: 0 36 MT Field Offset Type VT Attr Value Name 37 6fa424e4 4000001 4 System.String 0 instance <Name>k__BackingField 38 6fa442a8 4000002 8 System.Int32 1 instance <Age>k__BackingField