Advanced .Net Debugging 5:基本除錯任務(執行緒的操作、程式碼審查、CLR內部的命令、診斷命令和崩潰轉儲檔案)

可均可可發表於2024-03-21
一、介紹
    
這是我的《Advanced .Net Debugging》這個系列的第五篇文章。今天這篇文章的標題雖然叫做“基本除錯任務”,但是這章的內容還是挺多的。上一篇我們瞭解了一些調.NET 框架中必要的概念,比如:記憶體轉儲、值型別轉儲、引用型別轉儲、陣列轉儲和異常轉儲等,我們既能做到知其然,又能做到眼見為實,知其所以然,對我們分析.NET 程式有很大的幫助。今天這篇文章主要涉及的內容是執行緒的操作、程式碼的審查和診斷命令等。SOSEX擴充套件的內容我就省略了,因為我這個系列的是基於 .NET 8 版本來寫的,SOSEX是基於 .NET Framework 版本的,如果大家想了解其內容,可以檢視我的【高階除錯】系列(我當前寫的是《Advanced .Net Debugging》系列,是不一樣的),當然,也可以看原書。【高階除錯】系列主要是集中在 .NET Framework 版本的。如果我們想成為一名合格程式設計師,這些除錯技巧都是必須要掌握的。
    如果在沒有說明的情況下,所有程式碼的測試環境都是 Net 8.0,如果有變動,我會在專案章節裡進行說明。好了,廢話不多說,開始我們今天的除錯工作。

     除錯環境我需要進行說明,以防大家不清楚,具體情況我已經羅列出來。
          作業系統:Windows Professional 10
          除錯工具:Windbg Preview(Debugger Client:1.2306.1401.0,Debugger engine:10.0.25877.1004)和 NTSD(10.0.22621.2428 AMD64)
          下載地址:可以去Microsoft Store 去下載
          開發工具:Microsoft Visual Studio Community 2022 (64 位) - Current版本 17.8.3

          Net 版本:.Net 8.0
          CoreCLR原始碼:原始碼下載
二、除錯原始碼
    廢話不多說,本節是除錯的原始碼部分,沒有程式碼,當然就談不上測試了,除錯必須有載體。

    2.1、ExampleCore_3_1_9
Advanced .Net Debugging 5:基本除錯任務(執行緒的操作、程式碼審查、CLR內部的命令、診斷命令和崩潰轉儲檔案)
 1 namespace ExampleCore_3_1_9
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             int a = 10;
 8             int b = 11;
 9             Console.WriteLine("X={0},Y={1}", a, b);
10             Test(12);
11             Console.ReadKey();
12         }
13 
14         private static void Test(int c)
15         {
16             Task.Run(Run1);
17             Task.Run(Run2);
18             Task.Run(Run3);
19         }
20 
21         private static void Run1()
22         {
23             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 正在執行");
24             Console.ReadLine();
25             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 結束執行");
26         }
27 
28         private static void Run2()
29         {
30             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 正在執行");
31             Console.ReadLine();
32             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 結束執行");
33         }
34 
35         private static void Run3()
36         {
37             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 正在執行");
38             Console.ReadLine();
39             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 結束執行");
40         }
41     }
42 }
View Code

    2.2、ExampleCore_3_1_10
Advanced .Net Debugging 5:基本除錯任務(執行緒的操作、程式碼審查、CLR內部的命令、診斷命令和崩潰轉儲檔案)
 1 namespace ExampleCore_3_1_10
 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

    2.3、ExampleCore_3_1_11
Advanced .Net Debugging 5:基本除錯任務(執行緒的操作、程式碼審查、CLR內部的命令、診斷命令和崩潰轉儲檔案)
 1 namespace ExampleCore_3_1_11
 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.4、ExampleCore_3_1_12
Advanced .Net Debugging 5:基本除錯任務(執行緒的操作、程式碼審查、CLR內部的命令、診斷命令和崩潰轉儲檔案)
 1 namespace ExampleCore_3_1_12
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Console.WriteLine("請輸入一個除數:");
 8             var num = Console.ReadLine();
 9             var result = 10 / Convert.ToInt32(num);
10 
11             Console.ReadLine();
12         }
13     }
14 }
View Code

三、基礎知識

    3.1、執行緒的操作

        在非託管程式碼除錯中,所有與執行緒相關的偵錯程式命令都是以非託管 Windows 執行緒為基礎的,換個說法就是,用於除錯非託管程式碼的偵錯程式命令使用的就是非託管 Windows 執行緒,偵錯程式命令知道如何轉儲我們要轉儲的物件。但是,託管程式碼就不一樣了,它的執行緒有自己的結構,偵錯程式本身是無法對呼叫棧進行遍歷的。
        我們知道,CLR 能對託管程式碼進行動態轉換,並且 JIT 編譯器可以將生成的機器程式碼放在它認為合適的地方。非託管偵錯程式是不知道 JIT 編譯器的任何知識,它也不知道生成的程式碼放在何處,因此就不能正確的顯示棧回溯。

        3.1.1、ClrStack
            A、基礎知識
                SOS 偵錯程式擴充套件提供了一個專門檢視託管函式呼叫棧的命令,畢竟只有 JIT 編譯器更熟悉託管函式,也知道編譯後的機器碼放在什麼位置。
                這個命令就是【!clrstack】。
                !clrstack -a(all):這個命令表示將執行緒棧中的所有區域性變數和引數全部輸出。
                !clrstack -p(parameter):這個命令表示將執行緒棧中的引數全部輸出。
                !clrstack -l(locals):這個命令表示將執行緒棧中的所有區域性變數全部輸出。

                我們還可以檢視所有託管執行緒棧,可以使用【~*e】命令。
                請注意:如果 ClrStack 命令在非託管執行緒的上下文中執行,將會顯示一個錯誤:
1 0:006> !clrstack
2 OS Thread Id: 0x335c (6)
3 Unable to walk the managed stack. The current thread is likely not a 
4 managed thread. You can run !clrthreads to get a list of managed threads in
5 the process
6 Failed to start stack walk: 80070057

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_9
                除錯任務:ClrStack 命令使用
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】。
                    

                    開啟【NTSD】偵錯程式視窗。
                    

                    使用【g】命令執行偵錯程式,知道偵錯程式有如圖輸出,偵錯程式會卡住暫停。
                    

                    按組合鍵【ctrl+c】進入中斷模式,在所有操作之前,我們先切換到託管執行緒,執行命令【~0s】。

1 0:003> ~0s
2 coreclr!CorSigUncompressElementType_EndPtr+0x18 [inlined in coreclr!MetaSig::CompareElementType+0x1d0]:
3 00007ffb`98b68e40 48ffc0          inc     rax

                    我們先使用【!clrstack】命令,後面不跟任何命令開關。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3de4 (0)
 3         Child SP               IP Call Site
 4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
 5 000000F08ABCE5D0 00007FFC5382F269 System.Text.DecoderDBCS.GetChars(Byte[], Int32, Int32, Char[], Int32, Boolean)
 6 000000F08ABCE660 00007FFB92A28A51 System.IO.StreamReader.ReadBuffer()
 7 000000F08ABCE6B0 00007FFB92A290A4 System.IO.StreamReader.ReadLine()
 8 000000F08ABCE760 00007FFC5383005D System.IO.SyncTextReader.ReadLine()
 9 000000F08ABCE7B0 00007FFC53829319 System.Console.ReadLine()
10 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])

                    它羅列出了呼叫棧。如果想檢視每個棧幀的引數,我們可以使用【!clrstack -p】命令,很簡單,就不多說了。

1 0:000> !clrstack -p
2 OS Thread Id: 0x3de4 (0)
3         Child SP               IP Call Site
4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
5 。。。。。。(省略了)
6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
7     PARAMETERS:(這裡就是引數所在地)
8         args (0x000000F08ABCE830) = 0x000002664e008ea0

                    如果想檢視每個棧幀的區域性變數,可以使用【!clrstack -l】命令。

1 0:000> !clrstack -l
2 OS Thread Id: 0x3de4 (0)
3         Child SP               IP Call Site
4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
5 。。。。。。(省略了)
6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
7     LOCALS:(以下就是區域性變數)
8         0x000000F08ABCE81C = 0x000000000000000a
9         0x000000F08ABCE818 = 0x000000000000000b

                    如果想檢視每一棧幀的區域性變數和引數,可以使用【!clrstack -a】命令。

 1 0:000> !clrstack -a
 2 OS Thread Id: 0x3de4 (0)
 3         Child SP               IP Call Site
 4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
 5 。。。。。。(省略了)
 6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
 7     PARAMETERS:(這裡是引數區域)
 8         args (0x000000F08ABCE830) = 0x000002664e008ea0
 9     LOCALS:(這裡是區域性變數區域)
10         0x000000F08ABCE81C = 0x000000000000000a
11         0x000000F08ABCE818 = 0x000000000000000b

                    很簡單,就不多數了。
                    還有一個命令,我們要熟悉一下,那就是~*e 命令。
                    ~ 命令輸出所有執行緒列表。

 1 0:000> ~
 2 .  0  Id: 3f64.3de4 Suspend: 1 Teb: 000000f0`8acb8000 Unfrozen
 3    1  Id: 3f64.ab4 Suspend: 1 Teb: 000000f0`8acd6000 Unfrozen ".NET Tiered Compilation Worker"
 4    2  Id: 3f64.b08 Suspend: 1 Teb: 000000f0`8acd8000 Unfrozen
 5 #  3  Id: 3f64.6d0 Suspend: 1 Teb: 000000f0`8acda000 Unfrozen
 6    4  Id: 3f64.220c Suspend: 1 Teb: 000000f0`8acc0000 Unfrozen ".NET EventPipe"
 7    5  Id: 3f64.1830 Suspend: 1 Teb: 000000f0`8acc2000 Unfrozen ".NET Debugger"
 8    6  Id: 3f64.3c34 Suspend: 1 Teb: 000000f0`8acc4000 Unfrozen ".NET Finalizer"
 9    8  Id: 3f64.10d0 Suspend: 1 Teb: 000000f0`8acca000 Unfrozen ".NET TP Worker"
10    9  Id: 3f64.3e9c Suspend: 1 Teb: 000000f0`8accc000 Unfrozen ".NET TP Gate"
11   10  Id: 3f64.3d90 Suspend: 1 Teb: 000000f0`8acce000 Unfrozen ".NET TP Worker"
12   11  Id: 3f64.1e48 Suspend: 1 Teb: 000000f0`8acd0000 Unfrozen ".NET TP Worker"

                    ~* 命令,顯示所有執行緒列表和入口函式。

 1 0:000> ~*
 2 .  0  Id: 3f64.3de4 Suspend: 1 Teb: 000000f0`8acb8000 Unfrozen
 3       Start: apphost!wmainCRTStartup (00007ff7`8a2b1360)
 4       Priority: 0  Priority class: 32  Affinity: f
 5    1  Id: 3f64.ab4 Suspend: 1 Teb: 000000f0`8acd6000 Unfrozen ".NET Tiered Compilation Worker"
 6       Start: coreclr!TieredCompilationManager::BackgroundWorkerBootstrapper0 (00007ffb`98c833f0)
 7       Priority: 0  Priority class: 32  Affinity: f
 8    2  Id: 3f64.b08 Suspend: 1 Teb: 000000f0`8acd8000 Unfrozen
 9       Start: KERNELBASE!CtrlRoutine (00007ffc`651d9c80)
10       Priority: 2  Priority class: 32  Affinity: f
11 #  3  Id: 3f64.6d0 Suspend: 1 Teb: 000000f0`8acda000 Unfrozen
12       Start: ntdll!DbgUiRemoteBreakin (00007ffc`6791ba10)
13       Priority: 0  Priority class: 32  Affinity: f
14    4  Id: 3f64.220c Suspend: 1 Teb: 000000f0`8acc0000 Unfrozen ".NET EventPipe"
15       Start: coreclr!server_thread (00007ffb`98c6b530)
16       Priority: 0  Priority class: 32  Affinity: f
17    5  Id: 3f64.1830 Suspend: 1 Teb: 000000f0`8acc2000 Unfrozen ".NET Debugger"
18       Start: coreclr!DebuggerRCThread::ThreadProcStatic (00007ffb`98c667f0)
19       Priority: 0  Priority class: 32  Affinity: f
20    6  Id: 3f64.3c34 Suspend: 1 Teb: 000000f0`8acc4000 Unfrozen ".NET Finalizer"
21       Start: coreclr!FinalizerThread::FinalizerThreadStart (00007ffb`98c4e370)
22       Priority: 2  Priority class: 32  Affinity: f
23    8  Id: 3f64.10d0 Suspend: 1 Teb: 000000f0`8acca000 Unfrozen ".NET TP Worker"
24       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
25       Priority: 0  Priority class: 32  Affinity: f
26    9  Id: 3f64.3e9c Suspend: 1 Teb: 000000f0`8accc000 Unfrozen ".NET TP Gate"
27       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
28       Priority: 0  Priority class: 32  Affinity: f
29   10  Id: 3f64.3d90 Suspend: 1 Teb: 000000f0`8acce000 Unfrozen ".NET TP Worker"
30       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
31       Priority: 0  Priority class: 32  Affinity: f
32   11  Id: 3f64.1e48 Suspend: 1 Teb: 000000f0`8acd0000 Unfrozen ".NET TP Worker"
33       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
34       Priority: 0  Priority class: 32  Affinity: f

                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_9.exe,進入偵錯程式。繼續使用【g】命令,執行偵錯程式。我們的控制檯程式輸出如下內容,如圖:
                    

                    點選【break】按鈕,中斷偵錯程式的執行,由於,我們手動中斷程式執行,需要將執行緒切換到託管執行緒上,執行命令【~0s】。

1 0:001> ~0s
2 ntdll!NtReadFile+0x14:
3 00007ffc`678eae54 c3              ret

                    我們繼續使用【!clrstack】命令,輸出託管執行緒的呼叫棧。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3b40 (0)【底層作業系統的ID】
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 6 000000D3A5F7E530 00007ffc0bf676eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/.../LibraryImports.g.cs @ 412]
 7 000000D3A5F7E620 00007ffc0bf6c9c0 System.ConsolePal+WindowsConsoleStream..../System/ConsolePal.Windows.cs @ 1150]
 8 000000D3A5F7E680 00007ffc0bf6c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/....Windows.cs @ 1108]
 9 000000D3A5F7E6C0 00007ffc0bf6fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/.../ConsoleStream.cs @ 34]
10 000000D3A5F7E730 00007ffb8d1589c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/.../IO/StreamReader.cs @ 613]
11 000000D3A5F7E780 00007ffb8d1590a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/.../StreamReader.cs @ 802]
12 000000D3A5F7E830 00007ffc0bf7005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
13 000000D3A5F7E880 00007ffc0bf69319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
14 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]

                    我們可以使用【!clrstack -l】,檢視託管執行緒呼叫棧,並顯示每個棧幀的區域性變數。

 1 0:000> !clrstack -l
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 。。。。。。(省略了)49 
50 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
51     LOCALS:
52         0x000000D3A5F7E8EC = 0x000000000000000a
53         0x000000D3A5F7E8E8 = 0x000000000000000b 這就是我們的區域性變數

                    如果我們想檢視託管呼叫棧的引數,可以使用【!clrstack -p】命令,p(parameter)引數。

 1 0:000> !clrstack -p
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 。。。。。。(省略了)47 
48 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
49     PARAMETERS:
50         args (0x000000D3A5F7E900) = 0x000001efb4408ea0(這個就是 Main 方法的 args 引數)

                    0x000001efb4408ea0 這個地址就是 Program.Main 方法的 args 引數,args 是字串陣列,是引用型別,我們可以直接使用【!dumpobj】來確認。

1 0:000> !dumpobj 0x000001efb4408ea0
2 Name:        System.String[]
3 MethodTable: 00007ffb2e3cfab0
4 EEClass:     00007ffb2e27c440
5 Tracked Type: false
6 Size:        24(0x18) bytes
7 Array:       Rank 1, Number of elements 0, Type CLASS (Print Array)
8 Fields:
9 None

                    如果想同時檢視區域性變數和引數,可以使用【!clrstack -a】命令。

 1 0:000> !clrstack -a
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 6 。。。。。。(省略了)
 7 
 8 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
 9     PARAMETERS:
10         args (0x000000D3A5F7E900) = 0x000001efb4408ea0 (這是引數)
11     LOCALS:
12         0x000000D3A5F7E8EC = 0x000000000000000a (這是區域性變數)
13         0x000000D3A5F7E8E8 = 0x000000000000000b (這是區域性變數)

        3.1.2、Threads
            A、基礎知識
                如何你想列舉出程序中所有的託管程式碼執行緒,可以使用【!threads】命令,或者簡寫形式【!t】。當然,這個命令也有一些開關設定,-live 只羅列出那些處於活躍狀態的執行緒的資訊,-special 只輸出程序中所有“特殊的”執行緒,比如:垃圾收集執行緒、偵錯程式執行緒、執行緒池定時器執行緒等。
            B、眼見為實
                除錯原始碼:ExampleCore_3_1_9
                除錯任務:Threads 命令的使用
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】,開啟偵錯程式視窗。
                    

                    

                    使用【g】命令,繼續執行偵錯程式,等到偵錯程式輸出以下內容:
                    

                    按【ctrl+c】組合鍵進入除錯模式。

 1 0:013> !threads
 2 ThreadCount:      8
 3 UnstartedThread:  1
 4 BackgroundThread: 5
 5 PendingThread:    1
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     40a0 0000021021F41380    2a020 Preemptive  000002102641E0B8:000002102641F060 0000021021F2FD20 -00001 MTA
11    6    2     2fec 00000210239FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 MTA (Finalizer)
12    8    4     41ec 0000021021F60190  302b220 Preemptive  000002102640D408:000002102640E658 0000021021F2FD20 -00001 MTA (Threadpool Worker)
13    9    5     37bc 0000021021F623B0  302b220 Preemptive  000002102640EA58:0000021026410678 0000021021F2FD20 -00001 MTA (Threadpool Worker)
14   10    6     3f0c 00000250B8A1CC50  302b220 Preemptive  0000021026410E68:0000021026410FD0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
15   11    7     3288 00000250B8A23990  302b220 Preemptive  00000210264117C8:0000021026412FF0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
16 XXXX    8        0 00000250B8A2A330  1039820 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn (Threadpool Worker)
17    7    3     3974 00000250B8A1F8F0     9600 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn

                    【!t】命令效果一樣,就不一一展示了。
                    ThreadCount:有多少個託管執行緒,這個程序裡面有8個。
                    UnstartedThread:已經建立,但是還沒有使用的執行緒,當前數量是1。
                    BackgroundThread:後臺執行緒的數量,這個程序裡面有5個。
                    PendingThread:阻塞的執行緒的數量,當前這個程序是1個阻塞的執行緒。
                    DeadThread:當一個執行緒完成任務,但是還沒有被回收,這個階段的執行緒就是死執行緒,也就是說這個執行緒物件底層的資料結構的 OSID 已經銷燬。               
                    以上就是介紹的主要名稱,下面接著介紹,列表的每一項。我們使用 C# Thread 型別宣告一個執行緒的時候,其實在作業系統和CLR都有一個資料結構相對應,有了 OSID我們才可以在工作管理員中看到執行緒物件。

                    第一列 DBG:是 Windbg 偵錯程式的執行緒 ID,Windbg 給自己的執行緒起了一個標識,便於以後使用,也可以區分託管執行緒和非託管執行緒。
                    第二列 ID:託管執行緒 ID 值,就是 這段程式碼的值:Environment.CurrentManagedThreadId
                    第三列 OSID:作業系統執行緒的 ID。
                    第四列 ThreadOBJ:指向底層 CLR 執行緒資料結構的指標,可以使用【dp】命令觀察其中的內容,我們檢視託管執行緒 ID=4 的【0000021021F60190】內容,紅色標註就是託管執行緒的ID=00000004,就是4。

