1.HighLightingSystem 用於3D物體高亮顯示 在項目中的使用:導入插件後在需要高亮顯示的3d物體上附加Highlighter組件,在需要顯示高亮效果的攝像機上附加Highlighting Renderer組件。在代碼中調整Highlighter屬性即可控制物體高亮效果的開關、閃爍。 ...
一、簡介
今天是《Net 高級調試》的第八篇文章。這篇文章設計的內容挺多的,比如:如何查看方法的彙編代碼,如何獲取方法的描述符,對象同步塊的轉儲,對象方法表的轉儲,托管堆和垃圾回收器信息的轉儲,CLR 的版本,GC 模式,等等,內容挺多的。內容雖然挺多,但是這些都是高級調試的基礎。雖然這些都是基礎,如果這些掌握不好,以後的高級調試的道路,也不好走。當然了,第一次看視頻或者看書,是很迷糊的,不知道如何操作,還是那句老話,一遍不行,那就再來一遍,還不行,那就再來一遍,俗話說的好,書讀千遍,其意自現。
如果在沒有說明的情況下,所有代碼的測試環境都是 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、簡介
代碼審查就是觀察代碼,代碼由三種心態:機器代碼、IL代碼、C#代碼。高級調試屬於逆向分析,更多的是以 彙編代碼 為主,如果對彙編無感,想學好 Net 高級調試,也是比較困難的。
1.2、觀察彙編代碼
1)u命令
這個命令用來將非托管函數的機器代碼轉成彙編代碼,當然,我們想要查看彙編代碼,不一定非要使用 Windbg,我們也可以使用 Visual Studio IDE 的反彙編視窗。我們可以通過點擊菜單【調試】--》【視窗】----》【反彙編】,打開反彙編視窗。
2)!u命令
這個命令是由 SOS 提供的,專門用於觀察 托管函數 的彙編表示,接下來,我們查看一下 Main 方法的彙編代碼。
1.3、觀察 IL 代碼
SOS 提供了一個叫 !dumpil 的命令用來將托管函數的彙編指令轉成可讀的 IL 代碼。
1.4、觀察 C# 代碼
要觀察 C# 代碼,需要將記憶體中的 module 給剝離出來,然後使用 ILSpy 或者 DnSpy 等反編譯工具反轉即可。這就需要使用 Windbg 的【!savemodule】命令。大家也要防止 Dump 泄露,這個是嚴重的,別人就可以看到你的完整代碼。
2、雜項命令
2.1、獲取 CLR 版本、GC模式
如果想獲取 CLR 的版本,可以使用【!eeversion】命令,當然,我們也可以通過查看堆的數量,來瞭解 GC 模式,使用【!eeheap -gc】命令。
2.2、查看線程棧對象
如果我們想查看線程棧上的對象,一般都會使用【!clrstack -a】命令,但是這個命令只是看錶面,不能映射到對象,那麼我們可以使用【!dso】命令,這個命令可以把線程棧中的所有對象全部顯示出來。
2.3、觀察對象引用根
我們知道瞭如何查看對象引用根,我們就知道了為什麼沒有被 GC 回收,很輕鬆找到問題的所在,這個命令就是【!gcroot】。
三、調試過程
廢話不多說,這一節是具體的調試操作的過程,又可以說是眼見為實的過程,在開始之前,我還是要啰嗦兩句,這一節分為兩個部分,第一部分是測試的源碼部分,沒有代碼,當然就談不上測試了,調試必須有載體。第二部分就是根據具體的代碼來證實我們學到的知識,是具體的眼見為實。
1、測試源碼
1.1、Example_8_1_1
1 namespace Example_8_1_1 2 { 3 internal class Program 4 { 5 static void Main(string[] args) 6 { 7 var sum = Sum(10, 11); 8 Console.WriteLine($"sum={sum}"); 9 Console.ReadLine(); 10 } 11 12 private static int Sum(int a, int b) 13 { 14 int i = a; 15 int j = b; 16 var sum = i + j; 17 return sum; 18 } 19 } 20 }View Code
1.2、Example_8_1_2
1 namespace Example_8_1_2 2 { 3 internal class Program 4 { 5 private static List<byte[]> list = new List<byte[]>(); 6 7 static void Main(string[] args) 8 { 9 for (int i = 0; i < 100; i++) 10 { 11 list.Add(new byte[100000]); 12 } 13 Console.WriteLine("數據添加完畢!"); 14 Console.ReadLine(); 15 } 16 } 17 }View Code
2、眼見為實
項目的所有操作都是一樣的,所以就在這裡說明一下,但是每個測試例子,都需要重新啟動,並載入相應的應用程式,載入方法都是一樣的。流程如下:我們編譯項目,打開 Windbg,點擊【文件】----》【launch executable】附加程式,打開調試器的界面,程式已經處於中斷狀態。我們需要使用【g】命令,繼續運行程式,然後到達指定地點停止後,我們可以點擊【break】按鈕,就可以調試程式了。有時候可能需要切換到主線程,可以使用【~0s】命令。
2.1、查看 clr!CallDescrWorkerInternal+0x34 處的彙編代碼。
測試源碼:Example_8_1_1
說明一下,在這裡用其他的程式都是可以的,只是查看彙編代碼,可以查看非托管函數的、也可以查看托管函數的彙編代碼。
接下來,我們先找一個非托管函數的,看看它們的彙編代碼,到底是哪個函數,是隨機的。
我們使用【k】命令,查看一下非托管的調用棧,然後從裡面隨便找一個函數,看看它的彙編代碼。
1 0:000> k 2 # ChildEBP RetAddr 3 00 00efeff4 7533f25c ntdll!NtReadFile+0xc 4 01 00efeff4 705f9b71 KERNELBASE!ReadFile+0xec 5 02 00eff064 70d2b275 mscorlib_ni+0x4b9b71 6 03 00eff090 70d2b17b mscorlib_ni!System.IO.__ConsoleStream.ReadFileNative+0x89 [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205] 7 04 00eff0bc 705de6a3 mscorlib_ni!System.IO.__ConsoleStream.Read+0x9f [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134] 8 05 00eff0d4 705deb5b mscorlib_ni!System.IO.StreamReader.ReadBuffer+0x33 [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595] 9 06 00eff0f0 70e73786 mscorlib_ni!System.IO.StreamReader.ReadLine+0xe3 [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748] 10 07 00eff100 70cd1845 mscorlib_ni!System.IO.TextReader.SyncTextReader.ReadLine+0x1a [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 11 08 00eff108 011808d1 mscorlib_ni!System.Console.ReadLine+0x15 [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 12 WARNING: Frame IP not in any known module. Following frames may be wrong. 13 09 00eff138 7162f036 0x11808d1 14 0a 00eff144 716322da clr!CallDescrWorkerInternal+0x34 15 0b 00eff198 7163859b clr!CallDescrWorkerWithHandler+0x6b 16 0c 00eff204 717db11b clr!MethodDescCallSite::CallTargetWorker+0x16a 17 0d 00eff328 717db7fa clr!RunMain+0x1b3 18 0e 00eff594 717db727 clr!Assembly::ExecuteMainMethod+0xf7 19 0f 00effa78 717db8a8 clr!SystemDomain::ExecuteMainMethod+0x5ef 20 10 00effad0 717db9ce clr!ExecuteEXE+0x4c 21 11 00effb10 717d7305 clr!_CorExeMainInternal+0xdc 22 12 00effb4c 71ddfa84 clr!_CorExeMain+0x4d 23 13 00effb84 71ede81e mscoreei!_CorExeMain+0xd6 24 14 00effb94 71ee4338 MSCOREE!ShellShim__CorExeMain+0x9e 25 15 00effbac 7515f989 MSCOREE!_CorExeMain_Exported+0x8 26 16 00effbac 772a7084 KERNEL32!BaseThreadInitThunk+0x19 27 17 00effc08 772a7054 ntdll!__RtlUserThreadStart+0x2f 28 18 00effc18 00000000 ntdll!_RtlUserThreadStart+0x1bView Code 調用棧還是很多的,列表裡有:00eff144 716322da clr!CallDescrWorkerInternal+0x34,這樣一行代碼,我們使用【u】命令查看一下。
1 0:000> u clr!CallDescrWorkerInternal+0x34 2 clr!CallDescrWorkerInternal+0x34: 3 7162f036 8b4b0c mov ecx,dword ptr [ebx+0Ch] 4 7162f039 83f900 cmp ecx,0 5 7162f03c 740c je clr!CallDescrWorkerInternal+0x48 (7162f04a) 6 7162f03e 83f904 cmp ecx,4 7 7162f041 7412 je clr!CallDescrWorkerInternal+0x53 (7162f055) 8 7162f043 83f908 cmp ecx,8 9 7162f046 7412 je clr!CallDescrWorkerInternal+0x58 (7162f05a) 10 7162f048 eb06 jmp clr!CallDescrWorkerInternal+0x4e (7162f050)
代碼很清楚,可以自行查看。當然我們也可以在Windbg的【Disassembly】視窗查看彙編代碼,效果如圖:
【u】命令是從上向下看彙編代碼,我們也可以使用【ub】命令,從下向上查看彙編代碼。
1 0:000> ub clr!CallDescrWorkerInternal+0x34 2 clr!CallDescrWorkerInternal+0x21: 3 7162f023 83e804 sub eax,4 4 7162f026 ff30 push dword ptr [eax] 5 7162f028 49 dec ecx 6 7162f029 75f8 jne clr!CallDescrWorkerInternal+0x21 (7162f023) 7 7162f02b 8b4308 mov eax,dword ptr [ebx+8] 8 7162f02e 8b10 mov edx,dword ptr [eax] 9 7162f030 8b4804 mov ecx,dword ptr [eax+4] 10 7162f033 ff5310 call dword ptr [ebx+10h]
兩個命令的效果,如圖:
1 0:000> uf clr!_CorExeMain 2 clr!_CorExeMain: 3 717d72e0 6a14 push 14h 4 717d72e2 6818737d71 push offset clr!`dynamic atexit destructor for 'AppDataPathHolder''+0x27e0 (717d7318) 5 717d72e7 e8349de4ff call clr!_SEH_prolog4 (71621020) 6 717d72ec 33c0 xor eax,eax 7 717d72ee 8985e0ffffff mov dword ptr [ebp-20h],eax 8 717d72f4 8985e4ffffff mov dword ptr [ebp-1Ch],eax 9 717d72fa 8985fcffffff mov dword ptr [ebp-4],eax 10 717d7300 e81b460000 call clr!_CorExeMainInternal (717db920) 11 717d7305 c785fcfffffffeffffff mov dword ptr [ebp-4],0FFFFFFFEh 12 717d730f 33c0 xor eax,eax 13 717d7311 e8509de4ff call clr!_SEH_epilog4 (71621066) 14 717d7316 c3 ret
2.2、我們查看 Program 類型的 Main 方法的彙編代碼。
測試源碼:Example_8_1_1
1 0:000> !clrstack 2 OS Thread Id: 0x4164 (0) 3 Child SP IP Call Site 4 006fee34 772b10fc [InlinedCallFrame: 006fee34] 5 006fee30 705f9b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr) 6 006fee34 70d2b275 [InlinedCallFrame: 006fee34] Microsoft.Win32.Win32Native.ReadFile(.....) 7 006fee98 70d2b275 System.IO.__ConsoleStream.ReadFileNative(oolean, Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205] 8 006feecc 70d2b17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134] 9 006feeec 705de6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595] 10 006feefc 705deb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748] 11 006fef18 70e73786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 12 006fef28 70cd1845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 13 006fef30 025808d1 Example_8_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\..\Example_8_1_1\Program.cs @ 11] 14 006ff0d0 7162f036 [GCFrame: 006ff0d0]
025808d1 Main 方法的地址,我們可以使用【!u】查看一下。
1 0:000> !u 025808d1 2 Normal JIT generated code 3 Example_8_1_1.Program.Main(System.String[]) 4 Begin 02580848, size 95 5 6 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 8: 7 02580848 55 push ebp 8 02580849 8bec mov ebp,esp 9 0258084b 57 push edi 10 0258084c 56 push esi 11 0258084d 83ec20 sub esp,20h 12 02580850 8bf1 mov esi,ecx 13 02580852 8d7dd8 lea edi,[ebp-28h] 14 02580855 b906000000 mov ecx,6 15 0258085a 33c0 xor eax,eax 16 0258085c f3ab rep stos dword ptr es:[edi] 17 0258085e 8bce mov ecx,esi 18 02580860 894df4 mov dword ptr [ebp-0Ch],ecx 19 02580863 833df042c40000 cmp dword ptr ds:[0C442F0h],0 20 0258086a 7405 je 02580871 21 0258086c e80ff5446f call clr!JIT_DbgIsJustMyCode (719cfd80) 22 02580871 33d2 xor edx,edx 23 02580873 8955f0 mov dword ptr [ebp-10h],edx 24 02580876 90 nop 25 26 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 9: 27 02580877 b90a000000 mov ecx,0Ah 28 0258087c ba0b000000 mov edx,0Bh 29 02580881 ff156c4dc400 call dword ptr ds:[0C44D6Ch] (Example_8_1_1.Program.Sum(Int32, Int32), mdToken: 06000002) 30 02580887 8945ec mov dword ptr [ebp-14h],eax 31 0258088a 8b45ec mov eax,dword ptr [ebp-14h] 32 0258088d 8945f0 mov dword ptr [ebp-10h],eax 33 34 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 10: 35 02580890 b9a8421570 mov ecx,offset mscorlib_ni!GetObjectData+0x102 (701542a8) (MT: System.Int32) 36 02580895 e85a286bfe call 00c330f4 (JitHelp: CORINFO_HELP_NEWSFAST) 37 0258089a 8945e8 mov dword ptr [ebp-18h],eax 38 0258089d 8b0544237403 mov eax,dword ptr ds:[3742344h] ("sum={0}") 39 025808a3 8945dc mov dword ptr [ebp-24h],eax 40 025808a6 8b45e8 mov eax,dword ptr [ebp-18h] 41 025808a9 8b55f0 mov edx,dword ptr [ebp-10h] 42 025808ac 895004 mov dword ptr [eax+4],edx 43 025808af 8b45e8 mov eax,dword ptr [ebp-18h] 44 025808b2 8945d8 mov dword ptr [ebp-28h],eax 45 025808b5 8b4ddc mov ecx,dword ptr [ebp-24h] 46 025808b8 8b55d8 mov edx,dword ptr [ebp-28h] 47 025808bb e890d7f86d call mscorlib_ni!System.String.Format (7050e050) 48 025808c0 8945e4 mov dword ptr [ebp-1Ch],eax 49 025808c3 8b4de4 mov ecx,dword ptr [ebp-1Ch] 50 025808c6 e89946076e call mscorlib_ni!System.Console.WriteLine (705f4f64) 51 025808cb 90 nop 52 53 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 11: 54 025808cc e85f0f756e call mscorlib_ni!System.Console.ReadLine (70cd1830) 55 >>> 025808d1 8945e0 mov dword ptr [ebp-20h],eax 56 025808d4 90 nop 57 58 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 12: 59 025808d5 90 nop 60 025808d6 8d65f8 lea esp,[ebp-8] 61 025808d9 5e pop esi 62 025808da 5f pop edi 63 025808db 5d pop ebp 64 025808dc c3 retView Code
代碼太多,不變展示。>>> 025808d1 8945e0 mov dword ptr [ebp-20h],eax,三個小於號,表示當前執行到的位置。
2.3、使用【!dumpil】命令查看 IL 代碼。
測試源碼:Example_8_1_1
我們要想查看一個方法的 IL 代碼,必須先找到 這個方法的 MD,也就是方法描述符。
我們可以使用【!clrstack】命令找到 Main 方法的 IP,根據 IP 再找到 MD。
1 0:000> !clrstack 2 OS Thread Id: 0x4164 (0) 3 Child SP IP Call Site 4 006fee34 772b10fc [InlinedCallFrame: 006fee34] 5 006fee30 705f9b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr) 6 006fee34 70d2b275 [InlinedCallFrame: 006fee34] Microsoft.Win32.Win32Native.ReadFile(... Int32 ByRef, IntPtr) 7 006fee98 70d2b275 System.IO.__ConsoleStream.ReadFileNative(...) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205] 8 006feecc 70d2b17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134] 9 006feeec 705de6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595] 10 006feefc 705deb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748] 11 006fef18 70e73786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 12 006fef28 70cd1845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 13 006fef30 025808d1 Example_8_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_8_1_1\Program.cs @ 11] 14 006ff0d0 7162f036 [GCFrame: 006ff0d0]
025808d1 紅色標註的就是 Main 方法的IP,我們使用【!ip2md】命令,就可以找到方法描述符Md了。
1 0:000> !ip2md 025808d1 2 MethodDesc: 00c44d58 3 Method Name: Example_8_1_1.Program.Main(System.String[]) 4 Class: 00c41290 5 MethodTable: 00c44d78 6 mdToken: 06000001 7 Module: 00c44044 8 IsJitted: yes 9 CodeAddr: 02580848 10 Transparency: Critical 11 Source file: E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_8_1_1\Program.cs @ 11
MethodDesc: 00c44d58 紅色標註的就是方法描述符的而地址。有了方法描述(MD),我們就可以使用【!dumpil】命令查看 IL 代碼了。
1 0:000> !dumpil 00c44d58 2 ilAddr = 00362050 3 IL_0000: nop 4 IL_0001: ldc.i4.s 10 5 IL_0003: ldc.i4.s 11 6 IL_0005: call Example_8_1_1.Program::Sum 7 IL_000a: stloc.0 8 IL_000b: ldstr "sum={0}" 9 IL_0010: ldloc.0 10 IL_0011: box System.Int32 11 IL_0016: call System.String::Format 12 IL_001b: call System.Console::WriteLine 13 IL_0020: nop 14 IL_0021: call System.Console::ReadLine 15 IL_0026: pop 16 IL_0027: ret
除了以上方法,我們也可以使用【!name2ee】命令達到同樣的效果。那我麽查看一下 Sum 方法 IL 代碼。
1 0:000> !name2ee Example_8_1_1!Example_8_1_1.Program.Sum 2 Module: 00c44044 3 Assembly: Example_8_1_1.exe 4 Token: 06000002 5 MethodDesc: 00c44d64 6 Name: Example_8_1_1.Program.Sum(Int32, Int32) 7 JITTED Code Address: 025808f0
MethodDesc: 00c44d64 紅色標註的就是方法描述符的地址,有了這個地址,我們就可以使用【!dumpil】命令了。
1 0:000> !dumpil 00c44d64 2 ilAddr = 00362084 3 IL_0000: nop 4 IL_0001: ldarg.0 5 IL_0002: stloc.0 6 IL_0003: ldarg.1 7 IL_0004: stloc.1 8 IL_0005: ldloc.0 9 IL_0006: ldloc.1 10 IL_0007: add 11 IL_0008: stloc.2 12 IL_0009: ldloc.2 13 IL_000a: stloc.3 14 IL_000b: br.s IL_000d 15 IL_000d: ldloc.3 16 IL_000e: ret
2.4、通過 Dump 查看 C# 源碼。
測試源碼:Example_8_1_1
我們想要查看 Example_8_1_1項目的源碼,必須找到這個項目的【模塊】,也就是 module,我們切換到主線程,也就是 0 號線程,使用命令【~0s】,使用命令【!clrstack】找到調用棧。
1 0:000> !clrstack 2 OS Thread Id: 0x3438 (0) 3 Child SP IP Call Site 4 00cfef94 772910fc [InlinedCallFrame: 00cfef94] 5 00cfef90 6d869b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr) 6 00cfef94 6df9b275 [InlinedCallFrame: 00cfef94] Microsoft.Win32.Win32Native.ReadFile(... Int32 ByRef, IntPtr) 7 00cfeff8 6df9b275 System.IO.__ConsoleStream.ReadFileNative(.. Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205] 8 00cff02c 6df9b17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134] 9 00cff04c 6d84e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595] 10 00cff05c 6d84eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748] 11 00cff078 6e0e3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 12 00cff088 6df41845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 13 00cff090 013e08d1 Example_8_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_8_1_1\Program.cs @ 11] 14 00cff228 6fdbf036 [GCFrame: 00cff228]
013e08d1 紅色標註的地址就是 Main 方法的 IP,有了 IP,我們可以通過 IP 找到 MD(方法描述符),在方法描述符里就包含了module 信息。
1 0:000> !ip2md 013e08d1 2 MethodDesc: 00f14d58 3 Method Name: Example_8_1_1.Program.Main(System.String[]) 4 Class: 00f11290 5 MethodTable: 00f14d78 6 mdToken: 06000001 7 Module: 00f14044 8 IsJitted: yes 9 CodeAddr: 013e0848 10 Transparency: Critical 11 Source file: E:\Visual Studio 2022\...\Example_8_1_1\Program.cs
Module: 00f14044 這個信息就是模塊信息,我們就可以使用【!savemodule】命令,保存文件了。
1 0:000> !savemodule 00f14044 F:\Test\SaveDump\test.dll 2 3 sections in file 3 section 0 - VA=2000, VASize=818, FileAddr=200, FileSize=a00 4 section 1 - VA=4000, VASize=5f0, FileAddr=c00, FileSize=600 5 section 2 - VA=6000, VASize=c, FileAddr=1200, FileSize=200
文件就保存下來了,截圖效果:
有了這個文件,我們就可以使用 ILSpy 反編譯工具查看源碼了,很簡單,就不寫了。
2.5、如何查看 CLR 版本和 GC 模式。
測試源碼:Example_8_1_1
1 0:000> !eeversion 2 4.8.4300.0 retail 3 Workstation mode(工作站模式,一般指:Winform,WPF,Console等桌面應用) 4 SOS Version: 4.8.4300.0 retail build
還有一種方式查看 GC 模式,我們可以查看 托管堆的個數,一個堆的就是工作站模式,其他就是伺服器模式。
1 0:000> !eeheap -gc 2 Number of GC Heaps: 1(這裡就表示是工作站模式) 3 generation 0 starts at 0x02d91018 4 generation 1 starts at