Net 高級調試之八:代碼審查及雜項命令

来源:https://www.cnblogs.com/PatrickLiu/archive/2023/11/14/17828613.html
-Advertisement-
Play Games

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+0x1b
View 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]

             兩個命令的效果,如圖:
             

              如果我們想把一個函數的所有的彙編代碼全部顯示出來,我們可以使用【uf】命令,我們看看 clr!_CorExeMain 函數的彙編代碼吧。
 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              ret
View 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 
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 0 前言 潛心打造國內一流,國際領先的技術乾貨。 文章收錄在我的 GitHub 倉庫,歡迎Star/fork: JavaEdge-Interview 受網路和運行環境影響,應用程式可能遇到暫時性故障,如瞬時網路抖動、服務暫時不可用、服務繁忙導致超時等。 自動重試機制可大幅避免此類故障,保障操作成功執 ...
  • 來源:blog.csdn.net/weixin_42653522/article/details/117151913 1、前言 ApplicationContext 中的事件處理是通過 ApplicationEvent 類和 ApplicationListener 介面提供的。如果將實現了 Appl ...
  • 學習視頻:【孫哥說Spring5:從設計模式到基本應用到應用級底層分析,一次深入淺出的Spring全探索。學不會Spring?只因你未遇見孫哥】 第二章、第一個Spring程式 1.軟體版本 1.JDK1.8+ 2.Maven3.5+ 3.IDEA2018+ 4.SpringFramework 5. ...
  • 目錄1.修飾類時2.修飾方法時3.修飾屬性和局部變數時3.1修飾局部變數時3.2修飾成員變數時3.3修飾類變數時4.final與普通變數的區別5.final用於引用 1.修飾類時 1.只能是公共的(public)就算不寫也是public 2.被final修飾的類不可以被繼承 //前面預設有個publ ...
  • SciPy庫本身是針對科學計算而不是圖像處理的,只是圖像處理也包含了很多數學計算,所以Scipy也提供了一個專門的模塊ndimage用於圖像處理。 ndimage模塊提供的功能包括輸入/輸出圖像、顯示圖像、基本操作(如裁剪、翻轉、旋轉等)、圖像過濾(如去噪、銳化等)、圖像分割、分類、特征提取以及註冊 ...
  • 目錄 Welcome to YARP - 1.認識YARP並搭建反向代理服務 Welcome to YARP - 2.配置功能 2.1 - 配置文件(Configuration Files) 2.2 - 配置提供者(Configuration Providers) 2.3 - 配置過濾器(Confi ...
  • 一:背景 1. 講故事 前幾個月有位朋友找到我,說他們的的web程式沒有響應了,而且監控發現線程數特別高,記憶體也特別大,讓我幫忙看一下怎麼回事,現在回過頭來幾經波折,回味價值太濃了。 二:程式到底經歷了什麼 1. 線上程上找原因 這個程式記憶體高,線程高,無響應,尼瑪是一個複合態問題,那怎麼入手呢?按 ...
  • 前言: 之前對於項目上播放大解析度視頻(特別是大於4k解析度的)常常會感覺相當的頭疼,最開始使用的是Unity自帶的VideoPlayer,發現效果並不理想,更換為AVPro後發現播放是流暢了 但不能操作視頻快進,只要一快進就會出現卡頓,最後偶然間發現了一款用於播放Hap格式視頻的插件才最終解決了這 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...