1 0:013> dp 0000021021F60190
2 00000210`21f60190  00000000`00000000 00000000`0302b220(執行緒狀態)
3 00000210`21f601a0  00000013`9097f108 00000210`21f2fd20
4 00000210`21f601b0  baadf00d`00000004(執行緒ID) 00000210`21f601c0
5 00000210`21f601c0  00000210`21f601c0 00000210`21f601c0
6 00000210`21f601d0  00000000`00000000 baadf00d`baad0000
7 00000210`21f601e0  00000000`00000000 00000210`2640d408
8 00000210`21f601f0  00000210`2640e658 00000000`00002008
9 00000210`21f60200  00000000`00000000 00000000`00000000

                    紅色標註的就是執行緒的狀態。我們可以使用【dt coreclr!Thread 0000021021F60190】檢視 ThreadOBJ 的資料結構。

  1 0:013> dt coreclr!Thread 0000021021F60190
  2    +0x000 m_stackLocalAllocator : (null)
  3    =00007ffd`26cc9b34 m_DetachCount    : 0n0
  4    =00007ffd`26cc9b30 m_ActiveDetachCount : 0n0
  5    +0x008 m_State          : Volatile<enum Thread::ThreadState>
  6    +0x00c m_fPreemptiveGCDisabled : Volatile<unsigned long>
  7    +0x010 m_pFrame         : 0x00000013`9097f108 Frame
  8    +0x018 m_pDomain        : 0x00000210`21f2fd20 AppDomain
  9    +0x020 m_ThreadId       : 4(託管執行緒的 ID)
 10    +0x028 m_pHead          : 0x00000210`21f601c0 LockEntry
 11    +0x030 m_embeddedEntry  : LockEntry
 12    +0x050 m_pBlockingLock  : VolatilePtr<DeadlockAwareLock,DeadlockAwareLock *>
 13    +0x058 m_alloc_context  : gc_alloc_context
 14    +0x090 m_thAllocContextObj : TypeHandle
 15    +0x098 m_pTEB           : 0x00000013`8fae5000 _NT_TIB
 16    +0x0a0 m_pRCWStack      : 0x00000210`23a0aa20 RCWStackHeader
 17    +0x0a8 m_ThreadTasks    : 0 (No matching name)
 18    +0x0ac m_StateNC        : 0x1180 (No matching name)
 19    +0x0b0 m_dwForbidSuspendThread : Volatile<long>
 20    +0x0b4 m_dwHashCodeSeed : 0x170e7536
 21    +0x0b8 m_pLoadLimiter   : (null)
 22    +0x0c0 m_AbortType      : 0
 23    +0x0c8 m_AbortEndTime   : 0xffffffff`ffffffff
 24    +0x0d0 m_RudeAbortEndTime : 0xffffffff`ffffffff
 25    +0x0d8 m_fRudeAbortInitiated : 0n0
 26    +0x0dc m_AbortController : 0n0
 27    +0x0e0 m_AbortRequestLock : 0n0
 28    +0x0e4 m_ThrewControlForThread : 0
 29    +0x0e8 m_OSContext      : 0x00000210`21f60d40 _CONTEXT
 30    +0x0f0 m_pPendingTypeLoad : (null)
 31    +0x0f8 m_Link           : SLink
 32    +0x100 m_dwLastError    : 0
 33    +0x108 m_CacheStackBase : 0x00000013`90980000 Void
 34    +0x110 m_CacheStackLimit : 0x00000013`90800000 Void
 35    +0x118 m_CacheStackSufficientExecutionLimit : 0x00000013`90820000
 36    +0x120 m_CacheStackStackAllocNonRiskyExecutionLimit : 0x00000013`90880000
 37    +0x128 m_pvHJRetAddr    : 0xcccccccc`cccccccc Void
 38    +0x130 m_ppvHJRetAddrPtr : 0xcccccccc`cccccccc  -> ????
 39    +0x138 m_HijackedFunction : 0xbaadf00d`baadf00d MethodDesc
 40    +0x140 m_UserInterrupt  : 0n0
 41    +0x148 m_DebugSuspendEvent : CLREvent
 42    +0x158 m_EventWait      : CLREvent
 43    +0x168 m_WaitEventLink  : WaitEventLink
 44    +0x198 m_ThreadHandle   : 0x00000000`0000027c Void
 45    +0x1a0 m_ThreadHandleForClose : 0xffffffff`ffffffff Void
 46    +0x1a8 m_ThreadHandleForResume : 0xffffffff`ffffffff Void
 47    +0x1b0 m_WeOwnThreadHandle : 0n1
 48    +0x1b8 m_OSThreadId     : 0x41ec
 49    +0x1c0 m_ExposedObject  : 0x00000210`23861180 OBJECTHANDLE__
 50    +0x1c8 m_StrongHndToExposedObject : 0x00000210`23861368 OBJECTHANDLE__
 51    +0x1d0 m_Priority       : 0x80000000
 52    +0x1d4 m_ExternalRefCount : 2
 53    +0x1d8 m_TraceCallCount : 0n0
 54    +0x1e0 m_LastThrownObjectHandle : (null)
 55    +0x1e8 m_ltoIsUnhandled : 0n0
 56    +0x1f0 m_ExceptionState : ThreadExceptionState
 57    +0x398 m_debuggerFilterContext : (null)
 58    +0x3a0 m_pProfilerFilterContext : (null)
 59    +0x3a8 m_hijackLock     : Volatile<long>
 60    +0x3b0 m_hCurrNotification : 0xbaadf00d`baadf00d OBJECTHANDLE__
 61    +0x3b8 m_fInteropDebuggingHijacked : 0n0
 62    +0x3bc m_profilerCallbackState : 0
 63    +0x3c0 m_dwProfilerEvacuationCounters : [33] Volatile<unsigned long>
 64    +0x444 m_monitorLockContentionCount : 2
 65    =00007ffd`26cc9b18 s_monitorLockContentionCountOverflow : 0
 66    +0x448 m_PreventAsync   : 0n0
 67    =00007ffd`26cc7310 m_DebugWillSyncCount : 0n-1
 68    +0x450 m_pSavedRedirectContext : (null)
 69    +0x458 m_pOSContextBuffer : (null)
 70    +0x460 m_ThreadLocalBlock : ThreadLocalBlock
 71    +0x488 m_tailCallTls    : TailCallTls
 72    +0x498 m_dwAVInRuntimeImplOkayCount : 0
 73    +0x4a0 m_pExceptionDuringStartup : (null)
 74    +0x4a8 m_debuggerActivePatchSkipper : VolatilePtr<DebuggerPatchSkip,DebuggerPatchSkip *>
 75    +0x4b0 m_fAllowProfilerCallbacks : 0n1
 76    +0x4b4 m_dwThreadHandleBeingUsed : Volatile<long>
 77    =00007ffd`26cc9b10 s_fCleanFinalizedThread : 0n0
 78    +0x4b8 m_pCreatingThrowableForException : (null)
 79    +0x4c0 m_dwIndexClauseForCatch : 0
 80    +0x4c8 m_sfEstablisherOfActualHandlerFrame : StackFrame
 81    +0x4d0 DebugBlockingInfo : ThreadDebugBlockingInfo
 82    +0x4d8 m_fDisableComObjectEagerCleanup : 0
 83    +0x4d9 m_fHasDeadThreadBeenConsideredForGCTrigger : 0
 84    +0x4dc m_random         : CLRRandom
 85    +0x5c8 m_uliInitializeSpyCookie : _ULARGE_INTEGER 0x0
 86    +0x5d0 m_fInitializeSpyRegistered : 0
 87    +0x5d8 m_pLastSTACtxCookie : (null)
 88    +0x5e0 m_fGCSpecial     : 0
 89    +0x5e8 m_pGCFrame       : 0x00000013`9097ef98 GCFrame
 90    +0x5f0 m_wCPUGroup      : 0
 91    +0x5f8 m_pAffinityMask  : 0
 92    +0x600 m_pAllLoggedTypes : (null)
 93    +0x608 m_gcModeOnSuspension : Volatile<unsigned long>
 94    +0x60c m_activityId     : _GUID {00000000-0000-0000-0000-000000000000}
 95    +0x61c m_HijackReturnKind : ff ( RT_Illegal )
 96    =00007ffd`26cc9b80 dead_threads_non_alloc_bytes : 0xa00
 97    +0x620 m_currentPrepareCodeConfig : (null)
 98    +0x628 m_isInForbidSuspendForDebuggerRegion : 0
 99    =00007ffd`26cdb7e0 s_pfnQueueUserAPC2Proc : (null)
100    +0x629 m_hasPendingActivation : 0

                    +0x020 m_ThreadId: 4 表示託管執行緒的ID。因為我列印的是 ThreadOBJ 為00000199DFD0CAE0 執行緒的結構。m 表示Management 託管的。

                    我們可以繼續看看 GC Alloc Context,在輸出的結構中有這樣一行程式碼:+0x058 m_alloc_context : gc_alloc_context,藍色的字型,可以點選,相當於執行【dx】命令。

                    第五列 State:CLR 層面的執行緒狀態,0302b220 就是託管執行緒的狀態。我們可以點進去或者使用【!threadstate】命令檢視執行緒狀態詳情,當前就是託管執行緒是3的狀態。

1 0:013> !threadstate 0302b220
2     Legal to Join(可以執行 join 操作)
3     Background(是後臺執行緒)
4     CLR Owns(是CLR 擁有的執行緒)
5     CoInitialized
6     In Multi Threaded Apartment(是MTA模式)
7     Fully initialized(已經完全初始化)
8     Thread Pool Worker Thread(是執行緒池執行緒)
9     Interruptible(可執行中斷操作)

                    第六列 GC Mode:表示當前的執行緒有沒有操作託管堆的許可權。
                    第七列 GC Alloc Context:緩衝區的開始節點和結束節點,每個執行緒在託管堆中分配一個物件,都有一個緩衝區,這個就是確定了緩衝區起始和結束。
                    第八列 Domain:表示當前執行緒所屬於的域。
                    第九列 Lock Count:表示當前的執行緒有多少個託管鎖。
                    第十列 Apt:表示執行緒是 STA(執行緒序列模式,WPF、WinForm) 模式還是 MTA (多執行緒並行模式)模式。
                    第十一列 Exception:在當前執行緒上發生了異常,會把這個異常和這個執行緒關聯起來。
                    Finalizer 表示當前是終結器執行緒,Threadpool Worker 表示執行緒是執行緒池的執行緒。

                    我們先來看看【-live】開關的使用。

 1 0:013> !threads -live
 2 ThreadCount:      8
 3 UnstartedThread:  1
 4 BackgroundThread: 5
 5 PendingThread:    1
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     40a0 0000021021F41380    2a020 Preemptive  000002102641E0B8:000002102641F060 0000021021F2FD20 -00001 MTA
11    6    2     2fec 00000210239FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 MTA (Finalizer)
12    8    4     41ec 0000021021F60190  302b220 Preemptive  000002102640D408:000002102640E658 0000021021F2FD20 -00001 MTA (Threadpool Worker)
13    9    5     37bc 0000021021F623B0  302b220 Preemptive  000002102640EA58:0000021026410678 0000021021F2FD20 -00001 MTA (Threadpool Worker)
14   10    6     3f0c 00000250B8A1CC50  302b220 Preemptive  0000021026410E68:0000021026410FD0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
15   11    7     3288 00000250B8A23990  302b220 Preemptive  00000210264117C8:0000021026412FF0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
16    7    3     3974 00000250B8A1F8F0     9600 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn
17 0:013> !t -live
18 ThreadCount:      8
19 UnstartedThread:  1
20 BackgroundThread: 5
21 PendingThread:    1
22 DeadThread:       1
23 Hosted Runtime:   no
24                                                                                                             Lock
25  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
26    0    1     40a0 0000021021F41380    2a020 Preemptive  000002102641E0B8:000002102641F060 0000021021F2FD20 -00001 MTA
27    6    2     2fec 00000210239FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 MTA (Finalizer)
28    8    4     41ec 0000021021F60190  302b220 Preemptive  000002102640D408:000002102640E658 0000021021F2FD20 -00001 MTA (Threadpool Worker)
29    9    5     37bc 0000021021F623B0  302b220 Preemptive  000002102640EA58:0000021026410678 0000021021F2FD20 -00001 MTA (Threadpool Worker)
30   10    6     3f0c 00000250B8A1CC50  302b220 Preemptive  0000021026410E68:0000021026410FD0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
31   11    7     3288 00000250B8A23990  302b220 Preemptive  00000210264117C8:0000021026412FF0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
32    7    3     3974 00000250B8A1F8F0     9600 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn

                    我們先來看看【-special】開關的使用。

 1 0:013> !t -special
 2 ThreadCount:      8
 3 UnstartedThread:  1
 4 BackgroundThread: 5
 5 PendingThread:    1
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     40a0 0000021021F41380    2a020 Preemptive  000002102641E0B8:000002102641F060 0000021021F2FD20 -00001 MTA
11    6    2     2fec 00000210239FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 MTA (Finalizer)
12    8    4     41ec 0000021021F60190  302b220 Preemptive  000002102640D408:000002102640E658 0000021021F2FD20 -00001 MTA (Threadpool Worker)
13    9    5     37bc 0000021021F623B0  302b220 Preemptive  000002102640EA58:0000021026410678 0000021021F2FD20 -00001 MTA (Threadpool Worker)
14   10    6     3f0c 00000250B8A1CC50  302b220 Preemptive  0000021026410E68:0000021026410FD0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
15   11    7     3288 00000250B8A23990  302b220 Preemptive  00000210264117C8:0000021026412FF0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
16 XXXX    8        0 00000250B8A2A330  1039820 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn (Threadpool Worker)
17    7    3     3974 00000250B8A1F8F0     9600 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn
18 WARNING: SOS needs to be upgraded for this version of the runtime. Some commands may not work correctly.
19 For more information see https://go.microsoft.com/fwlink/?linkid=2135652
20 
21 
22           OSID Special thread type
23         5 1464 DbgHelper
24         6 2fec Finalizer
25 
26 0:013> !threads -special
27 ThreadCount:      8
28 UnstartedThread:  1
29 BackgroundThread: 5
30 PendingThread:    1
31 DeadThread:       1
32 Hosted Runtime:   no
33                                                                                                             Lock
34  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
35    0    1     40a0 0000021021F41380    2a020 Preemptive  000002102641E0B8:000002102641F060 0000021021F2FD20 -00001 MTA
36    6    2     2fec 00000210239FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 MTA (Finalizer)
37    8    4     41ec 0000021021F60190  302b220 Preemptive  000002102640D408:000002102640E658 0000021021F2FD20 -00001 MTA (Threadpool Worker)
38    9    5     37bc 0000021021F623B0  302b220 Preemptive  000002102640EA58:0000021026410678 0000021021F2FD20 -00001 MTA (Threadpool Worker)
39   10    6     3f0c 00000250B8A1CC50  302b220 Preemptive  0000021026410E68:0000021026410FD0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
40   11    7     3288 00000250B8A23990  302b220 Preemptive  00000210264117C8:0000021026412FF0 0000021021F2FD20 -00001 MTA (Threadpool Worker)
41 XXXX    8        0 00000250B8A2A330  1039820 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn (Threadpool Worker)
42    7    3     3974 00000250B8A1F8F0     9600 Preemptive  0000000000000000:0000000000000000 0000021021F2FD20 -00001 Ukn
43 WARNING: SOS needs to be upgraded for this version of the runtime. Some commands may not work correctly.
44 For more information see https://go.microsoft.com/fwlink/?linkid=2135652
45 
46 
47           OSID Special thread type
48         5 1464 DbgHelper
49         6 2fec Finalizer

                    上面的引數使用都很簡單,就不多數了。

                2)、Windbg Preview 除錯
                    編譯專案,開啟 Windbg Preview 偵錯程式,依次點選【檔案】--->【Launch executable】載入我們的專案檔案:ExampleCore_3_1_9.exe,進入偵錯程式。【g】繼續執行偵錯程式,等我們的控制檯程式輸出如圖:
                    

                    此時,我們的偵錯程式也處於暫停狀態,點選【break】按鈕,進入偵錯程式的中斷模式。
                    我們可以使用【!threads】命令或者【!t】命令檢視託管執行緒的內容。

 1 0:001> !t
 2 ThreadCount:      7
 3 UnstartedThread:  0
 4 BackgroundThread: 5
 5 PendingThread:    0
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock  
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
11    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
12    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
13    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
14   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
15   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
16 XXXX    8        0 0000032707F17880  1039820 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 Ukn (Threadpool Worker) 
17 
18 
19 0:001> !threads
20 ThreadCount:      7
21 UnstartedThread:  0
22 BackgroundThread: 5
23 PendingThread:    0
24 DeadThread:       1
25 Hosted Runtime:   no
26                                                                                                             Lock  
27  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
28    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
29    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
30    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
31    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
32   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
33   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
34 XXXX    8        0 0000032707F17880  1039820 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 Ukn (Threadpool Worker) 

                    ThreadCount:有多少個託管執行緒,這個程序裡面有7個。
                    UnstartedThread:已經建立,但是還沒有使用的執行緒,當前數量是0。
                    BackgroundThread:後臺執行緒的數量,這個程序裡面有5個。
                    PendingThread:阻塞的執行緒的數量,當前這個程序是0個阻塞的執行緒。
                    DeadThread:當一個執行緒完成任務,但是還沒有被回收,這個階段的執行緒就是死執行緒,也就是說這個執行緒物件底層的資料結構的 OSID 已經銷燬。               
                    以上就是介紹的主要名稱,下面接著介紹,列表的每一項。我們使用 C# Thread 型別宣告一個執行緒的時候,其實在作業系統和CLR都有一個資料結構相對應,有了 OSID我們才可以在工作管理員中看到執行緒物件。

                    第一列 DBG:是 Windbg 偵錯程式自己的執行緒 ID,也可以區分託管執行緒和非託管執行緒。
                    第二列 ID:是託管執行緒,也就是我們 Thread 型別的識別符號 Id,就是這段程式碼的值:Environment.CurrentManagedThreadId
                    第三列 OSID:作業系統執行緒的 ID。
                    第四列 ThreadOBJ:指向底層 CLR 執行緒資料結構的指標,可以使用【dp】命令觀察其中的內容,我們檢視託管執行緒 ID=4 的【0000032708325930】內容,紅色標註就是託管執行緒的ID=00000004,就是4。

1 0:001> dp 0000032708325930
2 00000327`08325930  00000000`00000000 00000000`0302b220
3 00000327`08325940  000000e8`2457f518 000002e6`719d7b00
4 00000327`08325950  baadf00d`00000004 00000327`08325960
5 00000327`08325960  00000327`08325960 00000327`08325960
6 00000327`08325970  00000000`00000000 baadf00d`baad0000
7 00000327`08325980  00000000`00000000 000002e6`75c0ceb8
8 00000327`08325990  000002e6`75c0e658 00000000`00002008
9 00000327`083259a0  00000000`00000000 00000000`00000000

                    第五列 State:CLR 層面的執行緒狀態,00000000`0302b220 就是託管執行緒的狀態。我們可以點進去或者使用【!threadstate】命令檢視執行緒狀態詳情,當前就是託管執行緒是4的狀態。

1 0:001> !threadstate 00000000`0302b220
2     Legal to Join(可以執行 join 操作)
3     Background(是後臺執行緒)
4     CLR Owns(是CLR 擁有的執行緒)
5     CoInitialized(是以單執行緒方式建立的)
6     In Multi Threaded Apartment(是MTA模式)
7     Fully initialized(已經完全初始化)
8     Thread Pool Worker Thread(是執行緒池執行緒)
9     Interruptible(可執行中斷操作)

                    第六列 GC Mode:表示當前的執行緒有沒有操作託管堆的許可權。
                    第七列 GC Alloc Context:緩衝區的開始節點和結束節點,每個執行緒在託管堆中分配一個物件,都有一個緩衝區,這個就是確定了緩衝區起始和結束。
                    第八列 Domain:表示當前執行緒所屬於的域。
                    第九列 Lock Count:表示當前的執行緒有多少個託管鎖。
                    第十列 Apt:表示執行緒是 STA(執行緒序列模式,WPF、WinForm) 模式還是 MTA (多執行緒並行模式)模式。
                    第十一列 Exception:在當前執行緒上發生了異常,會把這個異常和這個執行緒關聯起來。
                    Finalizer 表示當前是終結器執行緒,Threadpool Worker 表示執行緒是執行緒池的執行緒。

                    我們可以使用【!t -live】或者【!threads -live】輸出活躍的執行緒。

 1 0:001> !t -live
 2 ThreadCount:      7
 3 UnstartedThread:  0
 4 BackgroundThread: 5
 5 PendingThread:    0
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock  
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
11    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
12    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
13    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
14   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
15   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
16 
17 0:001> !threads -live
18 ThreadCount:      7
19 UnstartedThread:  0
20 BackgroundThread: 5
21 PendingThread:    0
22 DeadThread:       1
23 Hosted Runtime:   no
24                                                                                                             Lock  
25  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
26    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
27    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
28    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
29    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
30   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
31   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 

                    這裡就沒有了 DBG 為 XXXX 的執行緒了。
                    接下來,我們在看看【!threads -special】或者【!t -special】命令的區別。效果很明顯,就不多說了。

 1 0:001> !t -special
 2 ThreadCount:      7
 3 UnstartedThread:  0
 4 BackgroundThread: 5
 5 PendingThread:    0
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock  
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
11    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
12    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
13    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
14   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
15   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
16 XXXX    8        0 0000032707F17880  1039820 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 Ukn (Threadpool Worker) 
17 
18           OSID Special thread type
19         5 1220 DbgHelper 
20         6 16f4 Finalizer 
21 
22 
23 0:001> !threads -special
24 ThreadCount:      7
25 UnstartedThread:  0
26 BackgroundThread: 5
27 PendingThread:    0
28 DeadThread:       1
29 Hosted Runtime:   no
30                                                                                                             Lock  
31  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
32    0    1     3968 000002E6719982E0    2a020 Preemptive  000002E675C1E0B8:000002E675C1F060 000002e6719d7b00 -00001 MTA 
33    6    2     16f4 000002E671A45C40    2b220 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 MTA (Finalizer) 
34    8    4     1574 0000032708325930  302b220 Preemptive  000002E675C0CEB8:000002E675C0E658 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
35    9    5     3ac8 0000032708328D40  302b220 Preemptive  000002E675C0EA58:000002E675C10678 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
36   10    6     2bf8 0000032707F16910  302b220 Preemptive  000002E675C1F490:000002E675C20FD0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
37   11    7     386c 000003270832E2F0  302b220 Preemptive  000002E675C117C8:000002E675C12FF0 000002e6719d7b00 -00001 MTA (Threadpool Worker) 
38 XXXX    8        0 0000032707F17880  1039820 Preemptive  0000000000000000:0000000000000000 000002e6719d7b00 -00001 Ukn (Threadpool Worker) 
39 
40           OSID Special thread type
41         5 1220 DbgHelper 
42         6 16f4 Finalizer 
                    紅色標註的就是輸出的區別資訊,很簡單,就不多說了。

        3.1.3、DumpStack
            A、基礎知識
                ClrStack 命令只輸出託管程式碼呼叫棧,內容更詳盡(比如:包含方法名稱和方法所需的引數),k 系列命令既可以輸出非託管程式碼呼叫棧,也可以輸出託管程式碼呼叫棧,這裡說明一下,和原書是不一樣的,原書中講只能輸出非託管呼叫棧,可能因為我使用的 .NET 8.0 平臺的原因,兩種呼叫棧都可以輸出。如果想同時獲取託管程式碼呼叫棧和非託管程式碼呼叫棧,可以使用 DumpStack 命令。
            B、眼見為實
                除錯原始碼:namespace ExampleCore_3_1_9
                除錯任務:DumpStack 命令和 k 命令使用
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.EXE】,開啟偵錯程式視窗。
                    進入偵錯程式後,我們【g】繼續執行偵錯程式,直到偵錯程式輸出如圖內容,我們按【ctrl+c】進入偵錯程式的中斷模式。
                    

                    我們先切換到託管執行緒上,執行命令【~0s】。

1 0:012> ~0s
2 coreclr!CLREventWaitWithTry:
3 00007ffe`1c3c5074 48895c2408      mov     qword ptr [rsp+8],rbx ss:000000dc`87d7e860=0000000000000001

                    。。。。。。。。

                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:namespace ExampleCore_3_1_9.exe。進入偵錯程式後,【g】繼續執行偵錯程式,直到我們的控制檯程式有如下輸出為止。
                    

                    此時,我們的偵錯程式也處於等待狀態,按【break】按鈕,進入中斷模式,開始我們的除錯。
                    首先,我們先切換到託管執行緒上下文,執行【~0s】命令。

1 0:001> ~0s
2 ntdll!NtReadFile+0x14:
3 00007ffe`d6faae54 c3              ret

                    然後,我們執行【k】命令,檢視一下非託管程式碼的呼叫棧。

 1 0:000> k
 2  # Child-SP          RetAddr               Call Site
 3 00 000000da`5b97e318 00007ffe`d44d8a53     ntdll!NtReadFile+0x14
 4 01 000000da`5b97e320 00007ffe`c2c37704     KERNELBASE!ReadFile+0x73
 5 02 000000da`5b97e3a0 00007ffe`c2c3c9c0     System_Console!Interop.Kernel32.ReadFile+0x84 [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412] 
 6 03 000000da`5b97e490 00007ffe`c2c3c8bb     System_Console!System.ConsolePal.WindowsConsoleStream.ReadFileNative+0x60 [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150] 
 7 04 000000da`5b97e4f0 00007ffe`c2c3fb84     System_Console!System.ConsolePal.WindowsConsoleStream.Read+0x2b [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108] 
 8 05 000000da`5b97e530 00007ffd`fcc489c1     System_Console!System.IO.ConsoleStream.Read+0x74 [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34] 
 9 06 000000da`5b97e5a0 00007ffd`fcc490a4     System_Private_CoreLib!System.IO.StreamReader.ReadBuffer+0x41 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613] 
10 07 000000da`5b97e5f0 00007ffe`c2c4005d     System_Private_CoreLib!System.IO.StreamReader.ReadLine+0x64 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802] 
11 08 000000da`5b97e6a0 00007ffe`c2c39319     System_Console!System.IO.SyncTextReader.ReadLine+0x3d [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77] 
12 09 000000da`5b97e6f0 00007ffd`9e0c19cf     System_Console!System.Console.ReadLine+0x19 [/_/src/libraries/System.Console/src/System/Console.cs @ 752] 
13 0a 000000da`5b97e720 00007ffd`fdc3a1a3     ExampleCore_3_1_9!ExampleCore_3_1_9.Program.Main+0x9f [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\Program.cs @ 11] 
14 0b 000000da`5b97e770 00007ffd`fdbc14c9     coreclr!CallDescrWorkerInternal+0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm @ 100] 
15 0c (Inline Function) --------`--------     coreclr!CallDescrWorkerWithHandler+0x56 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 67] 
16 0d 000000da`5b97e7b0 00007ffd`fdae75ac     coreclr!MethodDescCallSite::CallTargetWorker+0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 570] 
17 0e (Inline Function) --------`--------     coreclr!MethodDescCallSite::Call+0xb [D:\a\_work\1\s\src\coreclr\vm\callhelpers.h @ 458] 
18 0f 000000da`5b97e8f0 00007ffd`fdae6f7a     coreclr!RunMainInternal+0x11c [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1304] 
19 10 000000da`5b97ea10 00007ffd`fdae6b17     coreclr!RunMain+0xd2 [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1375] 
20 11 000000da`5b97eac0 00007ffd`fdae7321     coreclr!Assembly::ExecuteMainMethod+0x1bf [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1504] 
21 12 000000da`5b97ed90 00007ffd`fdbf7768     coreclr!CorHost2::ExecuteAssembly+0x281 [D:\a\_work\1\s\src\coreclr\vm\corhost.cpp @ 349] 
22 13 000000da`5b97ef00 00007ffe`c2c82c36     coreclr!coreclr_execute_assembly+0xd8 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp @ 504] 
23 14 (Inline Function) --------`--------     hostpolicy!coreclr_t::execute_assembly+0x2a [D:\a\_work\1\s\src\native\corehost\hostpolicy\coreclr.cpp @ 109] 
24 15 000000da`5b97efa0 00007ffe`c2c82f1c     hostpolicy!run_app_for_context+0x596 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 256] 
25 16 000000da`5b97f130 00007ffe`c2c8385a     hostpolicy!run_app+0x3c [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 285] 
26 17 000000da`5b97f170 00007ffe`c2cdb5c9     hostpolicy!corehost_main+0x15a [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 426] 
27 18 000000da`5b97f270 00007ffe`c2cde066     hostfxr!execute_app+0x2e9 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 145] 
28 19 000000da`5b97f370 00007ffe`c2ce02ec     hostfxr!`anonymous namespace'::read_config_and_execute+0xa6 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 532] 
29 1a 000000da`5b97f460 00007ffe`c2cde644     hostfxr!fx_muxer_t::handle_exec_host_command+0x16c [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 1007] 
30 1b 000000da`5b97f510 00007ffe`c2cd85a0     hostfxr!fx_muxer_t::execute+0x494 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 578] 
31 1c 000000da`5b97f650 00007ff7`e1a5f998     hostfxr!hostfxr_main_startupinfo+0xa0 [D:\a\_work\1\s\src\native\corehost\fxr\hostfxr.cpp @ 62] 
32 1d 000000da`5b97f750 00007ff7`e1a5fda6     apphost!exe_start+0x878 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 240] 
33 1e 000000da`5b97f920 00007ff7`e1a612e8     apphost!wmain+0x146 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 311] 
34 1f (Inline Function) --------`--------     apphost!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90] 
35 20 000000da`5b97f990 00007ffe`d5416fd4     apphost!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
36 21 000000da`5b97f9d0 00007ffe`d6f5cec1     KERNEL32!BaseThreadInitThunk+0x14
37 22 000000da`5b97fa00 00000000`00000000     ntdll!RtlUserThreadStart+0x21

                  我們再使用【!ClrStack】命令檢視一下託管呼叫棧,有什麼不同。

0:000> !clrstack
OS Thread Id: 0x10d4 (0)
        Child SP               IP Call Site
000000DA5B97E3D0 00007ffed6faae54 [InlinedCallFrame: 000000da5b97e3d0] 
000000DA5B97E3D0 00007ffec2c376eb [InlinedCallFrame: 000000da5b97e3d0] 
000000DA5B97E3A0 00007ffec2c376eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412]
000000DA5B97E490 00007ffec2c3c9c0 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1, Boolean, Int32 ByRef, Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150]
000000DA5B97E4F0 00007ffec2c3c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108]
000000DA5B97E530 00007ffec2c3fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34]
000000DA5B97E5A0 00007ffdfcc489c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613]
000000DA5B97E5F0 00007ffdfcc490a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802]
000000DA5B97E6A0 00007ffec2c4005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
000000DA5B97E6F0 00007ffec2c39319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
000000DA5B97E720 00007ffd9e0c19cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\Program.cs @ 11]

                  我們可以看到,【k】命令的輸出中包含【!clrstack】命令的輸出,只不過【!clrstack】命令,更詳細一點,每個方法的名稱和包含的引數都輸出了。

                  k 系列命令裡有一個命令很有用,那就是【kb】,這個命令可以提取方法的引數,我們可以嘗試提取【ntdll!NtReadFile+0x14】這個方法的第一個引數,瞭解它的用法。
 1 0:000> kb
 2  # RetAddr               : Args to Child                                                           : Call Site
 3 00 00007ffe`d44d8a53     : 00000000`00001000 00007ffd`fdc39da3 00000000`0000005c 000000da`5b97e3d0 : ntdll!NtReadFile+0x14
 4 01 00007ffe`c2c37704     : 00000000`0000005c 00000000`0000005c 00000000`00001000 000000da`5b97e520 : KERNELBASE!ReadFile+0x73
 5 02 00007ffe`c2c3c9c0     : 00000000`0000005c 00000251`29815038 00000000`00001000 000000da`5b97e520 : System_Console!Interop.Kernel32.ReadFile+0x84 [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412] 
 6 03 00007ffe`c2c3c8bb     : 00000000`0000005c 000000da`5b97e558 00000000`00000000 000000da`5b97e520 : System_Console!System.ConsolePal.WindowsConsoleStream.ReadFileNative+0x60 [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150] 
 7 04 00007ffe`c2c3fb84     : 00000251`2980c0d0 000000da`5b97e558 00000000`00000000 00000000`00001000 : System_Console!System.ConsolePal.WindowsConsoleStream.Read+0x2b [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108] 
 8 05 00007ffd`fcc489c1     : 00000251`2980c0d0 00000251`29815028 00000000`00000000 00000000`00001000 : System_Console!System.IO.ConsoleStream.Read+0x74 [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34] 
 9 06 00007ffd`fcc490a4     : 00000251`2980c138 00000251`25198390 00000251`29809670 00000000`00000001 : System_Private_CoreLib!System.IO.StreamReader.ReadBuffer+0x41 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613] 
10 07 00007ffe`c2c4005d     : 00000251`2980c138 00000251`25198390 00000251`29809670 00000000`00000001 : System_Private_CoreLib!System.IO.StreamReader.ReadLine+0x64 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802] 
11 08 00007ffe`c2c39319     : 00000251`2981e070 00000000`00000000 00000251`29809670 00000251`29c00000 : System_Console!System.IO.SyncTextReader.ReadLine+0x3d [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77] 
12 09 00007ffd`9e0c19cf     : 00000000`00000001 00000251`2980c020 00000251`2980b150 00000000`00000007 : System_Console!System.Console.ReadLine+0x19 [/_/src/libraries/System.Console/src/System/Console.cs @ 752] 
13 0a 00007ffd`fdc3a1a3     : 00000251`29808ea0 000000da`5b97edb8 000000da`5b97edb8 000000da`5b97e9a9 : ExampleCore_3_1_9!ExampleCore_3_1_9.Program.Main+0x9f [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\Program.cs @ 11] 
14 0b 00007ffd`fdbc14c9     : 00000000`00000000 00000000`00000130 000000da`5b97e9b8 00007ffd`fdaea456 : coreclr!CallDescrWorkerInternal+0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm @ 100] 
15 0c (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!CallDescrWorkerWithHandler+0x56 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 67] 
16 0d 00007ffd`fdae75ac     : 000000da`5b97ea38 00000000`00000000 00000000`00000048 00007ffd`fdbd28a6 : coreclr!MethodDescCallSite::CallTargetWorker+0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 570] 
17 0e (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!MethodDescCallSite::Call+0xb [D:\a\_work\1\s\src\coreclr\vm\callhelpers.h @ 458] 
18 0f 00007ffd`fdae6f7a     : 00000251`29808ea0 00000251`29808ea0 00000000`00000000 000000da`5b97edb8 : coreclr!RunMainInternal+0x11c [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1304] 
19 10 00007ffd`fdae6b17     : 00000251`25198390 00000251`00000000 00000251`25198390 00000000`00000000 : coreclr!RunMain+0xd2 [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1375] 
20 11 00007ffd`fdae7321     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000130 : coreclr!Assembly::ExecuteMainMethod+0x1bf [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1504] 
21 12 00007ffd`fdbf7768     : 00000000`00000001 000000da`5b97ef01 000000da`5b97efe0 00007ffe`c2c623ea : coreclr!CorHost2::ExecuteAssembly+0x281 [D:\a\_work\1\s\src\coreclr\vm\corhost.cpp @ 349] 
22 13 00007ffe`c2c82c36     : 00000251`2516a900 00000251`2516a660 00000000`00000000 00000251`2516a660 : coreclr!coreclr_execute_assembly+0xd8 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp @ 504] 
23 14 (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : hostpolicy!coreclr_t::execute_assembly+0x2a [D:\a\_work\1\s\src\native\corehost\hostpolicy\coreclr.cpp @ 109] 
24 15 00007ffe`c2c82f1c     : 00000251`25158228 000000da`5b97f209 00007ffe`c2cbc9c0 00000251`25158228 : hostpolicy!run_app_for_context+0x596 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 256] 
25 16 00007ffe`c2c8385a     : 00000000`00000000 00000251`25158220 00000251`25158220 00000000`00000000 : hostpolicy!run_app+0x3c [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 285] 
26 17 00007ffe`c2cdb5c9     : 00000251`251669e8 00000251`251668d0 00000000`00000000 000000da`5b97f309 : hostpolicy!corehost_main+0x15a [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 426] 
27 18 00007ffe`c2cde066     : 00000251`25167540 000000da`5b97f690 00000000`00000000 00000000`00000000 : hostfxr!execute_app+0x2e9 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 145] 
28 19 00007ffe`c2ce02ec     : 00007ffe`c2d125f8 00000251`251680d0 000000da`5b97f5d0 000000da`5b97f580 : hostfxr!`anonymous namespace'::read_config_and_execute+0xa6 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 532] 
29 1a 00007ffe`c2cde644     : 000000da`5b97f690 000000da`5b97f6b0 000000da`5b97f601 00000251`25168401 : hostfxr!fx_muxer_t::handle_exec_host_command+0x16c [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 1007] 
30 1b 00007ffe`c2cd85a0     : 000000da`5b97f6b0 00000251`25166690 00000000`00000001 00000251`25150000 : hostfxr!fx_muxer_t::execute+0x494 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 578] 
31 1c 00007ff7`e1a5f998     : 00007ffe`d48ef4e8 00007ffe`c2cd9b10 000000da`5b97f850 00000251`25166380 : hostfxr!hostfxr_main_startupinfo+0xa0 [D:\a\_work\1\s\src\native\corehost\fxr\hostfxr.cpp @ 62] 
32 1d 00007ff7`e1a5fda6     : 00007ff7`e1a6b6c0 00000000`00000007 00000251`25158220 00000000`0000005e : apphost!exe_start+0x878 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 240] 
33 1e 00007ff7`e1a612e8     : 00000000`00000000 00000000`00000000 00000251`25158220 00000000`00000000 : apphost!wmain+0x146 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 311] 
34 1f (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : apphost!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90] 
35 20 00007ffe`d5416fd4     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : apphost!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
36 21 00007ffe`d6f5cec1     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
37 22 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

                  00000000`00001000 00007ffd`fdc39da3 00000000`0000005c 000000da`5b97e3d0 這些就是 ntdll!NtReadFile 方法所需的具體引數。
                  我們使用【!DumpStack】命令,看看輸出的內容。

 1 0:000> !dumpstack
 2 OS Thread Id: 0x10d4 (0)
 3 Current frame: ntdll!NtReadFile + 0x14
 4 Child-SP         RetAddr          Caller, Callee
 5 000000DA5B97E310 00007ffed44d8a53 KERNELBASE!ReadFile + 0x73, calling ntdll!NtReadFile
 6 000000DA5B97E320 00007ffdfdc39da3 coreclr!NDirectImportThunk + 0x43 [D:\a\_work\1\s\src\coreclr\vm\amd64\AsmHelpers.asm:185], calling coreclr!NDirectImportWorker [D:\a\_work\1\s\src\coreclr\vm\dllimport.cpp:5834]
 7 000000DA5B97E390 00007ffec2c37704 (MethodDesc 00007ffd9e17dff8 + 0x84 Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
 8 000000DA5B97E3F0 00007ffec2c376eb (MethodDesc 00007ffd9e17dff8 + 0x6b Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr)), calling coreclr!JIT_PInvokeBegin [D:\a\_work\1\s\src\coreclr\vm\amd64\PInvokeStubs.asm:142]
 9 000000DA5B97E480 00007ffec2c3c9c0 (MethodDesc 00007ffd9e1a2cc0 + 0x60 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1<Byte>, Boolean, Int32 ByRef, Boolean)), calling System_Console + 0x10b04
10 000000DA5B97E4E0 00007ffec2c3c8bb (MethodDesc 00007ffd9e1a2c90 + 0x2b System.ConsolePal+WindowsConsoleStream.Read(System.Span`1<Byte>)), calling System_Console + 0x10b04
11 000000DA5B97E520 00007ffec2c3fb84 (MethodDesc 00007ffd9e1a2968 + 0x74 System.IO.ConsoleStream.Read(Byte[], Int32, Int32))
12 000000DA5B97E590 00007ffdfcc489c1 (MethodDesc 00007ffd9e1f6080 + 0x41 System.IO.StreamReader.ReadBuffer())
13 000000DA5B97E5E0 00007ffdfcc490a4 (MethodDesc 00007ffd9e1f60a8 + 0x64 System.IO.StreamReader.ReadLine())
14 000000DA5B97E690 00007ffec2c4005d (MethodDesc 00007ffd9e1ff650 + 0x3d System.IO.SyncTextReader.ReadLine())
15 000000DA5B97E6E0 00007ffec2c39319 (MethodDesc 00007ffd9e17a350 + 0x19 System.Console.ReadLine())
16 000000DA5B97E710 00007ffd9e0c19cf (MethodDesc 00007ffd9e1700c0 + 0x9f ExampleCore_3_1_9.Program.Main(System.String[])), calling 00007ffd9e2213e0
17 000000DA5B97E760 00007ffdfdc3a1a3 coreclr!CallDescrWorkerInternal + 0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm:100]
18 000000DA5B97E7A0 00007ffdfdbc14c9 coreclr!MethodDescCallSite::CallTargetWorker + 0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp:570], calling coreclr!CallDescrWorkerInternal [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm:37]
19 000000DA5B97E7C0 00007ffdfdaea456 coreclr!AppDomain::LoadDomainAssembly + 0xee [D:\a\_work\1\s\src\coreclr\vm\appdomain.cpp:2596], calling coreclr!AppDomain::LoadDomainAssembly [D:\a\_work\1\s\src\coreclr\vm\appdomain.cpp:2809]
20 000000DA5B97E830 00007ffdfdae708b coreclr!MethodDesc::IsVoid + 0x2f [D:\a\_work\1\s\src\coreclr\vm\method.cpp:987], calling coreclr!SigPointer::PeekElemTypeClosed [D:\a\_work\1\s\src\coreclr\vm\siginfo.cpp:2429]
21 000000DA5B97E8E0 00007ffdfdae75ac coreclr!RunMainInternal + 0x11c [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1304], calling coreclr!MethodDescCallSite::CallTargetWorker [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp:260]
22 000000DA5B97E900 00007ffdfdbd28a6 coreclr!MDInternalRO::GetSigOfMethodDef + 0x86 [D:\a\_work\1\s\src\coreclr\md\runtime\mdinternalro.cpp:1403], calling ntdll!LdrpDispatchUserCallTarget
23 000000DA5B97EA00 00007ffdfdae6f7a coreclr!RunMain + 0xd2 [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1375], calling coreclr!RunMainInternal [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1275]
24 000000DA5B97EAB0 00007ffdfdae6b17 coreclr!Assembly::ExecuteMainMethod + 0x1bf [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1504], calling coreclr!RunMain [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1324]
25 000000DA5B97EAF0 00007ffdfca71ae3 (MethodDesc 00007ffd9e14f460 + 0xa3 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**)), calling 00007ffd9e0c0378
26 000000DA5B97EB30 00007ffdfdc3b74a coreclr!DelayLoad_Helper + 0x7a [D:\a\_work\1\s\src\coreclr\vm\amd64\ExternalMethodFixupThunk.asm:61], calling coreclr!DynamicHelperWorker [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp:3776]
27 000000DA5B97EBF0 00007ffdfca71af0 (MethodDesc 00007ffd9e14f460 + 0xb0 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**)), calling 00007ffd9df50010
28 000000DA5B97EC50 00007ffdfdc3a1a3 coreclr!CallDescrWorkerInternal + 0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm:100]
29 000000DA5B97EC90 00007ffdfdb2389e coreclr!DispatchCallSimple + 0x72 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp:222], calling coreclr!__security_check_cookie [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\gs\amd64\amdsecgs.asm:45]
30 000000DA5B97ECB0 00007ffdfdbc1abf coreclr!MethodDesc::TryGetMultiCallableAddrOfCode + 0x87 [D:\a\_work\1\s\src\coreclr\vm\method.cpp:2071], calling coreclr!MethodDesc::GetMethodEntryPoint [D:\a\_work\1\s\src\coreclr\vm\method.cpp:477]
31 000000DA5B97ECF0 00007ffdfdbf9eb2 coreclr!`anonymous namespace'::GetConfigDWORD + 0x32 [D:\a\_work\1\s\src\coreclr\utilcode\clrconfig.cpp:247], calling coreclr!`anonymous namespace'::EnvGetString [D:\a\_work\1\s\src\coreclr\utilcode\clrconfig.cpp:134]
32 000000DA5B97ED80 00007ffdfdae7321 coreclr!CorHost2::ExecuteAssembly + 0x281 [D:\a\_work\1\s\src\coreclr\vm\corhost.cpp:349], calling coreclr!Assembly::ExecuteMainMethod [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp:1440]
33 000000DA5B97EDE0 00007ffed44ce8e6 KERNELBASE!MultiByteToWideChar + 0x186, calling KERNELBASE!_security_check_cookie
34 000000DA5B97EEB0 00007ffdfdbf7ad4 coreclr!StringToUnicode + 0x94 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp:87], calling KERNEL32!MultiByteToWideCharStub
35 000000DA5B97EEF0 00007ffdfdbf7768 coreclr!coreclr_execute_assembly + 0xd8 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp:504], calling ntdll!LdrpDispatchUserCallTarget
36 000000DA5B97EF10 00007ffec2c623ea hostpolicy!breadcrumb_writer_t::begin_write + 0x1ba [D:\a\_work\1\s\src\native\corehost\hostpolicy\breadcrumbs.cpp:39], calling hostpolicy!trace::verbose [D:\a\_work\1\s\src\native\corehost\hostmisc\trace.cpp:131]
37 000000DA5B97EF30 00007ffed4817381 ucrtbase!is_stream_flushable_or_commitable + 0x9, calling ucrtbase!is_stream_flushable
38 000000DA5B97EF60 00007ffed4818996 ucrtbase!fflush + 0x16, calling ucrtbase!is_stream_flushable_or_commitable
39 000000DA5B97EF90 00007ffec2c82c36 hostpolicy!run_app_for_context + 0x596 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:256], calling ntdll!LdrpDispatchUserCallTarget
40 000000DA5B97EFD0 00007ffed6f295f1 ntdll!RtlpFreeHeapInternal + 0x491, calling ntdll!RtlpHpStackLoggingEnabled
41 000000DA5B97F070 00007ffec2c9bd64 hostpolicy!mtx_do_lock + 0x11c [D:\a\_work\1\s\src\vctools\crt\github\stl\src\mutex.cpp:146], calling hostpolicy!__security_check_cookie [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\gs\amd64\amdsecgs.asm:45]
42 000000DA5B97F090 00007ffec2c9bc40 hostpolicy!_Mtx_unlock + 0x18 [D:\a\_work\1\s\src\vctools\crt\github\stl\src\mutex.cpp:159], calling ntdll!RtlReleaseSRWLockExclusive
43 000000DA5B97F0C0 00007ffec2c82316 hostpolicy!`anonymous namespace'::get_hostpolicy_context + 0x116 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:168], calling hostpolicy!_Mtx_unlock [D:\a\_work\1\s\src\vctools\crt\github\stl\src\mutex.cpp:148]
44 000000DA5B97F120 00007ffec2c82f1c hostpolicy!run_app + 0x3c [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:285], calling hostpolicy!run_app_for_context [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:208]
45 000000DA5B97F160 00007ffec2c8385a hostpolicy!corehost_main + 0x15a [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:426], calling hostpolicy!run_app [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp:280]
46 000000DA5B97F260 00007ffec2cdb5c9 hostfxr!execute_app + 0x2e9 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:145], calling ntdll!LdrpDispatchUserCallTarget
47 000000DA5B97F360 00007ffec2cde066 hostfxr!`anonymous namespace'::read_config_and_execute + 0xa6 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:532], calling hostfxr!execute_app [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:87]
48 000000DA5B97F3B0 00007ffed6f25d21 ntdll!RtlFreeHeap + 0x51, calling ntdll!RtlpFreeHeapInternal
49 000000DA5B97F450 00007ffec2ce02ec hostfxr!fx_muxer_t::handle_exec_host_command + 0x16c [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:1007], calling hostfxr!`anonymous namespace'::read_config_and_execute [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:515]
50 000000DA5B97F500 00007ffec2cde644 hostfxr!fx_muxer_t::execute + 0x494 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:578], calling hostfxr!fx_muxer_t::handle_exec_host_command [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:990]
51 000000DA5B97F640 00007ffec2cd85a0 hostfxr!hostfxr_main_startupinfo + 0xa0 [D:\a\_work\1\s\src\native\corehost\fxr\hostfxr.cpp:62], calling hostfxr!fx_muxer_t::execute [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp:555]
52 000000DA5B97F680 00007ffed450f3ad KERNELBASE!GetModuleHandleExW + 0xad, calling ntdll!LdrAddRefDll
53 000000DA5B97F710 00007ffed4818996 ucrtbase!fflush + 0x16, calling ucrtbase!is_stream_flushable_or_commitable
54 000000DA5B97F740 00007ff7e1a5f998 apphost!exe_start + 0x878 [D:\a\_work\1\s\src\native\corehost\corehost.cpp:240], calling ntdll!LdrpDispatchUserCallTarget
55 000000DA5B97F780 00007ff7e1a572bf apphost!trace::setup + 0x28f [D:\a\_work\1\s\src\native\corehost\hostmisc\trace.cpp:76], calling apphost!__security_check_cookie [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\gs\amd64\amdsecgs.asm:45]
56 000000DA5B97F910 00007ff7e1a5fda6 apphost!wmain + 0x146 [D:\a\_work\1\s\src\native\corehost\corehost.cpp:311], calling apphost!exe_start [D:\a\_work\1\s\src\native\corehost\corehost.cpp:101]
57 000000DA5B97F950 00007ff7e1a6100d apphost!__scrt_release_startup_lock + 0xd [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\utility\utility.cpp:161], calling apphost!__scrt_is_ucrt_dll_in_use [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\utility\ucrt_detection.c:22]
58 000000DA5B97F980 00007ff7e1a612e8 apphost!__scrt_common_main_seh + 0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288], calling apphost!wmain [D:\a\_work\1\s\src\native\corehost\corehost.cpp:290]
59 000000DA5B97F9C0 00007ffed5416fd4 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
60 000000DA5B97F9F0 00007ffed6f5cec1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget

                  【k】命令和【!dumpstack】命令,輸出的內容都差不多,但是也有一些區別,【!dumpstack】命令輸出的更詳細一點,每個呼叫棧都給出了地址。
                  如果我們想只輸出託管程式碼的呼叫棧,可以增加 -ee 命令開關。

 1 0:000> !dumpstack -ee
 2 OS Thread Id: 0x10d4 (0)
 3 Current frame: 
 4 Child-SP         RetAddr          Caller, Callee
 5 000000DA5B97E390 00007ffec2c37704 (MethodDesc 00007ffd9e17dff8 + 0x84 Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
 6 000000DA5B97E3F0 00007ffec2c376eb (MethodDesc 00007ffd9e17dff8 + 0x6b Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
 7 000000DA5B97E480 00007ffec2c3c9c0 (MethodDesc 00007ffd9e1a2cc0 + 0x60 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1<Byte>, Boolean, Int32 ByRef, Boolean))
 8 000000DA5B97E4E0 00007ffec2c3c8bb (MethodDesc 00007ffd9e1a2c90 + 0x2b System.ConsolePal+WindowsConsoleStream.Read(System.Span`1<Byte>))
 9 000000DA5B97E520 00007ffec2c3fb84 (MethodDesc 00007ffd9e1a2968 + 0x74 System.IO.ConsoleStream.Read(Byte[], Int32, Int32))
10 000000DA5B97E590 00007ffdfcc489c1 (MethodDesc 00007ffd9e1f6080 + 0x41 System.IO.StreamReader.ReadBuffer())
11 000000DA5B97E5E0 00007ffdfcc490a4 (MethodDesc 00007ffd9e1f60a8 + 0x64 System.IO.StreamReader.ReadLine())
12 000000DA5B97E690 00007ffec2c4005d (MethodDesc 00007ffd9e1ff650 + 0x3d System.IO.SyncTextReader.ReadLine())
13 000000DA5B97E6E0 00007ffec2c39319 (MethodDesc 00007ffd9e17a350 + 0x19 System.Console.ReadLine())
14 000000DA5B97E710 00007ffd9e0c19cf (MethodDesc 00007ffd9e1700c0 + 0x9f ExampleCore_3_1_9.Program.Main(System.String[]))
15 000000DA5B97EAF0 00007ffdfca71ae3 (MethodDesc 00007ffd9e14f460 + 0xa3 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**))
16 000000DA5B97EBF0 00007ffdfca71af0 (MethodDesc 00007ffd9e14f460 + 0xb0 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**))

        3.1.4、EEStack
            A、基礎知識
                如果想獲取程序中所有託管執行緒的呼叫棧,可以使用【!EEStack】命令,【!EEStack】命令會對程序中每個活躍的執行緒呼叫【!DumpStack】命令。也可以使用【~*e !dumpstack】,結果是一樣的。
                該命令有兩個命令開關,
                  -short 這個開關只輸出“感興趣”執行緒的呼叫棧。“感興趣”的執行緒是指:持有鎖的執行緒、被劫持以執行一個垃圾收集操作的執行緒或者是正在託管程式碼中執行的執行緒。
                  -EE 這個開關會直接傳遞給【!dumpstack】命令,只顯示託管程式碼呼叫棧。                
                
            B、眼見為實
                除錯原始碼:ExampleCore_3_1_9
                除錯任務:【!EEStack】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】,開啟偵錯程式。
                    

                    開啟偵錯程式,繼續使用【g】命令執行偵錯程式,直到偵錯程式輸出如圖:
                    

                    按組合鍵【ctrl+c】進入偵錯程式的中斷模式。我們需要切換到託管執行緒的上下文中,執行命令【~0s】。

1 0:003> ~0s
2 ntdll!NtDeviceIoControlFile+0x14:
3 00007ff8`f946d0c4 c3              ret

                    接下來,我們執行【!EEStack】命令,內容太多,省略了一些內容,不影響觀看。

 1 0:000> !EEStack
 2 ---------------------------------------------
 3 Thread   0
 4 Current frame: ntdll!NtDeviceIoControlFile + 0x14
 5 Child-SP         RetAddr          Caller, Callee
 6 000000462657E510 00007ff8f6917861 KERNELBASE!ConsoleCallServerGeneric + 0xe9, calling ntdll!NtDeviceIoControlFile
 7 000000462657E5E0 00007ff83f31bbb4 coreclr!PreStubWorker + 0x284 [D:\a\_work\1\s\src\coreclr\vm\prestub.cpp:2444], calling KERNEL32!SetLastErrorStub
 8 。。。。。。(省略了)
 9 000000462657FBB0 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
10 000000462657FBE0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
11 ---------------------------------------------
12 
13 Thread   6
14 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
15 Child-SP         RetAddr          Caller, Callee
16 0000004626E7F6C0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
17 0000004626E7F710 00007ff8f694b6db KERNELBASE!FlsSetValue + 0xb, calling ntdll!RtlFlsSetValue
18 。。。。。。()
19 0000004626E7FED0 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
20 0000004626E7FF00 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
21 ---------------------------------------------
22 
23 Thread   8
24 Current frame: coreclr!JIT_MonExit_Portable + 0xb3 [D:\a\_work\1\s\src\coreclr\vm\jithelpers.cpp:3996]
25 Child-SP         RetAddr          Caller, Callee
26 000000462717F200 00007ff891580070 (MethodDesc 00007ff7df9c23b8 + 0x50 System.IO.SyncTextReader.ReadLine()), calling 00007ff83f3380c0 (stub for System.Threading.Monitor.Exit(System.Object))
27 000000462717F250 00007ff891579319 (MethodDesc 00007ff7df92a350 + 0x19 System.Console.ReadLine())
28 。。。。。。(省略了)
29 000000462717F8A0 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
30 000000462717F8D0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
31 ---------------------------------------------
32 
33 Thread   9
34 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
35 Child-SP         RetAddr          Caller, Callee
36 000000462613F2C0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
37 000000462613F2F0 00007ff8f93f5ba1 ntdll!RtlpFreeHeapInternal + 0x491, calling ntdll!RtlpHpStackLoggingEnabled
38 。。。。。。(省略了)
39 000000462613FD70 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
40 ---------------------------------------------
41 
42 Thread  10
43 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
44 Child-SP         RetAddr          Caller, Callee
45 00000046272FE8F0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
46 00000046272FE910 00007ff83f35da2d coreclr!BucketTable::Add + 0x69 [D:\a\_work\1\s\src\coreclr\vm\virtualcallstub.cpp:3278], calling ntdll!LdrpDispatchUserCallTarget
47 。。。。。。(省略了)
48 00000046272FF770 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
49 00000046272FF7A0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
50 ---------------------------------------------
51 
52 Thread  11
53 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
54 Child-SP         RetAddr          Caller, Callee
55 000000462747E8B0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
56 000000462747E8D0 00007ff83f284f88 coreclr!CodeFragmentHeap::RealAllocAlignedMem + 0x180 [D:\a\_work\1\s\src\coreclr\vm\codeman.cpp:2150], calling ntdll!RtlLeaveCriticalSection
57 。。。。。。(省略了)
58 000000462747F730 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
59 000000462747F760 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
60 ---------------------------------------------
61 
62 Thread   1(這個執行緒是偵錯程式本身的,這個可以忽略,在 Windbg Preview 中是沒有的)
63 Current frame: ntdll!RtlpEnterCriticalSectionContended + 0xe2
64 Child-SP         RetAddr          Caller, Callee
65 00000046266FF290 00007ff8f93ffae2 ntdll!RtlEnterCriticalSection + 0x42, calling ntdll!RtlpEnterCriticalSectionContended
66 00000046266FF2C0 00007ff8f94c88b5 ntdll!RtlDebugAllocateHeap + 0xc5, calling ntdll!RtlEnterCriticalSection
67 00000046266FF320 00007ff8f93fd255 ntdll!RtlpAllocateHeap + 0xf5, calling ntdll!RtlDebugAllocateHeap
68 00000046266FF570 00007ff8f93fb44d ntdll!RtlpAllocateHeapInternal + 0xa2d, calling ntdll!RtlpAllocateHeap
69 00000046266FF680 00007ff8f9418269 ntdll!LdrpAllocateTls + 0x109, calling ntdll!RtlAllocateHeap
70 00000046266FF750 00007ff8f93e77a7 ntdll!LdrpInitializeThread + 0x6f, calling ntdll!LdrpAllocateTls
71 00000046266FF830 00007ff8f9445064 ntdll!LdrpInitialize + 0x408, calling ntdll!LdrpInitializeThread
72 00000046266FF8D0 00007ff8f9444c43 ntdll!LdrpInitialize + 0x3b, calling ntdll!LdrpInitialize
73 00000046266FF900 00007ff8f9444bee ntdll!LdrInitializeThunk + 0xe, calling ntdll!LdrpInitialize

                    這就是【!EEStack】命令的輸出,-short 開關加也不加,輸出的內容是一樣的。紅色部分是偵錯程式的,不用在意。執行緒 ID 不是託管執行緒的 ID,是偵錯程式自己標識的,它自己使用的,也就是 DBG 的值。
                    【!EEStack】命令會輸出程序中所有託管執行緒的詳細呼叫棧,而【!t】或者是【!Threads】命令也是輸出託管呼叫棧的簡單列表,當然,這個命令也會輸出死亡的執行緒,而【!EEStack】只會輸出活躍的執行緒,這就是區別。我們再看看【!t】的輸出,有對比就知道了。

 1 0:000> !Threads
 2 ThreadCount:      8
 3 UnstartedThread:  1
 4 BackgroundThread: 5
 5 PendingThread:    1
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     1330 000001DC85CE2820    2a020 Preemptive  000001DC8A40C0A8:000001DC8A40C638 000001DC85CD1090 -00001 MTA
11    6    2     1760 000001DC8783DDA0    2b220 Preemptive  0000000000000000:0000000000000000 000001DC85CD1090 -00001 MTA (Finalizer)
12    8    4     3c90 000001DC85CFD1A0  102b220 Cooperative 000001DC8A41F0C0:000001DC8A420FD0 000001DC85CD1090 -00001 MTA (Threadpool Worker)
13    9    5     1dec 0000021D1C7A63C0  302b220 Preemptive  000001DC8A40EA58:000001DC8A410678 000001DC85CD1090 -00001 MTA (Threadpool Worker)
14   10    6     35a8 0000021D1C7AAB70  302b220 Preemptive  000001DC8A4151F0:000001DC8A417030 000001DC85CD1090 -00001 MTA (Threadpool Worker)
15   11    7      4b4 0000021D1C7B1E60  302b220 Preemptive  000001DC8A411848:000001DC8A412FF0 000001DC85CD1090 -00001 MTA (Threadpool Worker)
16 XXXX    8        0 0000021D1C7AC2E0  1039820 Preemptive  0000000000000000:0000000000000000 000001DC85CD1090 -00001 Ukn (Threadpool Worker)
17    1    3     1d70 0000021D1C7B52D0     9600 Preemptive  0000000000000000:0000000000000000 000001DC85CD1090 -00001 Ukn
18 0:000>

                    DBG 值:XXXX 就是死亡的執行緒,其他內容輸出是一致的,內容很簡單,就不多數了。

                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】---【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_9.exe,進入到偵錯程式。繼續使用【g】命令執行偵錯程式,我們的控制檯程式輸出如下:
                    

                    此時,我們的偵錯程式也處於卡住的狀態,點選【break】按鈕,進入偵錯程式的中斷模式,開始我們的除錯了。
                    如果我們要檢視呼叫棧,必須切換到託管執行緒的上下文中,執行命令【~0s】。
                    我們直接執行【!EEStack】命令,它會輸出所有執行緒的呼叫棧,如果說【!t】或者說【!threads】是簡化版的,【!EEStack】就是詳情版的,內容如下。

 1 0:000> !eestack
 2 ---------------------------------------------
 3 Thread   0
 4 Current frame: ntdll!NtDeviceIoControlFile + 0x14
 5 Child-SP         RetAddr          Caller, Callee
 6 000000AFC917E780 00007ff8f6917861 KERNELBASE!ConsoleCallServerGeneric + 0xe9, calling ntdll!NtDeviceIoControlFile
 7 。。。。。。(省略了)
 9 000000AFC917FE20 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
10 000000AFC917FE50 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
11 ---------------------------------------------
12 
13 Thread   6
14 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
15 Child-SP         RetAddr          Caller, Callee
16 000000AFC9A7F5B0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
17 000000AFC9A7F600 00007ff8f694b6db KERNELBASE!FlsSetValue + 0xb, calling ntdll!RtlFlsSetValue
18 。。。。。。(省略了)
19 000000AFC9A7FDC0 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
20 000000AFC9A7FDF0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
21 ---------------------------------------------
22 
23 Thread   8
24 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
25 Child-SP         RetAddr          Caller, Callee
26 000000AFC9D7EA00 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
27 000000AFC9D7EA20 00007ff81efb4f88 coreclr!CodeFragmentHeap::RealAllocAlignedMem + 0x180 [D:\a\_work\1\s\src\coreclr\vm\codeman.cpp:2150], calling ntdll!RtlLeaveCriticalSection
28 。。。。。。(省略了)
29 000000AFC9D7F880 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
30 000000AFC9D7F8B0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
31 ---------------------------------------------
32 
33 Thread   9
34 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
35 Child-SP         RetAddr          Caller, Callee
36 000000AFC8CEED40 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
37 000000AFC8CEED70 00007ff8f93f5ba1 ntdll!RtlpFreeHeapInternal + 0x491, calling ntdll!RtlpHpStackLoggingEnabled
38 。。。。。。(省略了)
39 000000AFC8CEF760 00007ff81f0673be coreclr!ThreadNative::KickOffThread + 0x7e [D:\a\_work\1\s\src\coreclr\vm\comsynchronizable.cpp:230], calling coreclr!ManagedThreadBase_DispatchOuter [D:\a\_work\1\s\src\coreclr\vm\threads.cpp:7377]
40 000000AFC8CEF7C0 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
41 000000AFC8CEF7F0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
42 ---------------------------------------------
43 
44 Thread  10
45 Current frame: ntdll!NtWaitForMultipleObjects + 0x14
46 Child-SP         RetAddr          Caller, Callee
47 000000AFC9EFEEA0 00007ff8f6951d20 KERNELBASE!WaitForMultipleObjectsEx + 0xf0, calling ntdll!NtWaitForMultipleObjects
48 000000AFC9EFEEC0 00007ff81f08da2d coreclr!BucketTable::Add + 0x69 [D:\a\_work\1\s\src\coreclr\vm\virtualcallstub.cpp:3278], calling ntdll!LdrpDispatchUserCallTarget
49 。。。。。。(省略了)
50 000000AFC9EFFD20 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
51 000000AFC9EFFD50 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget
52 ---------------------------------------------
53 
54 Thread  11
55 Current frame: ntdll!NtReadFile + 0x14
56 Child-SP         RetAddr          Caller, Callee
57 000000AFCA07F260 00007ff8f6935783 KERNELBASE!ReadFile + 0x73, calling ntdll!NtReadFile
58 000000AFCA07F270 00007ff81f0f9da3 coreclr!NDirectImportThunk + 0x43 [D:\a\_work\1\s\src\coreclr\vm\amd64\AsmHelpers.asm:185], calling coreclr!NDirectImportWorker [D:\a\_work\1\s\src\coreclr\vm\dllimport.cpp:5834]
59 。。。。。。(省略了)
60 000000AFCA07FC80 00007ff8f9287344 KERNEL32!BaseThreadInitThunk + 0x14, calling ntdll!LdrpDispatchUserCallTarget
61 000000AFCA07FCB0 00007ff8f94226b1 ntdll!RtlUserThreadStart + 0x21, calling ntdll!LdrpDispatchUserCallTarget

                    這就是【!EEstack】命令的輸出,它輸出了執行緒為 0、6、8、9、10、11號的執行緒內容,當然這個編號不是託管執行緒的 ID 值,是偵錯程式 DBG 的值。我們在看看【!t】或者【!Threads】命令的輸出,大家一對比就知道了。

 1 0:000> !t
 2 ThreadCount:      7
 3 UnstartedThread:  0
 4 BackgroundThread: 5
 5 PendingThread:    0
 6 DeadThread:       1
 7 Hosted Runtime:   no
 8                                                                                                             Lock  
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3f1c 000001C39D8E9C30    2a020 Preemptive  000001C3A200C0A8:000001C3A200C638 000001c39d929390 -00001 MTA 
11    6    2     3d00 000001C39D996C40    2b220 Preemptive  0000000000000000:0000000000000000 000001c39d929390 -00001 MTA (Finalizer) 
12    8    4     2c38 000001C39D9062C0  302b220 Preemptive  000001C3A200CEB8:000001C3A200E658 000001c39d929390 -00001 MTA (Threadpool Worker) 
13    9    5     1ce4 000001C39F49B930  302b220 Preemptive  000001C3A200EA58:000001C3A2010678 000001c39d929390 -00001 MTA (Threadpool Worker) 
14   10    6     3eb0 00000204344A3A80  302b220 Preemptive  000001C3A20151F0:000001C3A2017030 000001c39d929390 -00001 MTA (Threadpool Worker) 
15   11    7     3c54 00000204344A69E0  102b220 Preemptive  000001C3A201F0C0:000001C3A2020FD0 000001c39d929390 -00001 MTA (Threadpool Worker) 
16 XXXX    8        0 00000204344A61A0  1039820 Preemptive  0000000000000000:0000000000000000 000001c39d929390 -00001 Ukn (Threadpool Worker) 

                    這裡還是有一點區別的,【!t】命令還輸出了一個死亡的執行緒,就是 DBG 值:XXXX 的執行緒,這個執行緒在【!EEStack】命令是沒有輸出的。
                    -short 這個命令開關就是預設值,加上和不加都是一個效果。也就是說【!EEStack】和【!EEStack -short】命令的輸出是一樣的。
                    如果我們想輸出所有執行緒的託管執行緒的呼叫棧,可以使用【!EEStack -ee|EE】命令。

 1 0:000> !EEStack -ee
 2 ---------------------------------------------
 3 Thread   0
 4 Current frame: 
 5 Child-SP         RetAddr          Caller, Callee
 6 000000AFC917E980 00007ff81e086370 (MethodDesc 00007ff7bf674ed0 + 0x10 System.Runtime.InteropServices.Marshal.SetLastSystemError(Int32))
 7 000000AFC917E9B0 00007ff891727893 (MethodDesc 00007ff7bf64e350 + 0x83 Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef))
 8 000000AFC917EA08 00007ff89172787a (MethodDesc 00007ff7bf64e350 + 0x6a Interop+Kernel32.ReadConsoleInput(IntPtr, INPUT_RECORD ByRef, Int32, Int32 ByRef))
 9 000000AFC917EAA0 00007ff89172aa0a (MethodDesc 00007ff7bf64b590 + 0xaa System.ConsolePal.ReadKey(Boolean))
10 000000AFC917EAD0 00007ff7bf591ba9 (MethodDesc 00007ff7bf6400d8 + 0x1b9 ExampleCore_3_1_9.Program.Test(Int32))
11 000000AFC917EB60 00007ff7bf5919d4 (MethodDesc 00007ff7bf6400c0 + 0xa4 ExampleCore_3_1_9.Program.Main(System.String[]))
12 000000AFC917EF50 00007ff81df31ae3 (MethodDesc 00007ff7bf61f460 + 0xa3 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**))
13 000000AFC917F050 00007ff81df31af0 (MethodDesc 00007ff7bf61f460 + 0xb0 System.Environment.InitializeCommandLineArgs(Char*, Int32, Char**))
14 ---------------------------------------------
15 Thread   6
16 Current frame: 
17 Child-SP         RetAddr          Caller, Callee
18 ---------------------------------------------
19 Thread   8
20 Current frame: 
21 Child-SP         RetAddr          Caller, Callee
22 000000AFC9D7EAE0 00007ff81e08634c (MethodDesc 00007ff7bf674eb8 + 0x1c System.Runtime.InteropServices.Marshal.GetLastSystemError())
23 000000AFC9D7EB10 00007ff891727da7 (MethodDesc 00007ff7bf64e460 + 0xa7 Interop+Kernel32.WriteFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
24 000000AFC9D7EB70 00007ff891727d6b (MethodDesc 00007ff7bf64e460 + 0x6b Interop+Kernel32.WriteFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
25 000000AFC9D7EC00 00007ff89172ca7f (MethodDesc 00007ff7bf672f68 + 0x4f System.ConsolePal+WindowsConsoleStream.WriteFileNative(IntPtr, System.ReadOnlySpan`1<Byte>, Boolean))
26 000000AFC9D7EC60 00007ff89172c90b (MethodDesc 00007ff7bf672f30 + 0x1b System.ConsolePal+WindowsConsoleStream.Write(System.ReadOnlySpan`1<Byte>))
27 000000AFC9D7EC90 00007ff81e10c6be (MethodDesc 00007ff7bf678cf8 + 0x17e System.IO.StreamWriter.Flush(Boolean, Boolean))
28 000000AFC9D7F1D0 00007ff891729bba (MethodDesc 00007ff7bf64a6f8 + 0x6a System.Console.<get_In>g__EnsureInitialized|14_0())
29 000000AFC9D7F1E0 00007ff891730042 (MethodDesc 00007ff7bf6e23b8 + 0x22 System.IO.SyncTextReader.ReadLine())
30 000000AFC9D7F200 00007ff891727fca (MethodDesc 00007ff7bf649cd8 + 0xa System.Console.get_In())
31 000000AFC9D7F230 00007ff891729319 (MethodDesc 00007ff7bf64a350 + 0x19 System.Console.ReadLine())
32 000000AFC9D7F260 00007ff7bf592600 (MethodDesc 00007ff7bf6400f0 + 0xc0 ExampleCore_3_1_9.Program.Run1())
33 000000AFC9D7F2F0 00007ff81e026502 (MethodDesc 00007ff7bf69e3f0 + 0x42 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object))
34 000000AFC9D7F340 00007ff81e040668 (MethodDesc 00007ff7bf67aa10 + 0x98 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread))
35 000000AFC9D7F3E0 00007ff81e02f400 (MethodDesc 00007ff7bf69f738 + 0x210 System.Threading.ThreadPoolWorkQueue.Dispatch())
36 000000AFC9D7F470 00007ff81e03c1d3 (MethodDesc 00007ff7bf6c4640 + 0x173 System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart())
37 ---------------------------------------------
38 Thread   9
39 Current frame: 
40 Child-SP         RetAddr          Caller, Callee
41 000000AFC8CEF310 00007ff81e020bd4 (MethodDesc 00007ff7bf6c86c8 + 0x64 System.Threading.WaitHandle.WaitOneNoCheck(Int32))
42 000000AFC8CEF370 00007ff81e038f36 (MethodDesc 00007ff7bf6c5268 + 0x106 System.Threading.PortableThreadPool+GateThread.GateThreadStart())
43 ---------------------------------------------
44 Thread  10
45 Current frame: 
46 Child-SP         RetAddr          Caller, Callee
47 000000AFC9EFEF80 00007ff81e08634c (MethodDesc 00007ff7bf674eb8 + 0x1c System.Runtime.InteropServices.Marshal.GetLastSystemError())
48 000000AFC9EFEFB0 00007ff891727da7 (MethodDesc 00007ff7bf64e460 + 0xa7 Interop+Kernel32.WriteFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
49 000000AFC9EFF670 00007ff891729bba (MethodDesc 00007ff7bf64a6f8 + 0x6a System.Console.<get_In>g__EnsureInitialized|14_0())
50 000000AFC9EFF680 00007ff891730042 (MethodDesc 00007ff7bf6e23b8 + 0x22 System.IO.SyncTextReader.ReadLine())
51 000000AFC9EFF6D0 00007ff891729319 (MethodDesc 00007ff7bf64a350 + 0x19 System.Console.ReadLine())
52 000000AFC9EFF700 00007ff7bf5924a0 (MethodDesc 00007ff7bf640108 + 0xc0 ExampleCore_3_1_9.Program.Run2())
53 000000AFC9EFF790 00007ff81e026502 (MethodDesc 00007ff7bf69e3f0 + 0x42 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object))
54 000000AFC9EFF7E0 00007ff81e040668 (MethodDesc 00007ff7bf67aa10 + 0x98 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread))
55 000000AFC9EFF880 00007ff81e02f400 (MethodDesc 00007ff7bf69f738 + 0x210 System.Threading.ThreadPoolWorkQueue.Dispatch())
56 000000AFC9EFF910 00007ff81e03c1d3 (MethodDesc 00007ff7bf6c4640 + 0x173 System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart())
57 ---------------------------------------------
58 Thread  11
59 Current frame: 
60 Child-SP         RetAddr          Caller, Callee
61 000000AFCA07F2E0 00007ff891727704 (MethodDesc 00007ff7bf64e320 + 0x84 Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
62 000000AFCA07F340 00007ff8917276eb (MethodDesc 00007ff7bf64e320 + 0x6b Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr))
63 000000AFCA07F3D0 00007ff89172c9c0 (MethodDesc 00007ff7bf672f50 + 0x60 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1<Byte>, Boolean, Int32 ByRef, Boolean))
64 000000AFCA07F430 00007ff89172c8bb (MethodDesc 00007ff7bf672f20 + 0x2b System.ConsolePal+WindowsConsoleStream.Read(System.Span`1<Byte>))
65 000000AFCA07F470 00007ff89172fb84 (MethodDesc 00007ff7bf672bf8 + 0x74 System.IO.ConsoleStream.Read(Byte[], Int32, Int32))
66 000000AFCA07F4E0 00007ff81e1089c1 (MethodDesc 00007ff7bf6e0308 + 0x41 System.IO.StreamReader.ReadBuffer())
67 000000AFCA07F530 00007ff81e1090a4 (MethodDesc 00007ff7bf6e0330 + 0x64 System.IO.StreamReader.ReadLine())
68 000000AFCA07F5E0 00007ff89173005d (MethodDesc 00007ff7bf6e23b8 + 0x3d System.IO.SyncTextReader.ReadLine())
69 000000AFCA07F630 00007ff891729319 (MethodDesc 00007ff7bf64a350 + 0x19 System.Console.ReadLine())
70 000000AFCA07F660 00007ff7bf592760 (MethodDesc 00007ff7bf640120 + 0xc0 ExampleCore_3_1_9.Program.Run3())
71 000000AFCA07F6F0 00007ff81e026502 (MethodDesc 00007ff7bf69e3f0 + 0x42 System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(System.Threading.Thread, System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object))
72 000000AFCA07F740 00007ff81e040668 (MethodDesc 00007ff7bf67aa10 + 0x98 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef, System.Threading.Thread))
73 000000AFCA07F7A0 00007ff81e040563 (MethodDesc 00007ff7bf67a9e0 + 0x43 System.Threading.Tasks.Task.ExecuteEntryUnsafe(System.Threading.Thread))
74 000000AFCA07F7E0 00007ff81e02f400 (MethodDesc 00007ff7bf69f738 + 0x210 System.Threading.ThreadPoolWorkQueue.Dispatch())
75 000000AFCA07F870 00007ff81e03c1d3 (MethodDesc 00007ff7bf6c4640 + 0x173 System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart())

        3.1.5、COMState
            A、基礎知識
                Com 提供了兩種套間模型:單執行緒套間(Single Threaded Apartment,STA)和多執行緒套間(Multiple Threaded Apartment,MTA)。當一個執行緒使用一個 COM 物件時,它必須告訴 COM 子系統使用哪種套間模型。在 .NET 互用性層時具體的套間模型對執行緒的初始化也有區別,我們必須清楚。當我們在除錯 COM 互用性問題時,找出執行緒的套間模型也是一個基本素質要求。
                這裡有兩個命令可以使用,分別是【!ComState】和【!t|Threads】命令。效果是一樣的,但是輸出的內容會有區別。

            B、眼見視為
                除錯原始碼:ExampleCore_3_1_9
                除錯任務:ComState 和 t 命令的使用
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】,開啟偵錯程式。
                    

                    開啟偵錯程式,繼續使用【g】命令執行偵錯程式,直到偵錯程式輸出如圖:
                    

                    按組合鍵【ctrl+c】進入偵錯程式的中斷模式。我們需要切換到託管執行緒的上下文中,執行命令【~0s】。

1 0:003> ~0s
2 ntdll!NtDeviceIoControlFile+0x14:
3 00007ff8`f946d0c4 c3              ret

                    我們直接執行【!ComState】命令,看看是什麼樣子。

 1 0:000> !comstate
 2       ID             TEB  APT    APTId CallerTID          Context
 3   0 3dec 0000001082382000 MTA        0         0 0000017EA7F427A8
 4   1 2f00 0000001082384000 Ukn
 5   2 38ec 0000001082386000 Ukn
 6   3 18e0 0000001082388000 Ukn
 7   4 3bd0 000000108238A000 Ukn
 8   5 39c4 000000108238C000 Ukn
 9   6 3c04 000000108238E000 MTA        0         0 0000017EA7F427A8
10   7 3f88 0000001082390000 MTA        0         0 0000017EA7F427A8
11   8  e1c 0000001082394000 MTA        0         0 0000017EA7F427A8
12   9 3f20 0000001082396000 MTA        0         0 0000017EA7F427A8
13  10 10f0 0000001082398000 MTA        0         0 0000017EA7F427A8
14  11 21b8 000000108239A000 MTA        0         0 0000017EA7F427A8
15  12 2664 000000108239C000 MTA        0         0 0000017EA7F427A8
16  13 1ff8 000000108239E000 Ukn
17  14 3f10 00000010823A0000 Ukn

                    ID 列表示執行緒的ID,TEB 列表示各個執行緒的執行緒環境塊,透過【!teb】命令和 TEB 指標獲取執行緒的擴充套件資訊(例如執行緒最近發生的錯誤和棧大小的限制)。
                    我們執行命令【!teb 0000001082382000】命令檢視 ID 是 3dec 執行緒的擴充套件資訊。

 1 0:000> !teb 0000001082382000
 2 TEB at 0000001082382000
 3     ExceptionList:        0000000000000000(沒有異常,所以是0)
 4     StackBase:            0000001082580000
 5     StackLimit:           000000108256f000(棧大小的限制)
 6     SubSystemTib:         0000000000000000
 7     FiberData:            0000000000001e00
 8     ArbitraryUserPointer: 0000000000000000
 9     Self:                 0000001082382000
10     EnvironmentPointer:   0000000000000000
11     ClientId:             000000000000219c . 0000000000003dec(執行緒ID)
12     RpcHandle:            0000000000000000
13     Tls Storage:          0000017ea7f2b460
14     PEB Address:          0000001082381000
15     LastErrorValue:       0
16     LastStatusValue:      c000007c
17     Count Owned Locks:    0
18     HardErrorMode:        0

                    APT 列表示的就是執行緒是在哪一種套間模型下初始化的,MTA表示多執行緒套間,STA 表示單執行緒套間,Ukn 通常表示執行緒此時還沒有初始化 COM 。各個列就簡介到此。我們在看看【!t】命令,也可以找到執行緒是哪種套間模型。

 1 0:000> !t
 2 ThreadCount:      8
 3 UnstartedThread:  0
 4 BackgroundThread: 7
 5 PendingThread:    0
 6 DeadThread:       0
 7 Hosted Runtime:   no
 8                                                                                                             Lock
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3dec 0000017EA7F32970    2a020 Preemptive  0000017EAC40C0A8:0000017EAC40C638 0000017EA7F21050 -00001 MTA
11    6    2     3c04 000001BF3E4FDDA0    2b220 Preemptive  0000000000000000:0000000000000000 0000017EA7F21050 -00001 MTA (Finalizer)
12    7    3     3f88 0000017EA7F3E290    2b220 Preemptive  0000000000000000:0000000000000000 0000017EA7F21050 -00001 MTA
13    8    4      e1c 0000017EA7F4C4D0  102b220 Preemptive  0000017EAC40D388:0000017EAC40E658 0000017EA7F21050 -00001 MTA (Threadpool Worker)
14    9    5     3f20 0000017EA7F4FAC0  302b220 Preemptive  0000017EAC40EA58:0000017EAC410678 0000017EA7F21050 -00001 MTA (Threadpool Worker)
15   10    6     10f0 000001BF3E91ACD0  102b220 Preemptive  0000017EAC41E180:0000017EAC41F060 0000017EA7F21050 -00001 MTA (Threadpool Worker)
16   11    7     21b8 000001BF3E91E5B0  302b220 Preemptive  0000017EAC411848:0000017EAC412FF0 0000017EA7F21050 -00001 MTA (Threadpool Worker)
17   12    8     2664 000001BF3E91BDE0  102b220 Preemptive  0000017EAC413330:0000017EAC415010 0000017EA7F21050 -00001 MTA (Threadpool Worker)

                    紅色標註的 Apt 列就是說明執行緒是屬於哪種套件模型。

                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】---【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_9.exe,進入到偵錯程式。繼續使用【g】命令執行偵錯程式,我們的控制檯程式輸出如下:
                    

                    此時,我們的偵錯程式也處於卡住的狀態,點選【break】按鈕,進入偵錯程式的中斷模式,開始我們的除錯了。
                    我們直接執行【!ComState】命令,看結果。

 1 0:012> !comstate
 2       ID             TEB  APT    APTId CallerTID          Context
 3   0 3d50 0000005FFA6A4000 MTA        0         0 000002204F75FF18
 4   1 1a3c 0000005FFA6A6000 Ukn
 5   2 25a4 0000005FFA6A8000 Ukn
 6   3 1344 0000005FFA6AA000 Ukn
 7   4 1d68 0000005FFA6AC000 Ukn
 8   5 1510 0000005FFA6AE000 MTA        0         0 000002204F75FF18
 9   6 1e74 0000005FFA6B0000 MTA        0         0 000002204F75FF18
10   7 3344 0000005FFA6B4000 MTA        0         0 000002204F75FF18
11   8 33b4 0000005FFA6B6000 MTA        0         0 000002204F75FF18
12   9 373c 0000005FFA6B8000 MTA        0         0 000002204F75FF18
13  10 3e60 0000005FFA6BA000 MTA        0         0 000002204F75FF18
14  11 1ffc 0000005FFA6BC000 MTA        0         0 000002204F75FF18
15  12 1d04 0000005FFA6BE000 Ukn

                    ID 列就是執行緒 ID,TEB 列就是執行緒的執行緒環境塊,可以使用【!teb】命令和 TEB 指標獲取執行緒的擴充套件資訊。APT 列就是指出執行緒是在哪一種套間模型中初始化的。MTA表示拖執行緒套間,STA 表示單執行緒套間,Ukn 表示執行緒還沒有初始化 COM。
                    接下來,我們測試一下【!teb】命令。我們檢視 ID=3d50 執行緒的擴充套件資訊。就可以執行命令【!teb 0000005FFA6A4000】,直接看結果。

 1 0:012> !teb 0000005FFA6A4000
 2 TEB at 0000005ffa6a4000
 3     ExceptionList:        0000000000000000
 4     StackBase:            0000005ffa5b0000
 5     StackLimit:           0000005ffa59f000
 6     SubSystemTib:         0000000000000000
 7     FiberData:            0000000000001e00
 8     ArbitraryUserPointer: 0000000000000000
 9     Self:                 0000005ffa6a4000
10     EnvironmentPointer:   0000000000000000
11     ClientId:             00000000000033c4 . 0000000000003d50
12     RpcHandle:            0000000000000000
13     Tls Storage:          000002204f7425c0
14     PEB Address:          0000005ffa6a3000
15     LastErrorValue:       0
16     LastStatusValue:      c000007c
17     Count Owned Locks:    0
18     HardErrorMode:        0

                    如果想檢視執行緒屬於哪種套間模型,也可以使用【!t】或者【!Threads】命令,輸出結果中的 Apt 列就是表示哪種套間模型的。

 1 0:012> !threads
 2 ThreadCount:      8
 3 UnstartedThread:  0
 4 BackgroundThread: 7
 5 PendingThread:    0
 6 DeadThread:       0
 7 Hosted Runtime:   no
 8                                                                                                             Lock  
 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
10    0    1     3d50 000002204F7499A0    2a020 Preemptive  0000022053C0C0A8:0000022053C0C638 000002204f788fa0 -00001 MTA 
11    5    2     1510 000002204F7F6C40    2b220 Preemptive  0000000000000000:0000000000000000 000002204f788fa0 -00001 MTA (Finalizer) 
12    6    3     1e74 000002204F756070    2b220 Preemptive  0000000000000000:0000000000000000 000002204f788fa0 -00001 MTA 
13    7    4     3344 000002204F768D20  302b220 Preemptive  0000022053C0D388:0000022053C0E658 000002204f788fa0 -00001 MTA (Threadpool Worker) 
14    8    5     33b4 00000260E6217740  302b220 Preemptive  0000022053C0EA58:0000022053C10678 000002204f788fa0 -00001 MTA (Threadpool Worker) 
15    9    6     373c 00000220512C6440  302b220 Preemptive  0000022053C10EE8:0000022053C10FD0 000002204f788fa0 -00001 MTA (Threadpool Worker) 
16   10    7     3e60 00000220512C8870  102b220 Preemptive  0000022053C1D0A0:0000022053C1F060 000002204f788fa0 -00001 MTA (Threadpool Worker) 
17   11    8     1ffc 00000260E621DFE0  102b220 Preemptive  0000022053C13330:0000022053C15010 000002204f788fa0 -00001 MTA (Threadpool Worker) 

                    標紅的就是 Apt 列,很簡單,就不多說了。


    3.2、程式碼審查
        3.2.1、反彙編程式碼
            A、基礎知識
                在我們除錯非託管程式碼的時候,可以使用【u|U】命令,將程式碼位元組流轉換為彙編指令。在託管程式碼除錯中,如果我們知道程式碼的地址,也可以使用【u】命令對程式碼進行反彙編。這個命令也有弊端,它對 CLR瞭解不深,所以不能給我太多的資訊。SOS 偵錯程式擴充套件給我們一個更好的用【!u|U】命令,u 字元不區分大小寫,由於 SOS 更瞭解 CLR 內部細節,因此【!u】命令會提供可讀性更強的資訊。

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:u 和 !u 命令的使用
                說明一下,在這裡用其他的程式都是可以的,只是檢視彙編程式碼,可以檢視非託管函式的、也可以檢視託管函式的彙編程式碼。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】,開啟偵錯程式。
                    我們剛進入偵錯程式,可以直接執行【k】命令。

1 0:000> k
2 Child-SP          RetAddr               Call Site
3 0000004f`6e17f150 00007ff8`f94a3bba     ntdll!LdrpDoDebuggerBreak+0x30
4 0000004f`6e17f190 00007ff8`f9444dbb     ntdll!LdrpInitializeProcess+0x1eda
5 0000004f`6e17f5b0 00007ff8`f9444c43     ntdll!LdrpInitialize+0x15f
6 0000004f`6e17f650 00007ff8`f9444bee     ntdll!LdrpInitialize+0x3b
7 0000004f`6e17f680 00000000`00000000     ntdll!LdrInitializeThunk+0xe

                    ntdll!LdrpDoDebuggerBreak 我們看看這個方法彙編程式碼,直接使用【u】命令。

 1 0:000> u 00007ff8`f94a3bba
 2 ntdll!LdrpInitializeProcess+0x1eda:
 3 00007ff8`f94a3bba e8cd9df8ff      call    ntdll!LdrpDropLastInProgressCount (00007ff8`f942d98c)
 4 00007ff8`f94a3bbf 488b052a840900  mov     rax,qword ptr [ntdll!Kernel32ThreadInitThunkFunction (00007ff8`f953bff0)]
 5 00007ff8`f94a3bc6 4885c0          test    rax,rax
 6 00007ff8`f94a3bc9 7437            je      ntdll!LdrpInitializeProcess+0x1f22 (00007ff8`f94a3c02)
 7 00007ff8`f94a3bcb 4533c0          xor     r8d,r8d
 8 00007ff8`f94a3bce 33d2            xor     edx,edx
 9 00007ff8`f94a3bd0 8d4a01          lea     ecx,[rdx+1]
10 00007ff8`f94a3bd3 ff1527140b00    call    qword ptr [ntdll!_guard_dispatch_icall_fptr (00007ff8`f9555000)]

                    這是非託管方法彙編程式碼的編譯過程,我們看看託管程式碼。繼續【g】執行偵錯程式。直到偵錯程式輸出如下:
                    

                    按【ctrl+c】組合鍵鍵入偵錯程式中斷除錯模式。我們執行命令【~0s】命令,切換到託管執行緒。

1 0:001> ~0s
2 ntdll!LdrpDispatchUserCallTarget+0x12:
3 00007ff8`f945c8d2 4c8bd0          mov     r10,rax

                    現在,我們要檢視我們的 Program.Main() 方法的彙編,分別執行【u】和【!u】命令,看看區別吧。

1 0:000> !clrstack
2 OS Thread Id: 0x3e6c (0)
3         Child SP               IP Call Site
4 0000004F6E17E4E8 00007ff8f945c8d2 [PrestubMethodFrame: 0000004f6e17e4e8] System.Text.DecoderDBCS.GetChars(Byte[], Int32, Int32, Char[], Int32, Boolean)
5 0000004F6E17E6C0 00007FF813B38A51 System.IO.StreamReader.ReadBuffer()
6 0000004F6E17E710 00007FF813B390A4 System.IO.StreamReader.ReadLine()
7 0000004F6E17E7C0 00007FF8E5E1005D System.IO.SyncTextReader.ReadLine()
8 0000004F6E17E810 00007FF8E5E09319 System.Console.ReadLine()
9 0000004F6E17E840 00007FF7C61A19DB ExampleCore_3_1_10.Program.Main(System.String[])

                    ExampleCore_3_1_10.Program.Main 方法的地址是 00007FF7C61A19DB ,有了地址,我們就可以執行命令。

 1 0:000> u 00007FF7C61A19DB
 2 00007ff7`c61a19db 488945b8        mov     qword ptr [rbp-48h],rax
 3 00007ff7`c61a19df 90              nop
 4 00007ff7`c61a19e0 90              nop
 5 00007ff7`c61a19e1 4883c470        add     rsp,70h
 6 00007ff7`c61a19e5 5d              pop     rbp
 7 00007ff7`c61a19e6 c3              ret
 8 00007ff7`c61a19e7 ba19050200      mov     edx,20519h
 9 00007ff7`c61a19ec 05d2015000      add     eax,5001D2h
10 
11 0:000> !u 00007FF7C61A19DB
12 Normal JIT generated code
13 ExampleCore_3_1_10.Program.Main(System.String[])
14 ilAddr is 0000016EA0AA2050 pImport is 000001C10A940290
15 Begin 00007FF7C61A1930, size b7
16 00007ff7`c61a1930 55              push    rbp
17 00007ff7`c61a1931 4883ec70        sub     rsp,70h
18 00007ff7`c61a1935 488d6c2470      lea     rbp,[rsp+70h]
19 00007ff7`c61a193a 33c0            xor     eax,eax
20 00007ff7`c61a193c 488945b8        mov     qword ptr [rbp-48h],rax
21 00007ff7`c61a1940 c5d857e4        vxorps  xmm4,xmm4,xmm4
22 00007ff7`c61a1944 c5f97f65c0      vmovdqa xmmword ptr [rbp-40h],xmm4
23 00007ff7`c61a1949 c5f97f65d0      vmovdqa xmmword ptr [rbp-30h],xmm4
24 00007ff7`c61a194e c5f97f65e0      vmovdqa xmmword ptr [rbp-20h],xmm4
25 00007ff7`c61a1953 c5f97f65f0      vmovdqa xmmword ptr [rbp-10h],xmm4
26 00007ff7`c61a1958 48894d10        mov     qword ptr [rbp+10h],rcx
27 00007ff7`c61a195c 833dc5c9080000  cmp     dword ptr [00007ff7`c622e328],0
28 00007ff7`c61a1963 7405            je      00007ff7`c61a196a
29 00007ff7`c61a1965 e816c1c95f      call    coreclr!JIT_DbgIsJustMyCode (00007ff8`25e3da80)
30 00007ff7`c61a196a 90              nop
31 00007ff7`c61a196b b90a000000      mov     ecx,0Ah
32 00007ff7`c61a1970 ba0b000000      mov     edx,0Bh
33 00007ff7`c61a1975 ff154d520a00    call    qword ptr [00007ff7`c6246bc8] (ExampleCore_3_1_10.Program.Sum(Int32, Int32), mdToken: 0000000006000002)
34 00007ff7`c61a197b 8945cc          mov     dword ptr [rbp-34h],eax
35 00007ff7`c61a197e 8b4dcc          mov     ecx,dword ptr [rbp-34h]
36 00007ff7`c61a1981 894dfc          mov     dword ptr [rbp-4],ecx
37 00007ff7`c61a1984 488d4dd0        lea     rcx,[rbp-30h]
38 00007ff7`c61a1988 ba04000000      mov     edx,4
39 00007ff7`c61a198d 41b801000000    mov     r8d,1
40 00007ff7`c61a1993 ff15173d0d00    call    qword ptr [00007ff7`c62756b0]
41 00007ff7`c61a1999 488d4dd0        lea     rcx,[rbp-30h]
42 00007ff7`c61a199d 48baa0047835af010000 mov rdx,1AF357804A0h ("sum=")
43 00007ff7`c61a19a7 ff15db3d0d00    call    qword ptr [00007ff7`c6275788]
44 00007ff7`c61a19ad 90              nop
45 00007ff7`c61a19ae 488d4dd0        lea     rcx,[rbp-30h]
46 00007ff7`c61a19b2 8b55fc          mov     edx,dword ptr [rbp-4]
47 00007ff7`c61a19b5 ff15ad3f0d00    call    qword ptr [00007ff7`c6275968]
48 00007ff7`c61a19bb 90              nop
49 00007ff7`c61a19bc 488d4dd0        lea     rcx,[rbp-30h]
50 00007ff7`c61a19c0 ff157a3d0d00    call    qword ptr [00007ff7`c6275740]
51 00007ff7`c61a19c6 488945c0        mov     qword ptr [rbp-40h],rax
52 00007ff7`c61a19ca 488b4dc0        mov     rcx,qword ptr [rbp-40h]
53 00007ff7`c61a19ce ff1574470d00    call    qword ptr [00007ff7`c6276148]
54 00007ff7`c61a19d4 90              nop
55 00007ff7`c61a19d5 ff151d460d00    call    qword ptr [00007ff7`c6275ff8]
56 >>> 00007ff7`c61a19db 488945b8        mov     qword ptr [rbp-48h],rax
57 00007ff7`c61a19df 90              nop
58 00007ff7`c61a19e0 90              nop
59 00007ff7`c61a19e1 4883c470        add     rsp,70h
60 00007ff7`c61a19e5 5d              pop     rbp
61 00007ff7`c61a19e6 c3              ret
62 0:000>

                    我們看到了【u】和【!u】命令的區別了,很簡單,就不多說了。
                    

                2)、Windbg Preview 除錯
                    我們編譯專案,開啟 Windbg,點選【檔案】----》【launch executable】附加程式,開啟偵錯程式的介面,程式已經處於中斷狀態。
                    這個時候,其實,我們不需要執行我們的程式,就可以直接使用【k】命令,檢視一下非託管的呼叫棧,然後從裡面隨便找一個函式,看看它的彙編程式碼。

1 0:000> k
2  # Child-SP          RetAddr               Call Site
3 00 000000f8`6fb7efa0 00007ff8`f94a3bba     ntdll!LdrpDoDebuggerBreak+0x30
4 01 000000f8`6fb7efe0 00007ff8`f9444dbb     ntdll!LdrpInitializeProcess+0x1eda
5 02 000000f8`6fb7f400 00007ff8`f9444c43     ntdll!LdrpInitialize+0x15f
6 03 000000f8`6fb7f4a0 00007ff8`f9444bee     ntdll!LdrpInitialize+0x3b
7 04 000000f8`6fb7f4d0 00000000`00000000     ntdll!LdrInitializeThunk+0xe

                    00007ff8`f94a3bba 我們檢視這個地址的彙編程式碼,可以使用【u 00007ff8`f94a3bba】指令。

 1 0:000> u 00007ff8`f94a3bba
 2 ntdll!LdrpInitializeProcess+0x1eda:
 3 00007ff8`f94a3bba e8cd9df8ff      call    ntdll!LdrpDropLastInProgressCount (00007ff8`f942d98c)
 4 00007ff8`f94a3bbf 488b052a840900  mov     rax,qword ptr [ntdll!Kernel32ThreadInitThunkFunction (00007ff8`f953bff0)]
 5 00007ff8`f94a3bc6 4885c0          test    rax,rax
 6 00007ff8`f94a3bc9 7437            je      ntdll!LdrpInitializeProcess+0x1f22 (00007ff8`f94a3c02)
 7 00007ff8`f94a3bcb 4533c0          xor     r8d,r8d
 8 00007ff8`f94a3bce 33d2            xor     edx,edx
 9 00007ff8`f94a3bd0 8d4a01          lea     ecx,[rdx+1]
10 00007ff8`f94a3bd3 ff1527140b00    call    qword ptr [ntdll!_guard_dispatch_icall_fptr (00007ff8`f9555000)]

                    我們也可以使用【g】命令執行我們的偵錯程式,控制檯輸出【sum=21】,偵錯程式卡住狀態,點選【break】按鈕進入除錯狀態。切換到託管主執行緒,執行【~0s】命令。
                    使用【k】命令,輸出呼叫棧。

 1 0:000> k
 2  # Child-SP          RetAddr               Call Site
 3 00 000000f8`6fb7e288 00007ff8`f6935783     ntdll!NtReadFile+0x14
 4 01 000000f8`6fb7e290 00007ff8`d3b67704     KERNELBASE!ReadFile+0x73
 5 02 000000f8`6fb7e310 00007ff8`d3b6c9c0     System_Console!Interop.Kernel32.ReadFile+0x84 [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412] 
 6 03 000000f8`6fb7e400 00007ff8`d3b6c8bb     System_Console!System.ConsolePal.WindowsConsoleStream.ReadFileNative+0x60 [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150] 
 7 04 000000f8`6fb7e460 00007ff8`d3b6fb84     System_Console!System.ConsolePal.WindowsConsoleStream.Read+0x2b [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108] 
 8 05 000000f8`6fb7e4a0 00007ff8`0fc189c1     System_Console!System.IO.ConsoleStream.Read+0x74 [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34] 
 9 06 000000f8`6fb7e510 00007ff8`0fc190a4     System_Private_CoreLib!System.IO.StreamReader.ReadBuffer+0x41 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613] 
10 07 000000f8`6fb7e560 00007ff8`d3b7005d     System_Private_CoreLib!System.IO.StreamReader.ReadLine+0x64 [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802] 
11 08 000000f8`6fb7e610 00007ff8`d3b69319     System_Console!System.IO.SyncTextReader.ReadLine+0x3d [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77] 
12 09 000000f8`6fb7e660 00007ff7`b10b19db     System_Console!System.Console.ReadLine+0x19 [/_/src/libraries/System.Console/src/System/Console.cs @ 752] 
13 0a 000000f8`6fb7e690 00007ff8`10c0a1a3     ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main+0xab [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9] 
14 0b 000000f8`6fb7e710 00007ff8`10b914c9     coreclr!CallDescrWorkerInternal+0x83 [D:\a\_work\1\s\src\coreclr\vm\amd64\CallDescrWorkerAMD64.asm @ 100] 
15 0c (Inline Function) --------`--------     coreclr!CallDescrWorkerWithHandler+0x56 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 67] 
16 0d 000000f8`6fb7e750 00007ff8`10ab75ac     coreclr!MethodDescCallSite::CallTargetWorker+0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 570] 
17 0e (Inline Function) --------`--------     coreclr!MethodDescCallSite::Call+0xb [D:\a\_work\1\s\src\coreclr\vm\callhelpers.h @ 458] 
18 0f 000000f8`6fb7e890 00007ff8`10ab6f7a     coreclr!RunMainInternal+0x11c [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1304] 
19 10 000000f8`6fb7e9b0 00007ff8`10ab6b17     coreclr!RunMain+0xd2 [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1375] 
20 11 000000f8`6fb7ea60 00007ff8`10ab7321     coreclr!Assembly::ExecuteMainMethod+0x1bf [D:\a\_work\1\s\src\coreclr\vm\assembly.cpp @ 1504] 
21 12 000000f8`6fb7ed30 00007ff8`10bc7768     coreclr!CorHost2::ExecuteAssembly+0x281 [D:\a\_work\1\s\src\coreclr\vm\corhost.cpp @ 349] 
22 13 000000f8`6fb7eea0 00007ff8`d3be2c36     coreclr!coreclr_execute_assembly+0xd8 [D:\a\_work\1\s\src\coreclr\dlls\mscoree\exports.cpp @ 504] 
23 14 (Inline Function) --------`--------     hostpolicy!coreclr_t::execute_assembly+0x2a [D:\a\_work\1\s\src\native\corehost\hostpolicy\coreclr.cpp @ 109] 
24 15 000000f8`6fb7ef40 00007ff8`d3be2f1c     hostpolicy!run_app_for_context+0x596 [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 256] 
25 16 000000f8`6fb7f0d0 00007ff8`d3be385a     hostpolicy!run_app+0x3c [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 285] 
26 17 000000f8`6fb7f110 00007ff8`d3c3b5c9     hostpolicy!corehost_main+0x15a [D:\a\_work\1\s\src\native\corehost\hostpolicy\hostpolicy.cpp @ 426] 
27 18 000000f8`6fb7f210 00007ff8`d3c3e066     hostfxr!execute_app+0x2e9 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 145] 
28 19 000000f8`6fb7f310 00007ff8`d3c402ec     hostfxr!`anonymous namespace'::read_config_and_execute+0xa6 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 532] 
29 1a 000000f8`6fb7f400 00007ff8`d3c3e644     hostfxr!fx_muxer_t::handle_exec_host_command+0x16c [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 1007] 
30 1b 000000f8`6fb7f4b0 00007ff8`d3c385a0     hostfxr!fx_muxer_t::execute+0x494 [D:\a\_work\1\s\src\native\corehost\fxr\fx_muxer.cpp @ 578] 
31 1c 000000f8`6fb7f5f0 00007ff7`bcdef998     hostfxr!hostfxr_main_startupinfo+0xa0 [D:\a\_work\1\s\src\native\corehost\fxr\hostfxr.cpp @ 62] 
32 1d 000000f8`6fb7f6f0 00007ff7`bcdefda6     apphost!exe_start+0x878 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 240] 
33 1e 000000f8`6fb7f8c0 00007ff7`bcdf12e8     apphost!wmain+0x146 [D:\a\_work\1\s\src\native\corehost\corehost.cpp @ 311] 
34 1f (Inline Function) --------`--------     apphost!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90] 
35 20 000000f8`6fb7f930 00007ff8`f9287344     apphost!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
36 21 000000f8`6fb7f970 00007ff8`f94226b1     KERNEL32!BaseThreadInitThunk+0x14
37 22 000000f8`6fb7f9a0 00000000`00000000     ntdll!RtlUserThreadStart+0x21

                    coreclr!CallDescrWorkerInternal 我們可以看看這個方法的反彙編。

 1 0:000> u 00007ff8`10b914c9
 2 coreclr!MethodDescCallSite::CallTargetWorker+0x2a1 [D:\a\_work\1\s\src\coreclr\vm\callhelpers.cpp @ 570]:
 3 00007ff8`10b914c9 488b7520        mov     rsi,qword ptr [rbp+20h]
 4 00007ff8`10b914cd 4885f6          test    rsi,rsi
 5 00007ff8`10b914d0 751d            jne     coreclr!MethodDescCallSite::CallTargetWorker+0x2c7 (00007ff8`10b914ef)
 6 00007ff8`10b914d2 488b4d58        mov     rcx,qword ptr [rbp+58h]
 7 00007ff8`10b914d6 4833cd          xor     rcx,rbp
 8 00007ff8`10b914d9 e832a70700      call    coreclr!__security_check_cookie (00007ff8`10c0bc10)
 9 00007ff8`10b914de 488d6568        lea     rsp,[rbp+68h]
10 00007ff8`10b914e2 415f            pop     r15

                    接下來,我們如果想檢視 Program.Main() 方法的彙編原始碼,我們先執行【!clrstack】命令。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3ad8 (0)
 3         Child SP               IP Call Site
 4 0000000B6B37E3A0 00007ff8f946d0a4 [InlinedCallFrame: 0000000b6b37e3a0] 
 5 0000000B6B37E3A0 00007ff8916176eb [InlinedCallFrame: 0000000b6b37e3a0] 
 6 0000000B6B37E370 00007ff8916176eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412]
 7 0000000B6B37E460 00007ff89161c9c0 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1, Boolean, Int32 ByRef, Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150]
 8 0000000B6B37E4C0 00007ff89161c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108]
 9 0000000B6B37E500 00007ff89161fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34]
10 0000000B6B37E570 00007ff8124389c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613]
11 0000000B6B37E5C0 00007ff8124390a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802]
12 0000000B6B37E670 00007ff89162005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
13 0000000B6B37E6C0 00007ff891619319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
14 0000000B6B37E6F0 00007ff7b38e19db ExampleCore_3_1_10.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9]

                    ExampleCore_3_1_10.Program.Main 方法的地址是 00007ff7b38e19db ,針對這個地址,執行命令【u 00007ff7b38e19db】命令。

 1 0:000> u 00007ff7b38e19db 
 2 ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main+0xab [E:\Visual Studio 2022\...\ExampleCore_3_1_10\Program.cs @ 9]:
 3 00007ff7`b38e19db 488945b8        mov     qword ptr [rbp-48h],rax
 4 00007ff7`b38e19df 90              nop
 5 00007ff7`b38e19e0 90              nop
 6 00007ff7`b38e19e1 4883c470        add     rsp,70h
 7 00007ff7`b38e19e5 5d              pop     rbp
 8 00007ff7`b38e19e6 c3              ret
 9 00007ff7`b38e19e7 ba19050200      mov     edx,20519h
10 00007ff7`b38e19ec 05d2015000      add     eax,5001D2h

                    【u】命令給出的內容太少,我們可以使用【!u|U】命令,獲取更多的資訊。

 1 0:000> !u 00007ff7b38e19db
 2 Normal JIT generated code
 3 ExampleCore_3_1_10.Program.Main(System.String[])
 4 ilAddr is 0000020334F32050 pImport is 000001E665DF3B40
 5 Begin 00007FF7B38E1930, size b7
 6 
 7 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 6:
 8 00007ff7`b38e1930 55              push    rbp
 9 00007ff7`b38e1931 4883ec70        sub     rsp,70h
10 00007ff7`b38e1935 488d6c2470      lea     rbp,[rsp+70h]
11 00007ff7`b38e193a 33c0            xor     eax,eax
12 00007ff7`b38e193c 488945b8        mov     qword ptr [rbp-48h],rax
13 00007ff7`b38e1940 c5d857e4        vxorps  xmm4,xmm4,xmm4
14 00007ff7`b38e1944 c5f97f65c0      vmovdqa xmmword ptr [rbp-40h],xmm4
15 00007ff7`b38e1949 c5f97f65d0      vmovdqa xmmword ptr [rbp-30h],xmm4
16 00007ff7`b38e194e c5f97f65e0      vmovdqa xmmword ptr [rbp-20h],xmm4
17 00007ff7`b38e1953 c5f97f65f0      vmovdqa xmmword ptr [rbp-10h],xmm4
18 00007ff7`b38e1958 48894d10        mov     qword ptr [rbp+10h],rcx
19 00007ff7`b38e195c 833dc5c9080000  cmp     dword ptr [00007ff7`b396e328],0
20 00007ff7`b38e1963 7405            je      ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main+0x3a (00007ff7`b38e196a)
21 00007ff7`b38e1965 e816c1c65f      call    coreclr!JIT_DbgIsJustMyCode (00007ff8`1354da80)
22 00007ff7`b38e196a 90              nop
23 
24 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 7:
25 00007ff7`b38e196b b90a000000      mov     ecx,0Ah
26 00007ff7`b38e1970 ba0b000000      mov     edx,0Bh
27 00007ff7`b38e1975 ff154d520a00    call    qword ptr [00007ff7`b3986bc8] (ExampleCore_3_1_10.Program.Sum(Int32, Int32), mdToken: 0000000006000002)
28 00007ff7`b38e197b 8945cc          mov     dword ptr [rbp-34h],eax
29 00007ff7`b38e197e 8b4dcc          mov     ecx,dword ptr [rbp-34h]
30 00007ff7`b38e1981 894dfc          mov     dword ptr [rbp-4],ecx
31 
32 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 8:
33 00007ff7`b38e1984 488d4dd0        lea     rcx,[rbp-30h]
34 00007ff7`b38e1988 ba04000000      mov     edx,4
35 00007ff7`b38e198d 41b801000000    mov     r8d,1
36 00007ff7`b38e1993 ff15173d0d00    call    qword ptr [00007ff7`b39b56b0]
37 00007ff7`b38e1999 488d4dd0        lea     rcx,[rbp-30h]
38 00007ff7`b38e199d 48baa004cdc943020000 mov rdx,243C9CD04A0h ("sum=")
39 00007ff7`b38e19a7 ff15db3d0d00    call    qword ptr [00007ff7`b39b5788]
40 00007ff7`b38e19ad 90              nop
41 00007ff7`b38e19ae 488d4dd0        lea     rcx,[rbp-30h]
42 00007ff7`b38e19b2 8b55fc          mov     edx,dword ptr [rbp-4]
43 00007ff7`b38e19b5 ff15ad3f0d00    call    qword ptr [00007ff7`b39b5968]
44 00007ff7`b38e19bb 90              nop
45 00007ff7`b38e19bc 488d4dd0        lea     rcx,[rbp-30h]
46 00007ff7`b38e19c0 ff157a3d0d00    call    qword ptr [00007ff7`b39b5740]
47 00007ff7`b38e19c6 488945c0        mov     qword ptr [rbp-40h],rax
48 00007ff7`b38e19ca 488b4dc0        mov     rcx,qword ptr [rbp-40h]
49 00007ff7`b38e19ce ff1574470d00    call    qword ptr [00007ff7`b39b6148]
50 00007ff7`b38e19d4 90              nop
51 
52 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9:
53 00007ff7`b38e19d5 ff151d460d00    call    qword ptr [00007ff7`b39b5ff8]
54 >>> 00007ff7`b38e19db 488945b8        mov     qword ptr [rbp-48h],rax
55 00007ff7`b38e19df 90              nop
56 
57 E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 10:
58 00007ff7`b38e19e0 90              nop
59 00007ff7`b38e19e1 4883c470        add     rsp,70h
60 00007ff7`b38e19e5 5d              pop     rbp
61 00007ff7`b38e19e6 c3              ret


        3.2.2、從程式碼的地址上獲取方法描述符
            A、基礎知識
                非託管的【u】命令可以反彙編程式碼,但是這個命令無法解析託管程式碼,SOS偵錯程式擴充套件的【!u】命令可以獲取託管程式碼的更詳細資訊。如果我們能獲取託管程式碼的地址,然後將這個地址轉換為方法描述符(MD),然後就可以使用【!DumpMD】命令獲取更詳細的資訊,【!IP2MD】這個命令就可以完成這個功能。
                語法格式:!IP2MD <Code Address>,這個命令不區分大小寫。
                如果想快速找出彙編程式碼位於哪個函式中,使用【!IP2MD】命令是很方便的。
                這是一種方法,要想查詢方法描述符,還有一個命令可以使用,它就是【!name2ee】,該命令的格式:Name2EE<module name>!<type or method name> 或者 Name2EE (name2ee) <module name><type or method name>。此命令支援 <module>!<type> 的 Windows 偵錯程式語法。 型別必須是完全限定的。

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:IP2MD 命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】,開啟偵錯程式視窗。
                    繼續使用【g】命令執行偵錯程式,知道偵錯程式輸出如圖:
                    

                    按組合鍵【ctrl+c】進入偵錯程式中斷模式,由於我們是手動中斷,當前執行緒是偵錯程式的執行緒,我們需要切換到託管執行緒上,執行命令【~0s】。

                    如圖:
                    

                    使用命令【!clrstack】檢視一下託管執行緒的呼叫棧,找到 Program.Main() 方法的 IP 地址。

 1 0:000> !ClrStack
 2 OS Thread Id: 0x14fc (0)
 3         Child SP               IP Call Site
 4 000000586F7EDF98 00007ff83cf4de30 [ExternalMethodFrame: 000000586f7edf98]
 5 000000586F7EE570 00007FF8F3BDF269 System.Text.DecoderDBCS.GetChars(Byte[], Int32, Int32, Char[], Int32, Boolean)
 6 000000586F7EE600 00007FF83C618A51 System.IO.StreamReader.ReadBuffer()
 7 000000586F7EE650 00007FF83C6190A4 System.IO.StreamReader.ReadLine()
 8 000000586F7EE700 00007FF8F3BE005D System.IO.SyncTextReader.ReadLine()
 9 000000586F7EE750 00007FF8F3BD9319 System.Console.ReadLine()
10 000000586F7EE780 00007FF7DD4719DB ExampleCore_3_1_10.Program.Main(System.String[])

                    ExampleCore_3_1_10.Program.Main 就是我們要找的方法,它的地址就是 IP 列的值:00007FF7DD4719DB ,有了地址,我們使用【!IP2MD 00007FF7DD4719DB】命令找到 Main() 方法的方法描述符。

 1 0:000> !IP2MD 00007FF7DD4719DB
 2 MethodDesc:   00007ff7dd5200c0
 3 Method Name:          ExampleCore_3_1_10.Program.Main(System.String[])
 4 Class:                00007ff7dd50fb20
 5 MethodTable:          00007ff7dd520100
 6 mdToken:              0000000006000001
 7 Module:               00007ff7dd4fe0a0
 8 IsJitted:             yes
 9 Current CodeAddr:     00007ff7dd471930
10 Version History:
11   ILCodeVersion:      0000000000000000
12   ReJIT ID:           0
13   IL Addr:            000001e1ebfd2050
14      CodeAddr:           00007ff7dd471930  (MinOptJitted)
15      NativeCodeVersion:  0000000000000000

                    很簡單,我們就知道了 Main() 方法的方法描述符,就是 MethodDesc: 00007ff7dd5200c0 。我們也可以使用【!Name2ee】命令透過名稱查詢制定方法的方法描述符,執行命令【!Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main】。

1 0:000> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ff7dd4fe0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ff7dd5200c0
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ff7dd471930

                    MethodDesc: 00007ff7dd5200c0 這就是我們找到的方法描述符,兩種方法找到的結果是一樣的,很簡單,話不多說了。
                    
                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出 sum=21 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式,由於我們是手動中斷,當前執行緒是偵錯程式的執行緒,所以需要切換到託管執行緒,執行命令【~0s】。

1 0:001> ~0s
2 ntdll!NtReadFile+0x14:
3 00007ff9`1134d0a4 c3              ret

                    執行命令後,提示符就是 0:000>,說明切換到了。繼續使用【!ClrStack】命令檢視託管執行緒的呼叫棧。

 1 0:000> !ClrStack
 2 OS Thread Id: 0xfbc (0)
 3         Child SP               IP Call Site
 4 000000A01F57E310 00007ff91134d0a4 [InlinedCallFrame: 000000a01f57e310] 
 5 000000A01F57E310 00007ff835a776eb [InlinedCallFrame: 000000a01f57e310] 
 6 000000A01F57E2E0 00007ff835a776eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412]
 7 000000A01F57E3D0 00007ff835a7c9c0 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1, Boolean, Int32 ByRef, Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150]
 8 000000A01F57E430 00007ff835a7c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108]
 9 000000A01F57E470 00007ff835a7fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34]
10 000000A01F57E4E0 00007ff8360689c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613]
11 000000A01F57E530 00007ff8360690a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802]
12 000000A01F57E5E0 00007ff835a8005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
13 000000A01F57E630 00007ff835a79319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
14 000000A01F57E660 00007ff7d75119db ExampleCore_3_1_10.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9]

                    ExampleCore_3_1_10.Program.Main 這就是我們的主方法,它的地址是 00007ff7d75119db ,有了地址,我們就可以使用【!IP2MD】命令找到 Main 方法的方法描述符了。
                    執行命令【!IP2MD 00007ff7d75119db】。

 1 0:000> !IP2MD 00007ff7d75119db
 2 MethodDesc:   00007ff7d75c00c0
 3 Method Name:          ExampleCore_3_1_10.Program.Main(System.String[])
 4 Class:                00007ff7d75afb20
 5 MethodTable:          00007ff7d75c0100
 6 mdToken:              0000000006000001
 7 Module:               00007ff7d759e0a0
 8 IsJitted:             yes
 9 Current CodeAddr:     00007ff7d7511930
10 Version History:
11   ILCodeVersion:      0000000000000000
12   ReJIT ID:           0
13   IL Addr:            000001a4549d2050
14      CodeAddr:           00007ff7d7511930  (MinOptJitted)
15      NativeCodeVersion:  0000000000000000
16 Source file:  E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9

                MethodDesc: 00007ff7d75c00c0 紅色標註的就是方法描述符的地址。
                除了以上方法,我們也可以使用【!name2ee】命令達到同樣的效果。

1 0:000> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ff7d759e0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ff7d75c00c0
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ff7d7511930

                MethodDesc: 00007ff7d75c00c0 這也是找到方法描述符的一種方法。

        3.2.3、顯示中間語言指令
            A、基礎知識
                .Net 程式碼由三種形態:機器程式碼、IL程式碼、C#程式碼,我們可以直接檢視 IL 程式碼,當然,檢視 IL 程式碼的方法也有很多種,SOS偵錯程式擴充套件提供了一個叫 【!dumpil】 的命令用來將託管函式的彙編指令轉成可讀的 IL 程式碼,當然,我們也可以使用 ILSpy 或者 DnSpy 等反編譯工具檢視。我推薦 ILSpy 或者 DnSpy 工具,使用更方便,可讀性更強。
                這裡我們主要介紹命令的用法,【!Dumpil】命令是以方法的方法描述符為引數,所以在使用【!dumpil】命令之前,我們必須找到方法的方法描述,前一節,我們說了,有兩種方法可以找到方法的方法描述符,第一個種就是使用【!IP2MD】命令,第二種就是使用【!Name2EE】命令。有了方法描述符的地址,我們就可以直接使用【!dumpil】命令了。
            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:【!Dumpil】命令的使用
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】,開啟偵錯程式視窗。
                    繼續使用【g】命令執行偵錯程式,知道偵錯程式輸出如圖:
                    

                    按組合鍵【ctrl+c】進入偵錯程式中斷模式,由於我們是手動中斷,當前執行緒是偵錯程式的執行緒,我們需要切換到託管執行緒上,執行命令【~0s】。

                    如圖:
                    

                    使用命令【!clrstack】檢視一下託管執行緒的呼叫棧,找到 Program.Main() 方法的 IP 地址。

 1 0:000> !clrstack
 2 OS Thread Id: 0x14fc (0)
 3         Child SP               IP Call Site
 4 000000586F7EDF98 00007ff83cf4de30 [ExternalMethodFrame: 000000586f7edf98]
 5 000000586F7EE570 00007FF8F3BDF269 System.Text.DecoderDBCS.GetChars(Byte[], Int32, Int32, Char[], Int32, Boolean)
 6 000000586F7EE600 00007FF83C618A51 System.IO.StreamReader.ReadBuffer()
 7 000000586F7EE650 00007FF83C6190A4 System.IO.StreamReader.ReadLine()
 8 000000586F7EE700 00007FF8F3BE005D System.IO.SyncTextReader.ReadLine()
 9 000000586F7EE750 00007FF8F3BD9319 System.Console.ReadLine()
10 000000586F7EE780 00007FF7DD4719DB ExampleCore_3_1_10.Program.Main(System.String[])

                    ExampleCore_3_1_10.Program.Main 方法的地址就是 00007FF7DD4719DB ,有了這個地址,就可以根據這個地址獲取方法的描述符了。
                    執行命令【!ip2md 00007FF7DD4719DB】。

 1 0:000> !ip2md 00007FF7DD4719DB
 2 MethodDesc:   00007ff7dd5200c0
 3 Method Name:          ExampleCore_3_1_10.Program.Main(System.String[])
 4 Class:                00007ff7dd50fb20
 5 MethodTable:          00007ff7dd520100
 6 mdToken:              0000000006000001
 7 Module:               00007ff7dd4fe0a0
 8 IsJitted:             yes
 9 Current CodeAddr:     00007ff7dd471930
10 Version History:
11   ILCodeVersion:      0000000000000000
12   ReJIT ID:           0
13   IL Addr:            000001e1ebfd2050
14      CodeAddr:           00007ff7dd471930  (MinOptJitted)
15      NativeCodeVersion:  0000000000000000

                    也可以透過【!Name2EE】命令獲取方法描述符。

1 0:000> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ff7dd4fe0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ff7dd5200c0
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ff7dd471930

                    這個兩個命令獲取同樣的方法描述符。繼續執行【!DumpIL 00007ff7dd5200c0】獲取 IL 程式碼。

 1 0:000> !DumpIL 00007ff7dd5200c0
 2 ilAddr is 000001E1EBFD2050 pImport is 0000018FDE7845F0
 3 ilAddr = 000001E1EBFD2050
 4 IL_0000: nop
 5 IL_0001: ldc.i4.s 10
 6 IL_0003: ldc.i4.s 11
 7 IL_0005: call int32 ExampleCore_3_1_10.Program::Sum(int32,int32)
 8 IL_000a: stloc.0
 9 IL_000b: ldloca.s VAR OR ARG 1
10 IL_000d: ldc.i4.4
11 IL_000e: ldc.i4.1
12 IL_000f: call void System.Runtime.CompilerServices.DefaultInterpolat::.ctor(int32,int32)
13 IL_0014: ldloca.s VAR OR ARG 1
14 IL_0016: ldstr "sum="
15 IL_001b: call void System.Runtime.CompilerServices.DefaultInterpolat::AppendLiteral(string)
16 IL_0020: nop
17 IL_0021: ldloca.s VAR OR ARG 1
18 IL_0023: ldloc.0
19 IL_0024: call <unknown token type 2b000000>
20 IL_0029: nop
21 IL_002a: ldloca.s VAR OR ARG 1
22 IL_002c: call string System.Runtime.CompilerServices.DefaultInterpolat::ToStringAndClear()
23 IL_0031: call void System.Console::WriteLine(string)
24 IL_0036: nop
25 IL_0037: call string System.Console::ReadLine()
26 IL_003c: pop
27 IL_003d: ret

                    內容很簡單,就不多說了。

                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出 sum=21 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式,由於我們是手動中斷,當前執行緒是偵錯程式的執行緒,所以需要切換到託管執行緒,執行命令【~0s】。

1 0:006> ~0s
2 ntdll!NtReadFile+0x14:
3 00007ff9`1134d0a4 c3              ret

                    我們先執行【!ClrStack】命令檢視一下託管呼叫棧,查詢一下 Program.Main() 方法的 IP 地址。

 1 0:000> !ClrStack
 2 OS Thread Id: 0x1b4c (0)
 3         Child SP               IP Call Site
 4 000000FDCAD7E7A0 00007ff91134d0a4 [InlinedCallFrame: 000000fdcad7e7a0] 
 5 000000FDCAD7E7A0 00007ff8d9a176eb [InlinedCallFrame: 000000fdcad7e7a0] 
 6 000000FDCAD7E770 00007ff8d9a176eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412]
 7 000000FDCAD7E860 00007ff8d9a1c9c0 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1, Boolean, Int32 ByRef, Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150]
 8 000000FDCAD7E8C0 00007ff8d9a1c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108]
 9 000000FDCAD7E900 00007ff8d9a1fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34]
10 000000FDCAD7E970 00007ff834d589c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613]
11 000000FDCAD7E9C0 00007ff834d590a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802]
12 000000FDCAD7EA70 00007ff8d9a2005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
13 000000FDCAD7EAC0 00007ff8d9a19319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
14 000000FDCAD7EAF0 00007ff7dcf019db ExampleCore_3_1_10.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9]

                    ExampleCore_3_1_10.Program.Main 方法的 IP 地址是 00007ff7dcf019db ,有了這個地址,我們先用第一種方式獲取方法描述符,執行命令【!IP2MD 00007ff7dcf019db

 1 0:000> !IP2MD 00007ff7dcf019db
 2 MethodDesc:   00007ff7dcfb00c0
 3 Method Name:          ExampleCore_3_1_10.Program.Main(System.String[])
 4 Class:                00007ff7dcf9fb20
 5 MethodTable:          00007ff7dcfb0100
 6 mdToken:              0000000006000001
 7 Module:               00007ff7dcf8e0a0
 8 IsJitted:             yes
 9 Current CodeAddr:     00007ff7dcf01930
10 Version History:
11   ILCodeVersion:      0000000000000000
12   ReJIT ID:           0
13   IL Addr:            000002dddfa32050
14      CodeAddr:           00007ff7dcf01930  (MinOptJitted)
15      NativeCodeVersion:  0000000000000000
16 Source file:  E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\Program.cs @ 9

                  MethodDesc: 00007ff7dcfb00c0 這就是方法描述符的地址,我們在使用第二種方式獲取方法描述符,使用【!Name2EE】命令。

1 0:000> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ff7dcf8e0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ff7dcfb00c0
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ff7dcf01930

                  MethodDesc: 00007ff7dcfb00c0 這也是我們找到的方法描述符,他們的結果都是一樣的。有了方法描述符,我們就可以使用【!DumpIL】命令獲取 IL 程式碼了。執行命令【!DumpIL 00007ff7dcfb00c0】。

 1 0:000> !DumpIL 00007ff7dcfb00c0
 2 ilAddr is 000002DDDFA32050 pImport is 00000230A1AFADC0
 3 ilAddr = 000002DDDFA32050
 4 IL_0000: nop 
 5 IL_0001: ldc.i4.s 10
 6 IL_0003: ldc.i4.s 11
 7 IL_0005: call int32 ExampleCore_3_1_10.Program::Sum(int32,int32)
 8 IL_000a: stloc.0 
 9 IL_000b: ldloca.s VAR OR ARG 1
10 IL_000d: ldc.i4.4 
11 IL_000e: ldc.i4.1 
12 IL_000f: call void System.Runtime.CompilerServices.DefaultInterpolat::.ctor(int32,int32)
13 IL_0014: ldloca.s VAR OR ARG 1
14 IL_0016: ldstr "sum="
15 IL_001b: call void System.Runtime.CompilerServices.DefaultInterpolat::AppendLiteral(string)
16 IL_0020: nop 
17 IL_0021: ldloca.s VAR OR ARG 1
18 IL_0023: ldloc.0 
19 IL_0024: call <unknown token type 2b000000>
20 IL_0029: nop 
21 IL_002a: ldloca.s VAR OR ARG 1
22 IL_002c: call string System.Runtime.CompilerServices.DefaultInterpolat::ToStringAndClear()
23 IL_0031: call void System.Console::WriteLine(string)
24 IL_0036: nop 
25 IL_0037: call string System.Console::ReadLine()
26 IL_003c: pop 
27 IL_003d: ret 

                  很簡單,不多說了。

    3.3、CLR 內部指令
        3.3.1、獲得 CLR 的版本
            A、基礎知識
                我們可以使用【!EEVersion】命令獲取當前除錯回話 CLR 的版本,該命令可以輸出使用 CLR 的版本,SOS 偵錯程式擴充套件的版本,以及 CLR 當前執行的模式(是伺服器模式還是工作站模式)。

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:【!EEVersion】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】命令,開啟偵錯程式視窗。
                    繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 sum=21。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。
                    此時,我們就可以直接執行【!EEVersion】命令。

1 0:002> !EEVersion
2 8.0.224.6711 free
3 8,0,224,6711 @Commit: 1381d5ebd2ab1f292848d5b19b80cf71ac332508
4 Workstation mode
5 SOS Version: 6.0.5.7301 retail build

                    效果如圖:
                    


                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出 sum=21 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。
                    直接執行命令【!EEVersion】。

1 0:008> !EEVersion
2 8.0.224.6711 free(CLR 版本)
3 8,0,224,6711 @Commit: 1381d5ebd2ab1f292848d5b19b80cf71ac332508
4 Workstation mode(工作站模式)
5 SOS Version: 8.0.10.10501 retail build(SOS 偵錯程式擴充套件的版本)

                    很簡單,話不多說。

        3.3.2、根據名稱找到方法的描述符
            A、基礎知識
                當我們知道一個完整的方法名的情況下,可以透過【!Name2ee】命令查詢該方法的描述符資訊,方法的名稱必須是完整的限定名。這個命令不光可以獲取方法的詳細資訊,也可以獲取型別的詳細資訊,只不過引數是型別的完整限定名。

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:【!Name2ee】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】命令,開啟偵錯程式視窗。
                    繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 sum=21。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。
                    此時,我們就可以直接執行【!Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main】命令了。

1 0:009> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ffb5bbbe0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ffb5bbe00c0(方法描述符地址)
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ffb5bb31930

                    效果如圖:
                    

                    該命令,可以針對方法起作用,也可以針對型別起作用。
                    執行【!Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program】命令檢視 Program 型別的詳情。

1 0:009> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program
2 Module:      00007ffb5bbbe0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000002000002
5 MethodTable: 00007ffb5bbe0100
6 EEClass:     00007ffb5bbcfb20
7 Name:        ExampleCore_3_1_10.Program

                    效果如圖:
                    


                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出 sum=21 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。

                    直接執行【!name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main】命令,查詢 Program.Main() 方法的資訊。

1 0:008> !name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program.Main
2 Module:      00007ff7dd61e0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000006000001
5 MethodDesc:  00007ff7dd6400c0
6 Name:        ExampleCore_3_1_10.Program.Main(System.String[])
7 JITTED Code Address: 00007ff7dd591930

                    【!name2ee】命令還可以獲取型別的資訊。執行命令【!name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program】。

1 0:008> !name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program
2 Module:      00007ff7dd61e0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000002000002
5 MethodTable: 00007ff7dd640100
6 EEClass:     00007ff7dd62fb20
7 Name:        ExampleCore_3_1_10.Program

                    很簡單,話不多說。

        3.3.3、物件同步塊的轉儲
            在這一節中,【!syncblk】命令可以用來獲取物件同步塊的資訊,這個命令在分析死鎖問題時非常有用,以後章節詳解,這裡就不多說了。

        3.3.4、物件方法表的轉儲
            A、基礎知識
                每個託管物件都有一個相應的方法表,它包含了物件的詳細資訊。我們可以使用【!DumpMT】命令獲取指定物件的方法表資訊,該命令的引數就是物件方法表的地址。
            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:【!DumpMT】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】命令,開啟偵錯程式視窗。
                    繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 sum=21。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。
                    此時,我們就可以直接執行【!Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program】命令來查詢它的方法表了。

1 0:009> !Name2EE ExampleCore_3_1_10!ExampleCore_3_1_10.Program
2 Module:      00007ffb5bbbe0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000002000002
5 MethodTable: 00007ffb5bbe0100(這就是方法表的地址)
6 EEClass:     00007ffb5bbcfb20
7 Name:        ExampleCore_3_1_10.Program

                    效果如圖:
                    

                    有了方法表的地址,我們就可以使用【!DumpMT】命令,執行命令【!DumpMT 00007ffb5bbe0100】。

 1 0:009> !DumpMT 00007ffb5bbe0100
 2 EEClass:         00007FFB5BBCFB20
 3 Module:          00007FFB5BBBE0A0
 4 Name:            ExampleCore_3_1_10.Program
 5 mdToken:         0000000002000002
 6 File:            E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
 7 BaseSize:        0x18
 8 ComponentSize:   0x0
 9 DynamicStatics:  false
10 ContainsPointers false
11 Slots in VTable: 7
12 Number of IFaces in IFaceMap: 0

                    效果如圖:
                    


                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出 sum=21 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。

                    我們透過【!Name2ee】命令找到型別的資訊,執行如下命令【!name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program

1 0:008> !name2ee ExampleCore_3_1_10!ExampleCore_3_1_10.Program
2 Module:      00007ff7dd61e0a0
3 Assembly:    ExampleCore_3_1_10.dll
4 Token:       0000000002000002
5 MethodTable: 00007ff7dd640100
6 EEClass:     00007ff7dd62fb20
7 Name:        ExampleCore_3_1_10.Program

                    MethodTable: 00007ff7dd640100 它就是 Program 型別的方法表地址,繼續執行【!DumpMT 00007ff7dd640100】命令。

 1 0:008> !DumpMT 00007ff7dd640100
 2 EEClass:             00007ff7dd62fb20
 3 Module:              00007ff7dd61e0a0
 4 Name:                ExampleCore_3_1_10.Program
 5 mdToken:             0000000002000002
 6 File:                E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
 7 AssemblyLoadContext: Default ALC - The managed instance of this context doesn't exist yet.
 8 BaseSize:            0x18
 9 ComponentSize:       0x0
10 DynamicStatics:      false
11 ContainsPointers:    false
12 Slots in VTable:     7
13 Number of IFaces in IFaceMap: 0

                    內容很簡單,就不廢話了。


        3.3.5、託管堆和垃圾收集器資訊的轉儲
            A、基礎知識
                CLR 垃圾收集器是一種高效的自動記憶體管理器,它確保記憶體實現最優的佈局和管理。SOS 偵錯程式擴充套件中提供了一些有關垃圾收集和託管堆的命令,如:DumpHeap(遍歷託管堆,收集並輸出這個堆以及位於堆上所有物件的資訊)、GCRoot(顯示對某個物件的根物件的引用資訊,當要找出某個物件為什麼沒有被回收,非常有用)、VerifyHeap(託管堆也可能損壞,這個命令可以驗證託管堆的完整性)和 TraverseHeap(遍歷託管堆,把結果輸出到檔案中,有 CLR 分析器分析) 等命令。
                我們不會演示所有命令的使用,著重演示 GCRoot 命令的使用。

            B、眼見為實
                除錯原始碼:ExampleCore_3_1_11
                除錯任務:【!GCRoot】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_11\bin\Debug\net8.0\ExampleCore_3_1_11.exe】命令,開啟偵錯程式視窗。
                    繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 資料新增完畢!。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。
                    此時,我們就可以直接執行【!DumpHeap -type Byte[]】命令在託管堆上查抄 byte[] 陣列了,找到了在分析。

  1 0:002> !DumpHeap -type Byte[]
  2          Address               MT     Size
  3 0000017882000028 00007ffb5b9fb810      536
  4 0000017882000240 00007ffb5b9fb810     1048
  5 0000017882000e20 00007ffb5b9f9cc0       34
  6 0000017882000e78 00007ffb5b9f9cc0     4120
  7 0000017882809650 00007ffb5b9f9e40       32
  8 0000017882809798 00007ffb5b9fb810      280
  9 00000178019004c8 00007ffb5b9fb810       24
 10 00000178019008a0 00007ffb5b9f9cc0       24
 11 0000017882c00048 00007ffb5b9f9cc0   100024
 12 0000017882c18720 00007ffb5b9f9cc0   100024
 13 0000017882c30df8 00007ffb5b9f9cc0   100024
 14 0000017882c494d0 00007ffb5b9f9cc0   100024
 15 0000017882c61ba8 00007ffb5b9f9cc0   100024
 16 0000017882c7a280 00007ffb5b9f9cc0   100024
 17 0000017882c92958 00007ffb5b9f9cc0   100024
 18 0000017882cab030 00007ffb5b9f9cc0   100024
 19 0000017882cc3708 00007ffb5b9f9cc0   100024
 20 0000017882cdbde0 00007ffb5b9f9cc0   100024
 21 0000017882cf44b8 00007ffb5b9f9cc0   100024
 22 0000017882d0cb90 00007ffb5b9f9cc0   100024
 23 0000017882d25268 00007ffb5b9f9cc0   100024
 24 0000017882d3d940 00007ffb5b9f9cc0   100024
 25 0000017882d56018 00007ffb5b9f9cc0   100024
 26 0000017882d6e6f0 00007ffb5b9f9cc0   100024
 27 0000017882d86dc8 00007ffb5b9f9cc0   100024
 28 0000017882d9f4a0 00007ffb5b9f9cc0   100024
 29 0000017882db7b78 00007ffb5b9f9cc0   100024
 30 0000017882dd0250 00007ffb5b9f9cc0   100024
 31 0000017882de8928 00007ffb5b9f9cc0   100024
 32 0000017882e01000 00007ffb5b9f9cc0   100024
 33 0000017882e196d8 00007ffb5b9f9cc0   100024
 34 0000017882e31db0 00007ffb5b9f9cc0   100024
 35 0000017882e4a488 00007ffb5b9f9cc0   100024
 36 0000017882e62b60 00007ffb5b9f9cc0   100024
 37 0000017882e7b238 00007ffb5b9f9cc0   100024
 38 0000017882e93910 00007ffb5b9f9cc0   100024
 39 0000017882eabfe8 00007ffb5b9f9cc0   100024
 40 0000017882ec46c0 00007ffb5b9f9cc0   100024
 41 0000017882edcd98 00007ffb5b9f9cc0   100024
 42 0000017882ef5470 00007ffb5b9f9cc0   100024
 43 0000017882f0db48 00007ffb5b9f9cc0   100024
 44 0000017882f26220 00007ffb5b9f9cc0   100024
 45 0000017882f3e8f8 00007ffb5b9f9cc0   100024
 46 0000017882f56fd0 00007ffb5b9f9cc0   100024
 47 0000017882f6f6a8 00007ffb5b9f9cc0   100024
 48 0000017882f87d80 00007ffb5b9f9cc0   100024
 49 0000017882fa0458 00007ffb5b9f9cc0   100024
 50 0000017882fb8b30 00007ffb5b9f9cc0   100024
 51 0000017882fd1208 00007ffb5b9f9cc0   100024
 52 0000017882fe98e0 00007ffb5b9f9cc0   100024
 53 0000017883001fb8 00007ffb5b9f9cc0   100024
 54 000001788301a690 00007ffb5b9f9cc0   100024
 55 0000017883032d68 00007ffb5b9f9cc0   100024
 56 000001788304b440 00007ffb5b9f9cc0   100024
 57 0000017883063b18 00007ffb5b9f9cc0   100024
 58 000001788307c1f0 00007ffb5b9f9cc0   100024
 59 00000178830948c8 00007ffb5b9f9cc0   100024
 60 00000178830acfa0 00007ffb5b9f9cc0   100024
 61 00000178830c5678 00007ffb5b9f9cc0   100024
 62 00000178830ddd50 00007ffb5b9f9cc0   100024
 63 00000178830f6428 00007ffb5b9f9cc0   100024
 64 000001788310eb00 00007ffb5b9f9cc0   100024
 65 00000178831271d8 00007ffb5b9f9cc0   100024
 66 000001788313f8b0 00007ffb5b9f9cc0   100024
 67 0000017883157f88 00007ffb5b9f9cc0   100024
 68 0000017883170660 00007ffb5b9f9cc0   100024
 69 0000017883188d38 00007ffb5b9f9cc0   100024
 70 00000178831a1410 00007ffb5b9f9cc0   100024
 71 00000178831b9ae8 00007ffb5b9f9cc0   100024
 72 00000178831d21c0 00007ffb5b9f9cc0   100024
 73 00000178831ea898 00007ffb5b9f9cc0   100024
 74 0000017883202f70 00007ffb5b9f9cc0   100024
 75 000001788321b648 00007ffb5b9f9cc0   100024
 76 0000017883233d20 00007ffb5b9f9cc0   100024
 77 000001788324c3f8 00007ffb5b9f9cc0   100024
 78 0000017883264ad0 00007ffb5b9f9cc0   100024
 79 000001788327d1a8 00007ffb5b9f9cc0   100024
 80 0000017883295880 00007ffb5b9f9cc0   100024
 81 00000178832adf58 00007ffb5b9f9cc0   100024
 82 00000178832c6630 00007ffb5b9f9cc0   100024
 83 00000178832ded08 00007ffb5b9f9cc0   100024
 84 00000178832f73e0 00007ffb5b9f9cc0   100024
 85 000001788330fab8 00007ffb5b9f9cc0   100024
 86 0000017883328190 00007ffb5b9f9cc0   100024
 87 0000017883340868 00007ffb5b9f9cc0   100024
 88 0000017883358f40 00007ffb5b9f9cc0   100024
 89 0000017883371618 00007ffb5b9f9cc0   100024
 90 0000017883389cf0 00007ffb5b9f9cc0   100024
 91 00000178833a23c8 00007ffb5b9f9cc0   100024
 92 00000178833baaa0 00007ffb5b9f9cc0   100024
 93 00000178833d3178 00007ffb5b9f9cc0   100024
 94 00000178833eb850 00007ffb5b9f9cc0   100024
 95 0000017883403f28 00007ffb5b9f9cc0   100024
 96 000001788341c600 00007ffb5b9f9cc0   100024
 97 0000017883434cd8 00007ffb5b9f9cc0   100024
 98 000001788344d3b0 00007ffb5b9f9cc0   100024
 99 0000017883465a88 00007ffb5b9f9cc0   100024
100 000001788347e160 00007ffb5b9f9cc0   100024
101 0000017883496838 00007ffb5b9f9cc0   100024
102 00000178834aef10 00007ffb5b9f9cc0   100024
103 00000178834c75e8 00007ffb5b9f9cc0   100024
104 00000178834dfcc0 00007ffb5b9f9cc0   100024
105 00000178834f8398 00007ffb5b9f9cc0   100024
106 0000017883510a70 00007ffb5b9f9cc0   100024
107 0000017883529148 00007ffb5b9f9cc0   100024
108 0000017883541820 00007ffb5b9f9cc0   100024
109 0000017883559ef8 00007ffb5b9f9cc0   100024
110 00000178835725d0 00007ffb5b9f9cc0   100024
111 
112 Statistics:
113               MT    Count    TotalSize Class Name
114 00007ffb5b9f9e40        1           32 System.Collections.Generic.List`1[[System.Byte[], System.Private.CoreLib]]
115 00007ffb5b9fb810        4         1888 System.Byte[][]
116 00007ffb5b9f9cc0      103     10006578 System.Byte[]
117 Total 108 objects
118 0:002>

                    我們可以知道資料大小為 100024 的項一共有100個,因為我們迴圈了100次。每一項資料的大小為什麼不是100000,而是 100024,因為它是陣列,所以它擁有同步塊索引、方法表資訊、陣列長度等附加資訊。在32位的機器上是100012,在64位機器是100024。
                    0000017883559ef8 我隨便找了一項,選的是最後一個項,這個就是元素的地址,我們可以使用【!GCRoot 0000017883559ef8】命令,檢視它的引用情況。

1 0:009> !gcroot 0000023306d59ef8
2 HandleTable:
3     0000023301B513E8 (strong handle)
4     -> 0000023303800028 System.Object[]
5     -> 0000023306009650 System.Collections.Generic.List`1[[System.Byte[], System.Private.CoreLib]]
6     -> 0000023305800240 System.Byte[][]
7     -> 0000023306D59EF8 System.Byte[]
8 
9 Found 1 unique roots (run '!gcroot -all' to see all roots).

                    【!VerifyHeap】該命令執行會有問題,效果如圖:
                    

                    推薦使用 Windbg,我只是想多熟悉一下。
                    執行命令【 !TraverseHeap F:\books\myTest.txt】,輸出檔案。

1 0:009> !TraverseHeap F:\books\myTest.txt
2 Assuming a uncorrupted GC heap.  If this is a crash dump consider -verify option
3 Writing CLRProfiler format to file F:\books\myTest.txt
4 Gathering types...
5 tracing roots...
6 
7 Walking heap...
8 
9 file F:\books\myTest.txt saved

                    效果如圖:
                    


                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_11.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出【資料新增完畢!】 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。
                    第一步,我們先在託管堆中查詢 Byte[] 陣列物件,執行命令【!dumpheap -type Byte[]】

  1 0:001> !dumpheap -type Byte[]
  2          Address               MT           Size
  3     01a606800028     7ff7dd61b810            536 
  4     01a606800240     7ff7dd61b810          1,048 
  5     01a606800e20     7ff7dd619cc0             34 
  6     01a606800e78     7ff7dd619cc0          4,120 
  7     01a607009650     7ff7dd619e40             32 
  8     01a607009798     7ff7dd61b810            280 
  9     01a607400048     7ff7dd619cc0        100,024 
 10     01a607418720     7ff7dd619cc0        100,024 
 11     01a607430df8     7ff7dd619cc0        100,024 
 12     01a6074494d0     7ff7dd619cc0        100,024 
 13     01a607461ba8     7ff7dd619cc0        100,024 
 14     01a60747a280     7ff7dd619cc0        100,024 
 15     01a607492958     7ff7dd619cc0        100,024 
 16     01a6074ab030     7ff7dd619cc0        100,024 
 17     01a6074c3708     7ff7dd619cc0        100,024 
 18     01a6074dbde0     7ff7dd619cc0        100,024 
 19     01a6074f44b8     7ff7dd619cc0        100,024 
 20     01a60750cb90     7ff7dd619cc0        100,024 
 21     01a607525268     7ff7dd619cc0        100,024 
 22     01a60753d940     7ff7dd619cc0        100,024 
 23     01a607556018     7ff7dd619cc0        100,024 
 24     01a60756e6f0     7ff7dd619cc0        100,024 
 25     01a607586dc8     7ff7dd619cc0        100,024 
 26     01a60759f4a0     7ff7dd619cc0        100,024 
 27     01a6075b7b78     7ff7dd619cc0        100,024 
 28     01a6075d0250     7ff7dd619cc0        100,024 
 29     01a6075e8928     7ff7dd619cc0        100,024 
 30     01a607601000     7ff7dd619cc0        100,024 
 31     01a6076196d8     7ff7dd619cc0        100,024 
 32     01a607631db0     7ff7dd619cc0        100,024 
 33     01a60764a488     7ff7dd619cc0        100,024 
 34     01a607662b60     7ff7dd619cc0        100,024 
 35     01a60767b238     7ff7dd619cc0        100,024 
 36     01a607693910     7ff7dd619cc0        100,024 
 37     01a6076abfe8     7ff7dd619cc0        100,024 
 38     01a6076c46c0     7ff7dd619cc0        100,024 
 39     01a6076dcd98     7ff7dd619cc0        100,024 
 40     01a6076f5470     7ff7dd619cc0        100,024 
 41     01a60770db48     7ff7dd619cc0        100,024 
 42     01a607726220     7ff7dd619cc0        100,024 
 43     01a60773e8f8     7ff7dd619cc0        100,024 
 44     01a607756fd0     7ff7dd619cc0        100,024 
 45     01a60776f6a8     7ff7dd619cc0        100,024 
 46     01a607787d80     7ff7dd619cc0        100,024 
 47     01a6077a0458     7ff7dd619cc0        100,024 
 48     01a6077b8b30     7ff7dd619cc0        100,024 
 49     01a6077d1208     7ff7dd619cc0        100,024 
 50     01a6077e98e0     7ff7dd619cc0        100,024 
 51     01a607801fb8     7ff7dd619cc0        100,024 
 52     01a60781a690     7ff7dd619cc0        100,024 
 53     01a607832d68     7ff7dd619cc0        100,024 
 54     01a60784b440     7ff7dd619cc0        100,024 
 55     01a607863b18     7ff7dd619cc0        100,024 
 56     01a60787c1f0     7ff7dd619cc0        100,024 
 57     01a6078948c8     7ff7dd619cc0        100,024 
 58     01a6078acfa0     7ff7dd619cc0        100,024 
 59     01a6078c5678     7ff7dd619cc0        100,024 
 60     01a6078ddd50     7ff7dd619cc0        100,024 
 61     01a6078f6428     7ff7dd619cc0        100,024 
 62     01a60790eb00     7ff7dd619cc0        100,024 
 63     01a6079271d8     7ff7dd619cc0        100,024 
 64     01a60793f8b0     7ff7dd619cc0        100,024 
 65     01a607957f88     7ff7dd619cc0        100,024 
 66     01a607970660     7ff7dd619cc0        100,024 
 67     01a607988d38     7ff7dd619cc0        100,024 
 68     01a6079a1410     7ff7dd619cc0        100,024 
 69     01a6079b9ae8     7ff7dd619cc0        100,024 
 70     01a6079d21c0     7ff7dd619cc0        100,024 
 71     01a6079ea898     7ff7dd619cc0        100,024 
 72     01a607a02f70     7ff7dd619cc0        100,024 
 73     01a607a1b648     7ff7dd619cc0        100,024 
 74     01a607a33d20     7ff7dd619cc0        100,024 
 75     01a607a4c3f8     7ff7dd619cc0        100,024 
 76     01a607a64ad0     7ff7dd619cc0        100,024 
 77     01a607a7d1a8     7ff7dd619cc0        100,024 
 78     01a607a95880     7ff7dd619cc0        100,024 
 79     01a607aadf58     7ff7dd619cc0        100,024 
 80     01a607ac6630     7ff7dd619cc0        100,024 
 81     01a607aded08     7ff7dd619cc0        100,024 
 82     01a607af73e0     7ff7dd619cc0        100,024 
 83     01a607b0fab8     7ff7dd619cc0        100,024 
 84     01a607b28190     7ff7dd619cc0        100,024 
 85     01a607b40868     7ff7dd619cc0        100,024 
 86     01a607b58f40     7ff7dd619cc0        100,024 
 87     01a607b71618     7ff7dd619cc0        100,024 
 88     01a607b89cf0     7ff7dd619cc0        100,024 
 89     01a607ba23c8     7ff7dd619cc0        100,024 
 90     01a607bbaaa0     7ff7dd619cc0        100,024 
 91     01a607bd3178     7ff7dd619cc0        100,024 
 92     01a607beb850     7ff7dd619cc0        100,024 
 93     01a607c03f28     7ff7dd619cc0        100,024 
 94     01a607c1c600     7ff7dd619cc0        100,024 
 95     01a607c34cd8     7ff7dd619cc0        100,024 
 96     01a607c4d3b0     7ff7dd619cc0        100,024 
 97     01a607c65a88     7ff7dd619cc0        100,024 
 98     01a607c7e160     7ff7dd619cc0        100,024 
 99     01a607c96838     7ff7dd619cc0        100,024 
100     01a607caef10     7ff7dd619cc0        100,024 
101     01a607cc75e8     7ff7dd619cc0        100,024 
102     01a607cdfcc0     7ff7dd619cc0        100,024 
103     01a607cf8398     7ff7dd619cc0        100,024 
104     01a607d10a70     7ff7dd619cc0        100,024 
105     01a607d29148     7ff7dd619cc0        100,024 
106     01a607d41820     7ff7dd619cc0        100,024 
107     01a607d59ef8     7ff7dd619cc0        100,024 
108     01a607d725d0     7ff7dd619cc0        100,024 
109     01e6991e04c8     7ff7dd61b810             24 
110     01e6991e08a0     7ff7dd619cc0             24 
111 
112 Statistics:
113           MT Count  TotalSize Class Name
114 7ff7dd619e40     1         32 System.Collections.Generic.List<System.Byte[]>
115 7ff7dd61b810     4      1,888 System.Byte[][]
116 7ff7dd619cc0   103 10,006,578 System.Byte[]
117 Total 108 objects, 10,008,498 bytes

                    資料大小為 100,024 的專案,一種有 100 項,因為我們 For 迴圈了一百次,為什麼大小不是 100000,而是 100024 ,因為每個陣列物件都有兩個附加成員和陣列長度,在 32 位機器上是100012,在64位機器上是100024。有了成員列表,我們可以在這個列表中,任意選擇一個項,在 Address 列,選一個地址,針對這個地址,我們使用【!gcroot】命令,就能看到我們想要的結果。

                    01a607d725d0 我選的就是這一項,標紅色的。

 1 0:001> !GCRoot 01a607d725d0
 2 HandleTable:
 3     000001a6043213e8 (strong handle)(static 底層是標記了 pinned,也就是這個 handle 持有 System.Object[] 陣列)
 4           -> 01a604800028     System.Object[] 
 5           -> 01a607009650     System.Collections.Generic.List<System.Byte[]> 
 6           -> 01a606800240     System.Byte[][] 
 7           -> 01a607d725d0     System.Byte[] 
 8 
 9 Thread 3028:
10     165219e7c0 7ff7dd5619e4 ExampleCore_3_1_11.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_11\Program.cs @ 14]
11         rbp-18: 000000165219e7e8
12           -> 01a607d725d0     System.Byte[] 
13 
14         rbp-10: 000000165219e7f0
15           -> 01a607009650     System.Collections.Generic.List<System.Byte[]> 
16           -> 01a606800240     System.Byte[][] 
17           -> 01a607d725d0     System.Byte[] 
18 
19 Found 3 unique roots.

                    執行命令【!VerifyHeap】,看一下託管堆健康的狀況。

1 0:001> !VerifyHeap
2 347 objects verified, 0 errors.
3 No heap corruption detected.

                    執行命令【 !TraverseHeap F:\books\myTest.txt】,輸出檔案。

1 0:001> !TraverseHeap F:\books\myTest.txt

                    你去指定目錄查詢吧,肯定有一個檔案【myTest.txt】存在。


    3.4、診斷命令
        以前的討論的命令都是除錯分析命令,SOS 偵錯程式擴充套件還提供了一些診斷命令,這些命令在除錯會話中提供一些輔助資訊。
        3.4.1、找出物件的應用程式域
            A、基礎知識
                如果我們想找某個物件屬於哪個應用程式域,我們可以使用【!FindAppDomain】命令。
            B、眼見為實
                除錯原始碼:ExampleCore_3_1_10
                除錯任務:【!FindAppDomain】命令的使用。
                1)、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】命令,開啟偵錯程式視窗。
                    繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 sum=21。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。
                    由於我們的操作和具體的堆疊有關,並且由於我們手動中斷,必須要轉換到託管執行緒上才可以,執行命令【~0s】。

1 0:009> ~0s
2 ntdll!RtlpEnterCriticalSectionContended+0xe4:
3 00007ffc`82a3fbd4 ebea            jmp     ntdll!RtlpEnterCriticalSectionContended+0xd0 (00007ffc`82a3fbc0)

                    效果如圖:
                    

                    繼續執行【!dso】或者【!DumpStackObjects】命令檢視一下託管執行緒棧上的物件。

 1 0:000> !dso
 2 OS Thread Id: 0x3f08 (0)
 3 RSP/REG          Object           Name
 4 00000051D657E2D0 000001688d40b648 System.Text.DecoderDBCS
 5 00000051D657E930 000001688d40c720 System.Char[]
 6 00000051D657E958 000001688d40b6f0 System.Byte[]
 7 00000051D657E988 000001688d40b648 System.Text.DecoderDBCS
 8 00000051D657E9E0 000001688d40b6f0 System.Byte[]
 9 00000051D657E9F0 000001688d40b648 System.Text.DecoderDBCS
10 00000051D657EA10 000001688d40c720 System.Char[]
11 00000051D657EA20 000001688d40b6f0 System.Byte[]
12 00000051D657EA28 000001a91f4810c8 System.String    bytes
13 00000051D657EA70 000001688d40b5e8 System.IO.StreamReader
14 00000051D657EAB0 000001688d40b648 System.Text.DecoderDBCS
15 00000051D657EAB8 000001688d40b6f0 System.Byte[]
16 00000051D657EAD0 000001688d40c720 System.Char[]
17 00000051D657EAF0 000001688d40b5e8 System.IO.StreamReader
18 00000051D657EB00 000001688d40b5e8 System.IO.StreamReader
19 00000051D657EB10 000001688d40aeb8 System.Object
20 00000051D657EBB0 000001688d40b5e8 System.IO.StreamReader
21 00000051D657EBC0 000001688d40aeb8 System.Object
22 00000051D657EC00 000001688d414738 System.IO.SyncTextReader
23 00000051D657EC10 000001688d40aeb8 System.Object
24 00000051D657EC48 000001688d40b4b0 System.IO.TextWriter+SyncTextWriter
25 00000051D657EC60 000001688d40ac48 System.String    sum=21
26 00000051D657ECB0 000001688d408eb0 System.String[]
27 00000051D657ED58 000001688d408eb0 System.String[]
28 00000051D657EF50 000001688d408eb0 System.String[]
29 00000051D657EF58 000001688d408eb0 System.String[]
30 00000051D657F070 000001688d408eb0 System.String[]
31 00000051D657F0F0 000001688d408ec8 System.String    E:\Visual Studio 2022\...\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
32 00000051D657F100 000001688d408eb0 System.String[]
33 00000051D657F110 000001688d408e90 System.String[]
34 00000051D657F148 000001688d408ec8 System.String    E:\Visual Studio 2022\...\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
35 00000051D657F2F8 000001688d408eb0 System.String[]

                    000001688d40b6f0 我們用它做例子,看看這個 byte 陣列屬於哪個應用程式域。執行【!FindAppDomain 000001688d40b6f0】命令。

1 0:000> !FindAppDomain 000001688d40b6f0
2 AppDomain: 0000016888e66b60(應用程式域的地址)
3 Name:      clrhost
4 ID:        1

                    AppDomain: 0000016888e66b60 我們有了應用程式域的地址,直接使用【!DumpDomain 0000016888e66b60】命令檢視應用程式域的詳情。

 1 0:000> !DumpDomain 0000016888e66b60
 2 --------------------------------------
 3 Domain 1:           0000016888e66b60
 4 LowFrequencyHeap:   00007FFBAF5865A8
 5 HighFrequencyHeap:  00007FFBAF586638
 6 StubHeap:           00007FFBAF5866C8
 7 Stage:              OPEN
 8 Name:               clrhost
 9 Assembly:           0000016888e79060 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll]
10 ClassLoader:        0000016888E790F0
11   Module
12   00007ffb4f594000    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll
13 
14 Assembly:           000001688a8c7ac0 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll]
15 ClassLoader:        000001688A8C7B50
16   Module
17   00007ffb4f77e0a0    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
18 
19 Assembly:           0000016888e480b0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll]
20 ClassLoader:        0000016888E48140
21   Module
22   00007ffb4f77fbc8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll
23 
24 Assembly:           0000016888eb95c0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll]
25 ClassLoader:        0000016888EB9930
26   Module
27   00007ffb4f7ac3a8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll
28 
29 Assembly:           000001688a8ca600 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll]
30 ClassLoader:        000001688A8CA950
31   Module
32   00007ffb4f7d72f0    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll
33 
34 Assembly:           0000016888e8f6b0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll]
35 ClassLoader:        0000016888E8F740
36   Module
37   00007ffb4f7dafa8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll
38 
39 Assembly:           0000016888e94090 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll]
40 ClassLoader:        0000016888E94120
41   Module
42   00007ffb4f7dd480    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll

                    當然,如果這個命令不跟任何引數,就會輸出當錢的應用程式域的資訊。

 1 0:000> !dumpdomain
 2 --------------------------------------
 3 System Domain:      00007ffbaf5860d0
 4 LowFrequencyHeap:   00007FFBAF5865A8
 5 HighFrequencyHeap:  00007FFBAF586638
 6 StubHeap:           00007FFBAF5866C8
 7 Stage:              OPEN
 8 Name:               None
 9 --------------------------------------
10 Domain 1:           0000016888e66b60
11 LowFrequencyHeap:   00007FFBAF5865A8
12 HighFrequencyHeap:  00007FFBAF586638
13 StubHeap:           00007FFBAF5866C8
14 Stage:              OPEN
15 Name:               clrhost
16 Assembly:           0000016888e79060 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll]
17 ClassLoader:        0000016888E790F0
18   Module
19   00007ffb4f594000    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll
20 
21 Assembly:           000001688a8c7ac0 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll]
22 ClassLoader:        000001688A8C7B50
23   Module
24   00007ffb4f77e0a0    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
25 
26 Assembly:           0000016888e480b0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll]
27 ClassLoader:        0000016888E48140
28   Module
29   00007ffb4f77fbc8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll
30 
31 Assembly:           0000016888eb95c0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll]
32 ClassLoader:        0000016888EB9930
33   Module
34   00007ffb4f7ac3a8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll
35 
36 Assembly:           000001688a8ca600 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll]
37 ClassLoader:        000001688A8CA950
38   Module
39   00007ffb4f7d72f0    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll
40 
41 Assembly:           0000016888e8f6b0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll]
42 ClassLoader:        0000016888E8F740
43   Module
44   00007ffb4f7dafa8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll
45 
46 Assembly:           0000016888e94090 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll]
47 ClassLoader:        0000016888E94120
48   Module
49   00007ffb4f7dd480    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll


                2)、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                    【g】繼續執行偵錯程式,等我們的控制檯程式輸出【sum=21】 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。
                    由於我們手動切換到中斷模式,我們需要切換到託管執行緒上,執行【~0s】命令。然後,我們執行【!dso】或者【!DumpStackObjects】命令,查詢棧上所有的物件。

 1 0:000> !DumpStackObjects
 2 OS Thread Id: 0x25fc (0)
 3           SP/REG           Object Name
 4     000e6437e6d8     0185c700b580 System.ConsolePal+WindowsConsoleStream
 5     000e6437e6e8     0185c700b580 System.ConsolePal+WindowsConsoleStream
 6     000e6437e6f8     0185c700b6f0 System.Byte[]
 7     000e6437e750     0185c700b580 System.ConsolePal+WindowsConsoleStream
 8     000e6437e798     0185c700b5e8 System.IO.StreamReader
 9     000e6437e7c0     0185c700b580 System.ConsolePal+WindowsConsoleStream
10     000e6437e7c8     0185c700b6f0 System.Byte[]
11     000e6437e800     0185c700b5e8 System.IO.StreamReader
12     000e6437e810     0185c700b5e8 System.IO.StreamReader
13     000e6437e820     0185c700aeb8 System.Object
14     000e6437e8c0     0185c700b5e8 System.IO.StreamReader
15     000e6437e8d0     0185c700aeb8 System.Object
16     000e6437e910     0185c7014738 System.IO.SyncTextReader
17     000e6437e920     0185c700aeb8 System.Object
18     000e6437e958     0185c700b4b0 System.IO.TextWriter+SyncTextWriter
19     000e6437e970     0185c700ac48 System.String
20     000e6437e9c0     0185c7008eb0 System.String[]
21     000e6437ea68     0185c7008eb0 System.String[]
22     000e6437ec60     0185c7008eb0 System.String[]
23     000e6437ec68     0185c7008eb0 System.String[]
24     000e6437ed80     0185c7008eb0 System.String[]
25     000e6437ee00     0185c7008ec8 System.String
26     000e6437ee10     0185c7008eb0 System.String[]
27     000e6437ee20     0185c7008e90 System.String[]
28     000e6437ee58     0185c7008ec8 System.String
29     000e6437f008     0185c7008eb0 System.String[]

                    0185c700b6f0 我查詢這個陣列屬於哪個引用程式域,執行命令【!FindAppDomain 0185c700b6f0】。

1 0:000> !FindAppDomain 0185c700b6f0
2 AppDomain: 00000185c2d189a0(引用程式域的地址)
3 Name:      clrhost
4 ID:        1

                    AppDomain: 00000185c2d189a0 有了引用程式域的地址,我們就可以使用【!DumpDomain】命令,檢視特定引用程式域的詳情了。
                    執行命令【!DumpDomain 00000185c2d189a0】。

 1 0:000> !DumpDomain 00000185c2d189a0
 2 --------------------------------------
 3 Domain 1:           00000185c2d189a0
 4 LowFrequencyHeap:   00007FFBAA0365A8
 5 HighFrequencyHeap:  00007FFBAA036638
 6 StubHeap:           00007FFBAA0366C8
 7 Stage:              OPEN
 8 Name:               clrhost
 9 Assembly:           00000185c2cdf720 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll]
10 ClassLoader:        00000185C2CDF7B0
11   Module
12   00007ffb4a024000    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll
13 
14 Assembly:           00000185c2cccba0 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll]
15 ClassLoader:        00000185C2CCCC30
16   Module
17   00007ffb4a20e0a0    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
18 
19 Assembly:           00000185c461e520 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll]
20 ClassLoader:        00000185C461E5B0
21   Module
22   00007ffb4a20fbc8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll
23 
24 Assembly:           00000185c2cce6c0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll]
25 ClassLoader:        00000185C2CCEA30
26   Module
27   00007ffb4a23c3a8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll
28 
29 Assembly:           00000185c2cf1ab0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll]
30 ClassLoader:        00000185C2CF1B40
31   Module
32   00007ffb4a2672f0    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll
33 
34 Assembly:           00000185c2cf6480 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll]
35 ClassLoader:        00000185C2CF6510
36   Module
37   00007ffb4a26afa8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll
38 
39 Assembly:           00000185c2cf6760 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll]
40 ClassLoader:        00000185C4620050
41   Module
42   00007ffb4a26d480    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll        

                    如果想檢視應用程式域的詳情,也可以執行命令【!DumpDomain】,無引數。

 1 0:000> !DumpDomain
 2 --------------------------------------
 3 System Domain:      00007ffbaa0360d0
 4 LowFrequencyHeap:   00007FFBAA0365A8
 5 HighFrequencyHeap:  00007FFBAA036638
 6 StubHeap:           00007FFBAA0366C8
 7 Stage:              OPEN
 8 Name:               None
 9 --------------------------------------
10 Domain 1:           00000185c2d189a0
11 LowFrequencyHeap:   00007FFBAA0365A8
12 HighFrequencyHeap:  00007FFBAA036638
13 StubHeap:           00007FFBAA0366C8
14 Stage:              OPEN
15 Name:               clrhost
16 Assembly:           00000185c2cdf720 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll]
17 ClassLoader:        00000185C2CDF7B0
18   Module
19   00007ffb4a024000    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Private.CoreLib.dll
20 
21 Assembly:           00000185c2cccba0 [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll]
22 ClassLoader:        00000185C2CCCC30
23   Module
24   00007ffb4a20e0a0    E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.dll
25 
26 Assembly:           00000185c461e520 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll]
27 ClassLoader:        00000185C461E5B0
28   Module
29   00007ffb4a20fbc8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.dll
30 
31 Assembly:           00000185c2cce6c0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll]
32 ClassLoader:        00000185C2CCEA30
33   Module
34   00007ffb4a23c3a8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Console.dll
35 
36 Assembly:           00000185c2cf1ab0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll]
37 ClassLoader:        00000185C2CF1B40
38   Module
39   00007ffb4a2672f0    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Threading.dll
40 
41 Assembly:           00000185c2cf6480 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll]
42 ClassLoader:        00000185C2CF6510
43   Module
44   00007ffb4a26afa8    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Text.Encoding.Extensions.dll
45 
46 Assembly:           00000185c2cf6760 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll]
47 ClassLoader:        00000185C4620050
48   Module
49   00007ffb4a26d480    C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.2\System.Runtime.InteropServices.dll       


        3.4.2、程序資訊
            A、基礎知識
                
在除錯會話中,如果我們想獲取記憶體使用量、環境變數、處理時間等這些資訊時,可以使用【!ProcInfo】命令,它有三個命令開關:-env(環境變數),-time(處理時間),-mem(記憶體使用情況),如果不帶任何引數,會輸出所有資訊。
            B、眼見為實
                
除錯原始碼:ExampleCore_3_1_10
                 除錯任務:【!ProcInfo】命令的使用。
                說明,其實這個專案可以是任意一個,不需要任何程式碼,所以我繼續使用原來的專案。
                  1)、NTSD 除錯
                      編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.2】命令列工具,輸入【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_10\bin\Debug\net8.0\ExampleCore_3_1_10.exe】命令,開啟偵錯程式視窗。
                      繼續使用【g】命令,執行偵錯程式,直到偵錯程式輸出 sum=21。此時,偵錯程式也處於卡死的狀態,按【ctrl+c】組合鍵進入偵錯程式中斷模式。

                      我們直接執行【!ProcInfo -env】命令,獲取系統的環境變數資訊。

 1 0:009> !ProcInfo -env
 2 ---------------------------------------
 3 Environment
 4 =::=::\
 5 =C:=C:\Program Files (x86)\Microsoft Visual Studio\Installer
 6 =D:=D:\Program Files\Microsoft Visual Studio\2022\Community
 7 =ExitCode=00000000
 8 ALLUSERSPROFILE=C:\ProgramData
 9 APPDATA=C:\Users\Administrator\AppData\Roaming
10 CommandPromptType=Native
11 CommonProgramFiles=C:\Program Files\Common Files
12 CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
13 CommonProgramW6432=C:\Program Files\Common Files
14 COMPLUS_MDA=1
15 COMPUTERNAME=MS-VMSQSWIJZFNM
16 ComSpec=C:\Windows\system32\cmd.exe
17 DevEnvDir=D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\
18 DriverData=C:\Windows\System32\Drivers\DriverData
19 ExtensionSdkDir=C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs
20 EXTERNAL_INCLUDE=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\ATLMFC\include;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include;D:\Windows Kits\10\include\10.0.22621.0\ucrt;D:\Windows Kits\10\\include\10.0.22621.0\\um;D:\Windows Kits\10\\include\10.0.22621.0\\shared;D:\Windows Kits\10\\include\10.0.22621.0\\winrt;D:\Windows Kits\10\\include\10.0.22621.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um
21 FPS_BROWSER_APP_PROFILE_STRING=Internet Explorer
22 FPS_BROWSER_USER_PROFILE_STRING=Default
23 Framework40Version=v4.0
24 FrameworkDir=C:\Windows\Microsoft.NET\Framework\
25 FrameworkDir32=C:\Windows\Microsoft.NET\Framework\
26 FrameworkVersion=v4.0.30319
27 FrameworkVersion32=v4.0.30319
28 FSHARPINSTALLDIR=D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools
29 GENICAM_GENTL32_PATH=C:\Program Files (x86)\Common Files\MVS\Runtime\Win32_i86
30 GENICAM_GENTL64_PATH=C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64
31 HOMEDRIVE=C:
32 HOMEPATH=\Users\Administrator
33 INCLUDE=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\
34 14.39.33519\ATLMFC\include;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include;D:\Windows Kits\10\include\10.0.22621.0\ucrt;D:\Windows Kits\10\\include\10.0.22621.0\\um;D:\Windows Kits\10\\include\10.0.22621.0\\shared;D:\Windows Kits\10\\include\10.0.22621.0\\winrt;D:\Windows Kits\10\\include\10.0.22621.0\\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um
35 LIB=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\ATLMFC\lib\x86;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x86;D:\Windows Kits\10\lib\10.0.22621.0\ucrt\x86;D:\Windows Kits\10\\lib\10.0.22621.0\\um\x86
36 LIBPATH=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\ATLMFC\lib\x86;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\lib\x86\store\references;D:\Windows Kits\10\UnionMetadata\10.0.22621.0;D:\Windows Kits\10\References\10.0.22621.0;C:\Windows\Microsoft.NET\Framework\v4.0.30319
37 LOCALAPPDATA=C:\Users\Administrator\AppData\Local
38 LOGONSERVER=\\MS-VMSQSWIJZFNM
39 MVCAM_COMMON_RUNENV=D:\Program Files (x86)\MVS\Development
40 MVCAM_GENICAM_CLPROTOCOL=C:\Program Files (x86)\Common Files\MVS\Runtime\CLProtocol
41 MVCAM_GIGE_DEBUG_HEARTBEAT=60000
42 NETFXSDKDir=C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\
43 NUMBER_OF_PROCESSORS=4
44 OneDrive=C:\Users\Administrator\OneDrive
45 OS=Windows_NT
46 Path=D:\Windows Kits\10\Debuggers\x64;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\bin\HostX86\x86;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\VC\VCPackages;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer;D:\Program Files\Micr
47 osoft Visual Studio\2022\Community\MSBuild\Current\bin\Roslyn;D:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools;D:\Program Files\Microsoft Visual Studio\2022\Community\Team Tools\DiagnosticsHub\Collector;D:\Windows Kits\10\bin\10.0.22621.0\\x86;D:\Windows Kits\10\bin\\x86;D:\Program Files\Microsoft Visual Studio\2022\Community\\MSBuild\Current\Bin\amd64;C:\Windows\Microsoft.NET\Framework\v4.0.30319;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\;C:\Program Files (x86)\Common Files\MVS\Runtime\Win32_i86;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\dotnet\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\DTS\Binn\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\;D:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;D:\XIMEA\API;C:\XIMEA\API;D:\Program Files\Git\cmd;D:\Windows Kits\10\Windows Performance Toolkit\;D:\Windows Kits\10\Debuggers\x64;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Users\Administrator\.dotnet\tools;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;D:\Program Files\Microsoft Visual Studio\2022\Community\Commo
48 n7\IDE\VC\Linux\bin\ConnectionManagerExe
49 PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
50 PROCESSOR_ARCHITECTURE=AMD64
51 PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 61 Stepping 4, GenuineIntel
52 PROCESSOR_LEVEL=6
53 PROCESSOR_REVISION=3d04
54 ProgramData=C:\ProgramData
55 ProgramFiles=C:\Program Files
56 ProgramFiles(x86)=C:\Program Files (x86)
57 ProgramW6432=C:\Program Files
58 PROMPT=$P$G
59 PSModulePath=C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules
60 PUBLIC=C:\Users\Public
61 SESSIONNAME=Console
62 SystemDrive=C:
63 SystemRoot=C:\Windows
64 TEMP=C:\Users\Administrator\AppData\Local\Temp
65 TMP=C:\Users\Administrator\AppData\Local\Temp
66 UCRTVersion=10.0.22621.0
67 UniversalCRTSdkDir=D:\Windows Kits\10\
68 USERDOMAIN=MS-VMSQSWIJZFNM
69 USERDOMAIN_ROAMINGPROFILE=MS-VMSQSWIJZFNM
70 USERNAME=Administrator
71 USERPROFILE=C:\Users\Administrator
72 VCIDEInstallDir=D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\VC\
73 VCINSTALLDIR=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\
74 VCToolsInstallDir=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\
75 VCToolsRedistDir=D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Redist\MSVC\14.38.33135\
76 VCToolsVersion=14.39.33519
77 VisualStudioVersion=17.0
78 VS170COMNTOOLS=D:\Program Files\Microsoft Visual Studio\2022\Community\Common7\Tools\
79 VSCMD_ARG_app_plat=Desktop
80 VSCMD_ARG_HOST_ARCH=x86
81 VSCMD_ARG_TGT_ARCH=x86
82 VSCMD_VER=17.9.2
83 VSINSTALLDIR=D:\Program Files\Microsoft Visual Studio\2022\Community\
84 windir=C:\Windows
85 WindowsLibPath=D:\Windows Kits\10\UnionMetadata\10.0.22621.0;D:\Windows Kits\10\References\10.0.22621.0
86 WindowsSdkBinPath=D:\Windows Kits\10\bin\
87 WindowsSdkDir=D:\Windows Kits\10\
88 WindowsSDKLibVersion=10.0.22621.0\
89 WindowsSdkVerBinPath=D:\Windows Kits\10\bin\10.0.22621.0\
90 WindowsSDKVersion=10.0.22621.0\
91 WindowsSDK_ExecutablePath_x64=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\
92 WindowsSDK_ExecutablePath_x86=C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 T
93 ools\
94 __DOTNET_ADD_32BIT=1
95 __DOTNET_PREFERRED_BITNESS=32
96 __VSCMD_PREINIT_PATH=C:\Program Files (x86)\Common Files\MVS\Runtime\Win32_i86;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\dotnet\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\DTS\Binn\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\;D:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;D:\XIMEA\API;C:\XIMEA\API;D:\Program Files\Git\cmd;D:\Windows Kits\10\Windows Performance Toolkit\;D:\Windows Kits\10\Debuggers\x64;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Users\Administrator\.dotnet\tools

                      我們執行【!ProcInfo -mem】命令,獲取系統使用記憶體使用的資訊。

 1 0:009> !ProcInfo -mem
 2 ---------------------------------------
 3 Process Memory
 4 WorkingSetSize:    18032 KB       PeakWorkingSetSize:    18036 KB
 5 VirtualSize:    -1872280724 KB       PeakVirtualSize:    -1872280724 KB
 6 PagefileUsage:      5460 KB       PeakPagefileUsage:      5476 KB
 7 ---------------------------------------
 8 58 percent of memory is in use.
 9 
10 Memory Availability (Numbers in MB)
11 
12                      Total        Avail
13 Physical Memory      16258         6707
14 Page File            18690         7452
15 Virtual Memory    134217727     132115918

                      我們執行【!ProcInfo -time】命令,獲取系統處理時間的資訊。

1 0:009> !ProcInfo -time
2 ---------------------------------------
3 Process Times
4 Process Started at: 2024 Mar 20 16:12:22.76
5 Kernel CPU time   : 0 days 00:00:00.06
6 User   CPU time   : 0 days 00:00:00.09
7 Total  CPU time   : 0 days 00:00:00.15


                  2)、Windbg Preview 除錯
                      編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】--->【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_10.exe,點選【開啟】按鈕進入偵錯程式。
                      【g】繼續執行偵錯程式,等我們的控制檯程式輸出【sum=21】 字樣後,此時偵錯程式處於卡死狀態,我們點選【break】按鈕進入偵錯程式的中斷模式。
                      這裡的內容很簡單,我不分步驟了,直接輸出結果。

 1 0:008> !ProcInfo -env
 2 ---------------------------------------
 3 Environment
 4 =::=::\
 5 ALLUSERSPROFILE=C:\ProgramData
 6 APPDATA=C:\Users\Administrator\AppData\Roaming
 7 CommonProgramFiles=C:\Program Files\Common Files
 8 CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files
 9 CommonProgramW6432=C:\Program Files\Common Files
10 COMPLUS_MDA=1
11 COMPUTERNAME=MS-VMSQSWIJZFNM
12 ComSpec=C:\Windows\system32\cmd.exe
13 DBGENG_OVERRIDE_DBGSRV_PATH=C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps\Microsoft.WinDbg_8wekyb3d8bbwe\dbgsrvX64.exe
14 DBGHELP_HOMEDIR=C:\ProgramData\Dbg
15 DriverData=C:\Windows\System32\Drivers\DriverData
16 GENICAM_GENTL32_PATH=C:\Program Files (x86)\Common Files\MVS\Runtime\Win32_i86
17 GENICAM_GENTL64_PATH=C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64
18 HOMEDRIVE=C:
19 HOMEPATH=\Users\Administrator
20 LOCALAPPDATA=C:\Users\Administrator\AppData\Local
21 LOGONSERVER=\\MS-VMSQSWIJZFNM
22 MVCAM_COMMON_RUNENV=D:\Program Files (x86)\MVS\Development
23 MVCAM_GENICAM_CLPROTOCOL=C:\Program Files (x86)\Common Files\MVS\Runtime\CLProtocol
24 MVCAM_GIGE_DEBUG_HEARTBEAT=60000
25 NUMBER_OF_PROCESSORS=4
26 OneDrive=C:\Users\Administrator\OneDrive
27 OS=Windows_NT
28 Path=C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64;C:\Program Files (x86)\Common Files\MVS\Runtime\Win32_i86;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\dotnet\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\Tools\Binn\;D:\Program Files\Microsoft SQL Server\100\DTS\Binn\;D:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\;D:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;D:\XIMEA\API;C:\XIMEA\API;D:\Program Files\Git\cmd;D:\Windows Kits\10\Windows Performance Toolkit\;D:\Wind
29 ows Kits\10\Debuggers\x64;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\Users\Administrator\.dotnet\tools
30 PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
31 PROCESSOR_ARCHITECTURE=AMD64
32 PROCESSOR_IDENTIFIER=Intel64 Family 6 Model 61 Stepping 4, GenuineIntel
33 PROCESSOR_LEVEL=6
34 PROCESSOR_REVISION=3d04
35 ProgramData=C:\ProgramData
36 ProgramFiles=C:\Program Files
37 ProgramFiles(x86)=C:\Program Files (x86)
38 ProgramW6432=C:\Program Files
39 PSModulePath=C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules
40 PUBLIC=C:\Users\Public
41 SRCSRV_SHOW_TF_PROMPT=1
42 SystemDrive=C:
43 SystemRoot=C:\Windows
44 TEMP=C:\Users\Administrator\AppData\Local\Temp
45 TMP=C:\Users\Administrator\AppData\Local\Temp
46 USERDOMAIN=MS-VMSQSWIJZFNM
47 USERDOMAIN_ROAMINGPROFILE=MS-VMSQSWIJZFNM
48 USERNAME=Administrator
49 USERPROFILE=C:\Users\Administrator
50 
51 windir=C:\Windows
52 0:008> !ProcInfo -mem
53 ---------------------------------------
54 Process Memory
55 WorkingSetSize:    17912 KB       PeakWorkingSetSize:    17916 KB
56 VirtualSize:    -1872282260 KB       PeakVirtualSize:    -1872282260 KB
57 PagefileUsage:      5380 KB       PeakPagefileUsage:      5380 KB
58 ---------------------------------------
59 60 percent of memory is in use.
60 
61 Memory Availability (Numbers in MB)
62 
63                      Total        Avail
64 Physical Memory      16258         6410
65 Page File            18690         7124
66 Virtual Memory    134217727     131818889
67 
68 0:008> !ProcInfo -time
69 ---------------------------------------
70 Process Times
71 Process Started at: 2024 Mar 20 16:22:16.61
72 Kernel CPU time   : 0 days 00:00:00.03
73 User   CPU time   : 0 days 00:00:00.14
74 Total  CPU time   : 0 days 00:00:00.17


    3.5、崩潰轉儲檔案
        A、基礎知識
            我們以前的分析都是實時除錯會話,“實時”意味著我們除錯的是一個正在執行的物理程序,可以訪問程序的所有狀態和控制被除錯程序的執行過程。有時候,這種除錯方式是不可行的,比如:一些生產的機器,這些機器位於鎖定的資料中心,並且進入許可非常嚴格。當然了,還有其他情況。這時候,我們就需要使用“事後除錯”的方法了。
            轉儲崩潰的檔案,有很多種方法和工具,我們主要介紹原書上的一些內容和我知道、並熟悉的一些工具,比如:ProcessExplorer。有其他更好的工具大家有也可以拿出來分享。
            【.dump】命令的引數是一個檔名,表示要轉儲的檔案。該命令還可以帶一系列引數開關,這些引數控制著將哪些程序狀態儲存到轉儲檔案中。當然,儲存程序狀態越多,除錯成功的機率越大。

            我介紹三種方法:
                1)、使用非託管偵錯程式元命令【.dump】轉儲檔案。
                2)、使用 Windows 系統的工作管理員轉儲檔案。
                3)、使用 ProcessExplorer 轉儲檔案。
        B、眼見為實
            除錯原始碼:ExampleCore_3_1_12
            除錯任務:轉儲檔案。
            1)、使用 【.dump】命令轉儲檔案
                1】、NTSD 除錯
                    編譯專案,開啟【Visual Studio 2022 Developer Command Prompt v17.9.4】命令列工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_12\bin\Debug\net8.0\ExampleCore_3_1_12.exe】,開啟偵錯程式視窗。
                    我們使用【g】命令繼續執行偵錯程式,直到偵錯程式輸出【請輸入一個除數:】字樣,我們輸入 0 ,回車繼續執行。
                    

                    偵錯程式出現異常,進入中斷模式。如圖:
                    

                    此時,我們就可以使用【.dump】命令轉儲檔案了。

1 0:000> .dump F:\books\MyTest2.dmp
2 Creating F:\books\MyTest2.dmp - mini user dump
3 Dump successfully written

                    檔案儲存成功,我們重新開啟一個偵錯程式,輸入命令【NTSD -z F:\books\MyTest2.dmp】,我們開始除錯轉儲檔案。需要告訴偵錯程式要除錯的是一個快照,需要使用命令開關 -z,緊跟著轉儲檔案的路徑。
                    

                    開啟新的偵錯程式視窗。

 1 Microsoft (R) Windows Debugger Version 10.0.22621.2428 AMD64
 2 Copyright (c) Microsoft Corporation. All rights reserved.
 3 
 4 
 5 Loading Dump File [F:\books\MyTest2.dmp]
 6 User Mini Dump File: Only registers, stack and portions of memory are available
 7 
 8 Symbol search path is: srv*
 9 Executable search path is:
10 Windows 10 Version 19045 MP (4 procs) Free x64
11 Product: WinNt, suite: SingleUserTS
12 Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
13 Machine Name:
14 Debug session time: Thu Mar 21 13:08:52.000 2024 (UTC + 8:00)
15 System Uptime: not available
16 Process Uptime: 0 days 1:23:35.000
17 ..................................
18 This dump file has an exception of interest stored in it.
19 The stored exception information can be accessed via .ecxr.
20 (3968.2168): Integer divide-by-zero - code c0000094 (first/second chance not available)
21 For analysis of this file, run !analyze -v
22 00007ffc`16d1199c f77de0          idiv    eax,dword ptr [rbp-20h] ss:00000092`50b7e510=00000000

                    在上面的除錯輸出中,第一部分資訊表示偵錯程式載入了一個衛星轉儲檔案。微型轉儲只是眾多轉儲檔案中的一種型別,它包含了有限的程序資訊。
                    接下來,重要的資訊,在轉儲檔案中包含了一個異常,並且異常資訊可以透過【.ecxr】命令來提取。

 1 0:000> .ecxr
 2 rax=000000000000000a rbx=0000009250b7e638 rcx=0000000000000000
 3 rdx=0000000000000000 rsi=0000009250b7e5e8 rdi=0000009250b7e788
 4 rip=00007ffc16d1199c rsp=0000009250b7e4e0 rbp=0000009250b7e530
 5  r8=00000193e5813b50  r9=0000009250b7e4c0 r10=00000fff8ed07bf4
 6 r11=0000009250b7e330 r12=0000009250b7e5a0 r13=0000000000000004
 7 r14=0000000000000001 r15=0000009250b7e700
 8 iopl=0         nv up ei pl nz na pe nc
 9 cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
10 00007ffc`16d1199c f77de0          idiv    eax,dword ptr [rbp-20h] ss:00000092`50b7e510=00000000

                    執行【.ecxr】命令,可以看到與這個異常相關的資訊,例如在發生異常時暫存器的值,透過這些資訊就可以獲取執行緒棧資訊。
                    好了,剩下就是使用除錯命令進行除錯吧。


                2】、Windbg Preview 除錯
                    編譯專案,開啟【Windbg Preview】偵錯程式,依次點選【檔案】---【Launch executable】,載入我們的專案檔案:ExampleCore_3_1_12.exe。進入偵錯程式後,直接【g】命令執行偵錯程式。直到我們的控制檯程式輸出【請輸入一個除數:】,我們輸入一個 0,回車,控制檯程式繼續執行,程式會丟擲一個異常,導致偵錯程式進入中斷模式,就可以開始我們的除錯了。

 1 0:000> g
 2 ModLoad: 00007ffd`2ec10000 00007ffd`2ec42000   C:\Windows\System32\IMM32.DLL
 3 ModLoad: 00007ffc`da2d0000 00007ffc`da329000   C:\Program Files\dotnet\host\fxr\8.0.3\hostfxr.dll
 4 ModLoad: 00007ffc`d63f0000 00007ffc`d6454000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\hostpolicy.dll
 5 ModLoad: 00007ffc`6ddb0000 00007ffc`6e296000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\coreclr.dll
 6 ModLoad: 00007ffd`2e950000 00007ffd`2ea7b000   C:\Windows\System32\ole32.dll
 7 ModLoad: 00007ffd`2e4c0000 00007ffd`2e813000   C:\Windows\System32\combase.dll
 8 ModLoad: 00007ffd`2f8a0000 00007ffd`2f96d000   C:\Windows\System32\OLEAUT32.dll
 9 ModLoad: 00007ffd`2df10000 00007ffd`2df92000   C:\Windows\System32\bcryptPrimitives.dll
10 (3fdc.c48): Unknown exception - code 04242420 (first chance)
11 ModLoad: 00007ffc`6cb10000 00007ffc`6d79c000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Private.CoreLib.dll
12 ModLoad: 00007ffc`6c950000 00007ffc`6cb09000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\clrjit.dll
13 ModLoad: 00007ffd`2dff0000 00007ffd`2e002000   C:\Windows\System32\kernel.appcore.dll
14 ModLoad: 00000283`bb770000 00000283`bb778000   E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_12\bin\Debug\net8.0\ExampleCore_3_1_12.dll
15 ModLoad: 00000283`bb780000 00000283`bb78e000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Runtime.dll
16 ModLoad: 00007ffc`da2a0000 00007ffc`da2c8000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Console.dll
17 ModLoad: 00007ffd`0b5f0000 00007ffd`0b602000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Threading.dll
18 ModLoad: 00000283`bb790000 00000283`bb798000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Text.Encoding.Extensions.dll
19 ModLoad: 00007ffd`06c70000 00007ffd`06c85000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.3\System.Runtime.InteropServices.dll
20 ModLoad: 00007ffc`fd310000 00007ffc`fd53e000   C:\Windows\SYSTEM32\icu.dll
21 (3fdc.c48): Integer divide-by-zero - code c0000094 (first chance)(說明系統丟擲了一個除以0的異常)
22 First chance exceptions are reported before any exception handling.
23 This exception may be expected and handled.
24 *** WARNING: Unable to verify checksum for E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_12\bin\Debug\net8.0\ExampleCore_3_1_12.dll
25 ExampleCore_3_1_12!ExampleCore_3_1_12.Program.Main+0x6c:
26 00007ffc`0e3a199c f77de0          idiv    eax,dword ptr [rbp-20h] ss:00000095`b617ec40=00000000

                    同時偵錯程式也會開啟【Program】視窗,顯示我們程式的原始碼,並在出錯的行暫停,如圖:
                    

                    此時,我們就可以使用【.dump】命令轉儲檔案了。

1 0:000> .dump F:\books\MyTest.dmp
2 Creating F:\books\MyTest.dmp - mini user dump
3 Dump successfully written

                    dump 命令的引數是一個檔名,表示轉儲的檔案。我們有了轉儲檔案,現在就開始除錯這個轉儲檔案。
                    我們可以開啟一個新的【Windbg】,也可以退出當前的重新載入。依次點選【檔案】---【Open dump file】,載入我們前面儲存的快照檔案:MyTest.dmp,點選【open】按鈕開啟偵錯程式。

 1 0:000> .dump F:\books\MyTest.dmp
 2 Creating F:\books\MyTest.dmp - mini user dump
 3 Dump successfully written
 4 windbg> q
 5 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\atlmfc.natvis'
 6 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\ObjectiveC.natvis'
 7 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\concurrency.natvis'
 8 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\cpp_rest.natvis'
 9 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\stl.natvis'
10 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\Windows.Data.Json.natvis'
11 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\Windows.Devices.Geolocation.natvis'
12 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\Windows.Devices.Sensors.natvis'
13 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\Windows.Media.natvis'
14 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\windows.natvis'
15 NatVis script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\Visualizers\winrt.natvis'
16 JavaScript script unloaded from 'C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\ApiExtension\CodeFlow.js'
17 
18 ************* Preparing the environment for Debugger Extensions Gallery repositories **************
19    ExtensionRepository : Implicit
20    UseExperimentalFeatureForNugetShare : false
21    AllowNugetExeUpdate : false
22    NonInteractiveNuget : true
23    AllowNugetMSCredentialProviderInstall : false
24    AllowParallelInitializationOfLocalRepositories : true
25 
26    EnableRedirectToV8JsProvider : false
27 
28    -- Configuring repositories
29       ----> Repository : LocalInstalled, Enabled: true
30       ----> Repository : UserExtensions, Enabled: true
31 
32 >>>>>>>>>>>>> Preparing the environment for Debugger Extensions Gallery repositories completed, duration 0.000 seconds
33 
34 ************* Waiting for Debugger Extensions Gallery to Initialize **************
35 
36 >>>>>>>>>>>>> Waiting for Debugger Extensions Gallery to Initialize completed, duration 0.032 seconds
37    ----> Repository : UserExtensions, Enabled: true, Packages count: 0
38    ----> Repository : LocalInstalled, Enabled: true, Packages count: 41
39 
40 Microsoft (R) Windows Debugger Version 10.0.27553.1004 AMD64
41 Copyright (c) Microsoft Corporation. All rights reserved.
42 
43 
44 Loading Dump File [F:\Books\MyTest.dmp]
45 User Mini Dump File: Only registers, stack and portions of memory are available
46 
47 
48 ************* Path validation summary **************
49 Response                         Time (ms)     Location
50 Deferred                                       srv*
51 Symbol search path is: srv*
52 Executable search path is: 
53 Windows 10 Version 19045 MP (4 procs) Free x64
54 Product: WinNt, suite: SingleUserTS
55 Edition build lab: 19041.1.amd64fre.vb_release.191206-1406
56 Debug session time: Thu Mar 21 11:27:02.000 2024 (UTC + 8:00)
57 System Uptime: 0 days 1:23:42.004
58 Process Uptime: 0 days 0:08:39.000
59 .......................................................
60 This dump file has an exception of interest stored in it.
61 The stored exception information can be accessed via .ecxr.
62 (3fdc.c48): Integer divide-by-zero - code c0000094 (first/second chance not available)
63 For analysis of this file, run !analyze -v
64 00007ffc`0e3a199c f77de0          idiv    eax,dword ptr [rbp-20h] ss:00000095`b617ec40=00000000

                    很簡單,就不多說了。


            2)、使用 Windows 系統的工作管理員轉儲檔案。
                這個很簡單,直接上圖看效果。我們開啟【工作管理員】,在【程序】標籤裡,隨便找一個程序,點選左側 > 小於號圖示,顯示摺疊的內容,我這裡選擇的是【Visual Studio】。
                

                  

                  

                  很簡單,話不多說。

            3)、使用 ProcessExplorer 轉儲檔案
                編譯專案,找到程式的可執行檔案,我們檔名是:ExampleCore_3_1_12.exe,雙擊執行。控制檯程式輸出:請輸入一個除數。我們開啟【ProcessExplorer】64位版本的。在右側過濾框中輸入 ExampleCore_3_1_12 ,查詢出我們程式的程序。
                

                 

                 此時,我們在專案程序上點選右鍵【Create Dump】,該選單有兩個子選單,分別是:Create Minidump 和 Create full dump,這兩個選單的區別就是,Minidump 的檔案包含的程序資訊有限,full dump 包含完整程序資訊。


四、總結
    這篇文章的第三部分終於寫完了。做程式設計師的,不能太懶惰,只有所有程式碼自己都寫了,都測試了,才會明白裡面發生的事情。Net 高階除錯這條路,也剛剛起步,還有很多要學的地方。皇天不負有心人,努力,不辜負自己,我相信付出就有回報,再者說,學習的過程,有時候,雖然很痛苦,但是,學有所成,學有所懂,這個開心的感覺還是不可言喻的。不忘初心,繼續努力。做自己喜歡做的,開心就好。

相關文章