Net 高階偵錯之七:執行緒操作相關命令介紹

2023-11-10 12:00:22

一、簡介
    今天是《Net 高階偵錯》的第七篇文章。上一篇文章我們說了值型別,參照型別,陣列等的記憶體表現形式。有了這個基礎,我們可以更好的瞭解我們的程式在執行時的狀態,記憶體裡有什麼東西,它們的結構組成是什麼樣子的,對我們偵錯程式是更有幫助的。今天,我們要說一些和執行緒有關的話題,雖然和執行緒相關,但是不是多執行緒的知識,不是執行緒安全的知識。今天我們討論的是如何檢視執行緒,它的表現形式,以及執行緒的呼叫棧,呼叫棧,又分為託管執行緒的呼叫棧和非託管執行緒的呼叫棧,這些也是我們高階偵錯必須掌握的。有了這些基礎,我們就知道了程式的開始端點,偵錯的起點我們就找到了。雖然這些都是基礎,如果這些掌握不好,以後的高階偵錯的道路,也不好走。當然了,第一次看視訊或者看書,是很迷糊的,不知道如何操作,還是那句老話,一遍不行,那就再來一遍,還不行,那就再來一遍,俗話說的好,書讀千遍,其意自現。
     如果在沒有說明的情況下,所有程式碼的測試環境都是 Net Framewok 4.8,但是,有時候為了檢視原始碼,可能需要使用 Net Core 的專案,我會在專案章節裡進行說明。好了,廢話不多說,開始我們今天的偵錯工作。

       偵錯環境我需要進行說明,以防大家不清楚,具體情況我已經羅列出來。
          作業系統:Windows Professional 10
          偵錯工具:Windbg Preview(可以去Microsoft Store 去下載)
          開發工具:Visual Studio 2022
          Net 版本:Net Framework 4.8
          CoreCLR原始碼:原始碼下載

二、基礎知識
    
    1、執行緒類相關介紹
        1.1、簡介
            在高階偵錯的過程中,很難不和 執行緒、執行緒棧 打交道,所以好好的學習並掌握有關執行緒操作的命令是很有必要的。

    2、獲取 執行緒列表 的命令
        2.1、檢視執行緒列表。
            可以使用【!t】命令獲取所有的託管執行緒。

        2.2、使用 Net 7.0 檢視執行緒列表
            可以使用【!t】命令獲取所有的託管執行緒,如果我們想檢視 CLR 的執行緒物件的結構就只能使用開源版本了,這裡使用Net 7.0。

    3、檢視非託管執行緒棧
        Windbg 是隨 Windows 成長起來的非託管偵錯程式,它自帶的命令只能檢視非託管呼叫棧,因為 C# 中的執行緒棧是託管函數,而託管函數是一種執行時編譯的,所以這個命令往往看不到託管部分。

        3.1、使用 k 命令檢視非託管執行緒棧
            【k】命令可以檢視執行緒棧,但是麼有辦法展示託管函數,作為補充,可以使用【!clrstack】命令。

        3.2、使用 kb 命令檢視執行緒棧。
            很多時候我們需要獲取非託管函數的引數,這個時候我們可以使用【kb】命令。

        3.3、檢視託管函數棧
            SOS 提供了一個專門檢視託管函數呼叫棧的命令,畢竟只有 JIT更熟悉託管函數,也知道編譯後的機器碼放在什麼位置。
            這個命令就是【!clrstack】。
            !clrstack -a:這個命令表示將執行緒棧中的所有區域性變數和引數全部輸出。
            !clrstack -p:這個命令表示將執行緒棧中的引數全部輸出。
            !clrstack -l:這個命令表示將執行緒棧中的所有區域性變數全部輸出。

            我們還可以檢視所有託管執行緒棧,可以使用【~*e】命令。

        3.4、檢視託管和非託管合體
            使用【!dumpstack】命令檢視託管和非託管的執行緒棧

        3.5、執行所有執行緒的 DumpStack。
            如果我們想檢視所有執行緒的執行緒棧,可以使用【!EEStack】,也可以使用【~*e !dumpstack】,結果是一樣的。
三、測試過程
    廢話不多說,這一節是具體的偵錯操作的過程,又可以說是眼見為實的過程,在開始之前,我還是要囉嗦兩句,這一節分為兩個部分,第一部分是測試的原始碼部分,沒有程式碼,當然就談不上測試了,偵錯必須有載體。第二部分就是根據具體的程式碼來證實我們學到的知識,是具體的眼見為實。

    1、測試原始碼
        1.1、Example_7_1_1

 1 namespace Example_7_1_1
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             int a = 10;
 8             int b = 11;
 9             Test(12);
10             Console.ReadLine();
11         }
12 
13         private static void Test(int c)
14         {
15             Task.Run(() => { Run1(); });
16             Task.Run(() => { Run2(); });
17             Task.Run(() => { Run3(); });
18         }
19 
20         private static void Run1()
21         {
22             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 正在執行");
23             Console.ReadLine();
24             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 結束執行");
25         }
26 
27         private static void Run2()
28         {
29             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 正在執行");
30             Console.ReadLine();
31             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 結束執行");
32         }
33 
34         private static void Run3()
35         {
36             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 正在執行");
37             Console.ReadLine();
38             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 結束執行");
39         }
40     }
41 }
View Code


        1.2、Example_7_1_2(特別說明,這個專案是 Net 7.0)

 1 namespace Example_7_1_2
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Console.WriteLine("Hello, World!");
 8             Debugger.Break();
 9         }
10     }
11 }
View Code


    2、眼見為實
        專案的所有操作都是一樣的,所以就在這裡說明一下,但是每個測試例子,都需要重新啟動,並載入相應的應用程式,載入方法都是一樣的。流程如下:我們編譯專案,開啟 Windbg,點選【檔案】----》【launch executable】附加程式,開啟偵錯程式的介面,程式已經處於中斷狀態。我們需要使用【g】命令,繼續執行程式,然後到達指定地點停止後,我們可以點選【break】按鈕,就可以偵錯程式了。有時候可能需要切換到主執行緒,可以使用【~0s】命令。

        2.1、使用 【!t】命令檢視程序中有多少個託管執行緒。
              
測試原始碼:Example_7_1_1

 1 0:012> !t
 2 ThreadCount:      6
 3 UnstartedThread:  0
 4 BackgroundThread: 5
 5 PendingThread:    0
 6 DeadThread:       0
 7 Hosted Runtime:   no
 8                                                                          Lock  
 9        ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
10    0    1 2ef4 00c73930     2a020 Preemptive  02B94F38:00000000 00c6d758 1     MTA 
11    5    2 39c0 00cb0728     2b220 Preemptive  00000000:00000000 00c6d758 0     MTA (Finalizer) 
12    9    3 17dc 00cdc010   3029220 Preemptive  02B9C6C8:00000000 00c6d758 0     MTA (Threadpool Worker) 
13   10    4  a18 00cdc9b8   3029220 Preemptive  02B98350:00000000 00c6d758 0     MTA (Threadpool Worker) 
14   11    5 31d0 00cdd360   3029220 Preemptive  02B9A350:00000000 00c6d758 0     MTA (Threadpool Worker) 
15   13    6  9a0 00ce05c0   1029220 Preemptive  02B9E1E8:00000000 00c6d758 0     MTA (Threadpool Worker) 

              ThreadCount:有多少個託管執行緒,這個程序裡面有6個。
              UnstartedThread:已經建立,但是還沒有使用的執行緒,當前數量是0。
              BackgroundThread:後臺執行緒的數量,這個程序裡面有5個
              PendingThread:阻塞的執行緒的數量,當前這個程序是0個阻塞的執行緒。
              DeadThread:當一個執行緒完成任務,但是還沒有被回收,這個階段的執行緒就是死執行緒,也就是說這個執行緒物件底層的資料結構的 OSID 已經銷燬。

              以上就是介紹的主要名稱,下面接著介紹,列表的每一項。我們使用 C# Thread 型別宣告一個執行緒的時候,其實在作業系統和CLR都有一個資料結構相對應,有了 OSID我們才可以在工作管理員中看到執行緒物件。

              第一列,沒有標題,是 WindbgThreadId,Windbg 自己的給 Thread 打了一個標記,便於以後使用,也可以區分託管執行緒和非託管執行緒。
              第二列 ID:是託管執行緒,也就是我們 Thread 型別的識別符號 Id,就是 這段程式碼的值:Environment.CurrentManagedThreadId
              第三列 OSID:作業系統執行緒的 ID,
              第四列 ThreadOBJ:CLR 底層的 Thread 執行緒物件,可以使用【dp】命令觀察其中的內容,我們檢視託管執行緒 ID=3 的【00cdc010】內容,紅色標註就是託管執行緒的ID,就是3。

1 0:012> dp 00cdc010
2 00cdc010  72074bd4 03029220 00000000 055ff680
3 00cdc020  00000000 00c6d758 00000000 00000003
4 00cdc030  00cdc034 00cdc034 00cdc034 00000000
5 00cdc040  00000000 baad0000 00c6ed50 0094f000
6 00cdc050  02b9c6c8 02b9dfe8 00003d10 00000000
7 00cdc060  00000000 00000000 00000000 00000000
8 00cdc070  00000000 baadf00d 70ad2c60 00cdc850
9 00cdc080  00000000 00000000 00000000 00000000

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

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

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

        2.2、如何檢視 CLR Thread 的結構,也就是檢視 ThreadOBJ 的結構。
              測試原始碼:Example_7_1_2(Net 7.0專案
              如果我們想在 Net Framework 環境下檢視 CLR 執行緒物件的結構是很難的,因為他是不開源的,所以我們只能新建 Net 7.0 的專案。
              輸出所有的執行緒列表。

 1 0:000> !t
 2 ThreadCount:      3
 3 UnstartedThread:  0
 4 BackgroundThread: 2
 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      624 00000199DFD0CAE0    2a020 Preemptive  00000199E440AD60:00000199E440C750 00000199dfd02dd0 -00001 MTA 
11    5    2     1344 00000199DFD51DD0    21220 Preemptive  0000000000000000:0000000000000000 00000199dfd02dd0 -00001 Ukn (Finalizer) 
12    6    3     3b40 000001DA763B15E0    2b220 Preemptive  0000000000000000:0000000000000000 00000199dfd02dd0 -00001 MTA 

              然後,我們使用【dt】命令,檢視執行緒的結構。

  1 0:000> dt coreclr!Thread 00000199DFD0CAE0
  2    +0x000 m_stackLocalAllocator : (null) 
  3    =00007ffd`027a8af0 m_DetachCount    : 0n0
  4    =00007ffd`027a8af4 m_ActiveDetachCount : 0n0
  5    +0x008 m_State          : Volatile<enum Thread::ThreadState>
  6    +0x00c m_fPreemptiveGCDisabled : Volatile<unsigned long>
  7    +0x010 m_pFrame         : 0x0000008a`24f7e478 Frame
  8    +0x018 m_pDomain        : 0x00000199`dfd02dd0 AppDomain
  9    +0x020 m_ThreadId       : 1
 10    +0x028 m_pHead          : 0x00000199`dfd0cb10 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           : 0x0000008a`24c20000 _NT_TIB
 16    +0x0a0 m_pRCWStack      : 0x00000199`dfd0d710 RCWStackHeader
 17    +0x0a8 m_ThreadTasks    : 0 (No matching name)
 18    +0x0ac m_StateNC        : 100 ( TSNC_ExistInThreadStore )
 19    +0x0b0 m_dwForbidSuspendThread : Volatile<long>
 20    +0x0b4 m_dwHashCodeSeed : 0xdfca504a
 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      : 0x00000199`dfd0d210 _CONTEXT
 30    +0x0f0 m_pPendingTypeLoad : (null) 
 31    +0x0f8 m_Link           : SLink
 32    +0x100 m_dwLastError    : 0
 33    +0x108 m_CacheStackBase : 0x0000008a`24f80000 Void
 34    +0x110 m_CacheStackLimit : 0x0000008a`24e00000 Void
 35    +0x118 m_CacheStackSufficientExecutionLimit : 0x0000008a`24e20000
 36    +0x120 m_CacheStackStackAllocNonRiskyExecutionLimit : 0x0000008a`24e80000
 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`000001e0 Void
 45    +0x1a0 m_ThreadHandleForClose : 0xffffffff`ffffffff Void
 46    +0x1a8 m_ThreadHandleForResume : 0xffffffff`ffffffff Void
 47    +0x1b0 m_WeOwnThreadHandle : 0n1
 48    +0x1b8 m_OSThreadId     : 0x624
 49    +0x1c0 m_ExposedObject  : 0x00000199`dfc411f8 OBJECTHANDLE__
 50    +0x1c8 m_StrongHndToExposedObject : 0x00000199`dfc413f8 OBJECTHANDLE__
 51    +0x1d0 m_Priority       : 0x80000000
 52    +0x1d4 m_ExternalRefCount : 1
 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_workerThreadPoolCompletionCount : 0
 65    =00007ffd`027b3cc0 s_workerThreadPoolCompletionCountOverflow : 0
 66    +0x448 m_ioThreadPoolCompletionCount : 0
 67    =00007ffd`027b3cc8 s_ioThreadPoolCompletionCountOverflow : 0
 68    +0x44c m_monitorLockContentionCount : 0
 69    =00007ffd`027a8ad8 s_monitorLockContentionCountOverflow : 0
 70    +0x450 m_PreventAsync   : 0n0
 71    =00007ffd`027a6204 m_DebugWillSyncCount : 0n-1
 72    +0x458 m_pSavedRedirectContext : (null) 
 73    +0x460 m_pOSContextBuffer : (null) 
 74    +0x468 m_ThreadLocalBlock : ThreadLocalBlock
 75    +0x490 m_tailCallTls    : TailCallTls
 76    +0x4a0 m_dwAVInRuntimeImplOkayCount : 0
 77    +0x4a8 m_pExceptionDuringStartup : (null) 
 78    +0x4b0 m_debuggerActivePatchSkipper : VolatilePtr<DebuggerPatchSkip,DebuggerPatchSkip *>
 79    +0x4b8 m_fAllowProfilerCallbacks : 0n1
 80    +0x4c0 m_pIOCompletionContext : 0x00000199`dfd0da40 Void
 81    +0x4c8 m_dwThreadHandleBeingUsed : Volatile<long>
 82    =00007ffd`027a8ad0 s_fCleanFinalizedThread : 0n0
 83    +0x4d0 m_pCreatingThrowableForException : (null) 
 84    +0x4d8 m_dwIndexClauseForCatch : 0
 85    +0x4e0 m_sfEstablisherOfActualHandlerFrame : StackFrame
 86    +0x4e8 DebugBlockingInfo : ThreadDebugBlockingInfo
 87    +0x4f0 m_fDisableComObjectEagerCleanup : 0
 88    +0x4f1 m_fHasDeadThreadBeenConsideredForGCTrigger : 0
 89    +0x4f4 m_random         : CLRRandom
 90    +0x5e0 m_uliInitializeSpyCookie : _ULARGE_INTEGER 0x0
 91    +0x5e8 m_fInitializeSpyRegistered : 0
 92    +0x5f0 m_pLastSTACtxCookie : (null) 
 93    +0x5f8 m_fGCSpecial     : 0
 94    +0x600 m_pGCFrame       : 0x0000008a`24f7e790 GCFrame
 95    +0x608 m_wCPUGroup      : 0
 96    +0x610 m_pAffinityMask  : 0
 97    +0x618 m_pAllLoggedTypes : (null) 
 98    +0x620 m_gcModeOnSuspension : Volatile<unsigned long>
 99    +0x624 m_activityId     : _GUID {00000000-0000-0000-0000-000000000000}
100    +0x634 m_HijackReturnKind : ff ( RT_Illegal )
101    =00007ffd`027a8b40 dead_threads_non_alloc_bytes : 0
102    +0x638 m_currentPrepareCodeConfig : (null) 
103    +0x640 m_isInForbidSuspendForDebuggerRegion : 0
104    =00007ffd`027ba3d0 s_pfnQueueUserAPC2Proc : (null) 
105    +0x641 m_hasPendingActivation : 0
View Code

              +0x020 m_ThreadId : 1表示託管執行緒的ID。因為我列印的是 ThreadOBJ 為00000199DFD0CAE0 執行緒的結構。m 表示Management 託管的。
              我們可以繼續看看 GC Alloc Context,在輸出的結構中有這樣一行程式碼:+0x058 m_alloc_context : gc_alloc_context,藍色的字型,可以點選,相當於執行【dx】命令。

1 0:000> dx -r1 (*((coreclr!gc_alloc_context *)0x199dfd0cb38))
2 (*((coreclr!gc_alloc_context *)0x199dfd0cb38))                 [Type: gc_alloc_context]
3     [+0x000] alloc_ptr        : 0x199e440ad60 : 0x0 [Type: unsigned char *]
4     [+0x008] alloc_limit      : 0x199e440c750 : 0x0 [Type: unsigned char *]
5     [+0x010] alloc_bytes      : 50920 [Type: __int64](小物件堆的大小)
6     [+0x018] alloc_bytes_uoh  : 17416 [Type: __int64](大物件堆的大小)
7     [+0x020] gc_reserved_1    : 0x0 [Type: void *]
8     [+0x028] gc_reserved_2    : 0x0 [Type: void *]
9     [+0x030] alloc_count      : 0 [Type: int]


        2.3、使用 Windbg 的【k】命令檢視非託管函數。
              測試原始碼:Example_7_1_1
              這裡操作需要切換到主執行緒上,執行命令【~0s】,然後使用【k】命令。

 1 0:010> ~0s
 2 eax=00000000 ebx=00000090 ecx=00000000 edx=00000000 esi=00f3f444 edi=00000000
 3 eip=77c310fc esp=00f3f32c ebp=00f3f38c iopl=0         nv up ei pl nz na po nc
 4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
 5 ntdll!NtReadFile+0xc:
 6 77c310fc c22400          ret     24h
 7 
 8 
 9 0:000> k
10  # ChildEBP RetAddr      
11 00 00f3f38c 75dbf25c     ntdll!NtReadFile+0xc
12 01 00f3f38c 70f79b71     KERNELBASE!ReadFile+0xec
13 02 00f3f3fc 716ab275     mscorlib_ni+0x4b9b71
14 03 00f3f428 716ab17b     ...
15 WARNING: Frame IP not in any known module. Following frames may be wrong.(無法顯示託管函數)
16 09 00f3f4b8 71faf036     0x2e9088e
17 0a 00f3f4c4 71fb22da     clr!CallDescrWorkerInternal+0x34
18 0b 00f3f518 71fb859b     clr!CallDescrWorkerWithHandler+0x6b
19 0c 00f3f588 7215b11b     clr!MethodDescCallSite::CallTargetWorker+0x16a
20 0d 00f3f6ac 7215b7fa     clr!RunMain+0x1b3
21 0e 00f3f918 7215b727     clr!Assembly::ExecuteMainMethod+0xf7
22 0f 00f3fdfc 7215b8a8     clr!SystemDomain::ExecuteMainMethod+0x5ef
23 10 00f3fe54 7215b9ce     clr!ExecuteEXE+0x4c
24 11 00f3fe94 72157305     clr!_CorExeMainInternal+0xdc
25 12 00f3fed0 7275fa84     clr!_CorExeMain+0x4d
26 13 00f3ff08 7285e81e     mscoreei!_CorExeMain+0xd6
27 14 00f3ff18 72864338     MSCOREE!ShellShim__CorExeMain+0x9e
28 15 00f3ff30 7636f989     MSCOREE!_CorExeMain_Exported+0x8
29 16 00f3ff30 77c27084     KERNEL32!BaseThreadInitThunk+0x19
30 17 00f3ff8c 77c27054     ntdll!__RtlUserThreadStart+0x2f
31 18 00f3ff9c 00000000     ntdll!_RtlUserThreadStart+0x1b

              但是我們可以使用 SOS的【!clrstack】命令顯示託管函數。

 1 0:000> !clrstack
 2 OS Thread Id: 0xc08 (0)
 3 Child SP       IP Call Site
 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
 6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(..., Int32, Int32 ByRef, IntPtr)
 7 00f3f410 716ab275 System.IO.__ConsoleStream.ReadFileNative(.., Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205]
 8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
 9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
13 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
14 00f3f62c 71faf036 [GCFrame: 00f3f62c] 


        2.4、使用【kb】命令檢視執行緒棧,提取 ntdll!NtReadFile 的第一個引數。
              測試原始碼:Example_7_1_1              

 1 0:000> kb
 2  # ChildEBP RetAddr      Args to Child              
 3 00 00f3f38c 75dbf25c     00000090 00000000 00000000 ntdll!NtReadFile+0xc
 4 01 00f3f38c 70f79b71     00000090 02f35d18 00000100 KERNELBASE!ReadFile+0xec
 5 02 00f3f3fc 716ab275     00000000 00f3f444 00000100 mscorlib_ni+0x4b9b71
 6 03 00f3f428 716ab17b     00f3f444 00000000 00000001 mscorlib_ni!System.IO.__ConsoleStream.ReadFileNative+0x89 [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205] 
 7 04 00f3f454 70f5e6a3     00000100 00000000 02f3a210 mscorlib_ni!System.IO.__ConsoleStream.Read+0x9f [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134] 
 8 05 00f3f46c 70f5eb5b     00000001 00000000 00f3f55c mscorlib_ni!System.IO.StreamReader.ReadBuffer+0x33 [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595] 
 9 06 00f3f488 717f3786     00000000 00f3f4d0 00f3f4a0 mscorlib_ni!System.IO.StreamReader.ReadLine+0xe3 [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748] 
10 07 00f3f498 71651845     00f3f4b8 02e9088e 00000000 mscorlib_ni!System.IO.TextReader.SyncTextReader.ReadLine+0x1a [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363] 
11 08 00f3f4a0 02e9088e     00000000 0000000b 0000000a mscorlib_ni!System.Console.ReadLine+0x15 [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984] 
12 WARNING: Frame IP not in any known module. Following frames may be wrong.
13 09 00f3f4b8 71faf036     0116a628 00f3f518 71fb22da 0x2e9088e
14 0a 00f3f4c4 71fb22da     00f3f55c 00f3f508 720a23d0 clr!CallDescrWorkerInternal+0x34
15 0b 00f3f518 71fb859b     00f3f570 02f324bc 00000000 clr!CallDescrWorkerWithHandler+0x6b
16 0c 00f3f588 7215b11b     00f3f664 6a38df42 02d04d78 clr!MethodDescCallSite::CallTargetWorker+0x16a
17 0d 00f3f6ac 7215b7fa     00f3f6f0 00000000 6a38d0f6 clr!RunMain+0x1b3
18 0e 00f3f918 7215b727     00000000 6a38d412 00b70000 clr!Assembly::ExecuteMainMethod+0xf7
19 0f 00f3fdfc 7215b8a8     6a38d7ba 00000000 00000000 clr!SystemDomain::ExecuteMainMethod+0x5ef
20 10 00f3fe54 7215b9ce     6a38d77a 00000000 721572e0 clr!ExecuteEXE+0x4c
21 11 00f3fe94 72157305     6a38d73e 00000000 721572e0 clr!_CorExeMainInternal+0xdc
22 12 00f3fed0 7275fa84     8ee8ef1f 72864330 7275fa20 clr!_CorExeMain+0x4d
23 13 00f3ff08 7285e81e     72864330 72750000 00f3ff30 mscoreei!_CorExeMain+0xd6
24 14 00f3ff18 72864338     72864330 7636f989 00c95000 MSCOREE!ShellShim__CorExeMain+0x9e
25 15 00f3ff30 7636f989     00c95000 7636f970 00f3ff8c MSCOREE!_CorExeMain_Exported+0x8
26 16 00f3ff30 77c27084     00c95000 281a60a3 00000000 KERNEL32!BaseThreadInitThunk+0x19
27 17 00f3ff8c 77c27054     ffffffff 77c462ae 00000000 ntdll!__RtlUserThreadStart+0x2f
28 18 00f3ff9c 00000000     00000000 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b

              ntdll!NtReadFile 方法的第一個引數是一個 Handle,我們可以使用【!handle】命令+ f 引數顯示詳情。Console.ReadLine()方法底層就是 File 的控制程式碼。

 1 0:000> !handle 00000090 f
 2 Handle 90
 3   Type             File
 4   Attributes       0
 5   GrantedAccess    0x12019f:
 6          ReadControl,Synch
 7          Read/List,Write/Add,Append/SubDir/CreatePipe,ReadEA,WriteEA,ReadAttr,WriteAttr
 8   HandleCount      2
 9   PointerCount     65531
10   No Object Specific Information available


        2.5、我們使用【!clrstack】命令檢視託管函數。
              測試原始碼:Example_7_1_1
              !clrstack 執行效果

 1 0:000> !clrstack
 2 OS Thread Id: 0xc08 (0)
 3 Child SP       IP Call Site
 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(..., Byte*, Int32, Int32 ByRef, IntPtr)
 6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(... Byte*, Int32, Int32 ByRef, IntPtr)
 7 00f3f410 716ab275 System.IO.__ConsoleStream.ReadFileNative(.. Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205]
 8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
 9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
13 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
14 00f3f62c 71faf036 [GCFrame: 00f3f62c] 

              !clrstack -a:顯示所有引數和區域性變數,關注紅色標註的。

 1 0:000> !clrstack -a
 2 OS Thread Id: 0xc08 (0)
 3 Child SP       IP Call Site
 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
 6     PARAMETERS:
 7         <no data>
 8         <no data>
 9         <no data>
10         <no data>
11         <no data>
12 ...(內容太多,就省略了,也沒用)
13 
14 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\..\Example_7_1_1\Program.cs @ 13]
15     PARAMETERS:(引數)
16         args (0x00f3f4b4) = 0x02f324bc(引數)
17     LOCALS:(區域性變數)
18         0x00f3f4b0 = 0x0000000a
19         0x00f3f4ac = 0x0000000b
20 
21 00f3f62c 71faf036 [GCFrame: 00f3f62c] 


              !clrstack -l:顯示所有區域性變數,關注紅色標註的。

 1 0:000> !clrstack -l
 2 OS Thread Id: 0xc08 (0)
 3 Child SP       IP Call Site
 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
 6 ...(內容太多,就省略了,也沒用)
 7 
 8 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
 9     LOCALS:(只有區域性變數)
10         0x00f3f4b0 = 0x0000000a
11         0x00f3f4ac = 0x0000000b
12 
13 00f3f62c 71faf036 [GCFrame: 00f3f62c] 


              !clrstack -p:顯示所有引數,關注紅色標註的。

 1 0:000> !clrstack -p
 2 OS Thread Id: 0xc08 (0)
 3 Child SP       IP Call Site
 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
 6     PARAMETERS:
 7         <no data>
 8         <no data>
 9         <no data>
10         <no data>
11         <no data>
12 
13 ...(內容太多,就省略了,也沒用)
14 
15 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
16     PARAMETERS:(只有引數)
17         args (0x00f3f4b4) = 0x02f324bc
18 
19 00f3f62c 71faf036 [GCFrame: 00f3f62c] 


        2.6、使用【~*e】檢視所有託管執行緒棧。
              測試原始碼:Example_7_1_1
              ~ 命令輸出所有執行緒列表。

 1 0:000> ~
 2 .  0  Id: 2074.c08 Suspend: 1 Teb: 00c98000 Unfrozen
 3    1  Id: 2074.2cdc Suspend: 1 Teb: 00c9b000 Unfrozen
 4    2  Id: 2074.3bec Suspend: 1 Teb: 00c9e000 Unfrozen
 5    3  Id: 2074.1a34 Suspend: 1 Teb: 00ca1000 Unfrozen
 6    4  Id: 2074.3858 Suspend: 1 Teb: 00ca4000 Unfrozen
 7    5  Id: 2074.379c Suspend: 1 Teb: 00ca7000 Unfrozen
 8    6  Id: 2074.3088 Suspend: 1 Teb: 00caa000 Unfrozen
 9    7  Id: 2074.2c54 Suspend: 1 Teb: 00cad000 Unfrozen
10    8  Id: 2074.20dc Suspend: 1 Teb: 00cb0000 Unfrozen
11    9  Id: 2074.2014 Suspend: 1 Teb: 00cb3000 Unfrozen
12 # 10  Id: 2074.187c Suspend: 1 Teb: 00cc2000 Unfrozen
13   11  Id: 2074.2b64 Suspend: 1 Teb: 00cb9000 Unfrozen
14   12  Id: 2074.1358 Suspend: 1 Teb: 00cbc000 Unfrozen
15   13  Id: 2074.6e8 Suspend: 1 Teb: 00cbf000 Unfrozen

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

 1 0:000> ~*
 2 .  0  Id: 2074.c08 Suspend: 1 Teb: 00c98000 Unfrozen
 3       Start: 00402bca
 4       Priority: 0  Priority class: 32  Affinity: f
 5    1  Id: 2074.2cdc Suspend: 1 Teb: 00c9b000 Unfrozen
 6       Start: ntdll!TppWorkerThread (77c10c90)
 7       Priority: 0  Priority class: 32  Affinity: f
 8    2  Id: 2074.3bec Suspend: 1 Teb: 00c9e000 Unfrozen
 9       Start: ntdll!TppWorkerThread (77c10c90)
10       Priority: 0  Priority class: 32  Affinity: f
11    3  Id: 2074.1a34 Suspend: 1 Teb: 00ca1000 Unfrozen
12       Start: ntdll!TppWorkerThread (77c10c90)
13       Priority: 0  Priority class: 32  Affinity: f
14    4  Id: 2074.3858 Suspend: 1 Teb: 00ca4000 Unfrozen
15       Start: clr!DebuggerRCThread::ThreadProcStatic (721565d0)
16       Priority: 0  Priority class: 32  Affinity: f
17    5  Id: 2074.379c Suspend: 1 Teb: 00ca7000 Unfrozen
18       Start: clr!Thread::intermediateThreadProc (72074b60)
19       Priority: 2  Priority class: 32  Affinity: f
20    6  Id: 2074.3088 Suspend: 1 Teb: 00caa000 Unfrozen
21       Start: combase!CRpcThreadCache::RpcWorkerThreadEntry (7731bcc0)
22       Priority: 0  Priority class: 32  Affinity: f
23    7  Id: 2074.2c54 Suspend: 1 Teb: 00cad000 Unfrozen
24       Start: ntdll!TppWorkerThread (77c10c90)
25       Priority: 0  Priority class: 32  Affinity: f
26    8  Id: 2074.20dc Suspend: 1 Teb: 00cb0000 Unfrozen
27       Start: ntdll!TppWorkerThread (77c10c90)
28       Priority: 0  Priority class: 32  Affinity: f
29    9  Id: 2074.2014 Suspend: 1 Teb: 00cb3000 Unfrozen
30       Start: clr!Thread::intermediateThreadProc (72074b60)
31       Priority: 0  Priority class: 32  Affinity: f
32 # 10  Id: 2074.187c Suspend: 1 Teb: 00cc2000 Unfrozen
33       Start: ntdll!DbgUiRemoteBreakin (77c6cee0)
34       Priority: 0  Priority class: 32  Affinity: f
35   11  Id: 2074.2b64 Suspend: 1 Teb: 00cb9000 Unfrozen
36       Start: clr!Thread::intermediateThreadProc (72074b60)
37       Priority: 0  Priority class: 32  Affinity: f
38   12  Id: 2074.1358 Suspend: 1 Teb: 00cbc000 Unfrozen
39       Start: clr!Thread::intermediateThreadProc (72074b60)
40       Priority: 0  Priority class: 32  Affinity: f
41   13  Id: 2074.6e8 Suspend: 1 Teb: 00cbf000 Unfrozen
42       Start: clr!Thread::intermediateThreadProc (72074b60)
43       Priority: 0  Priority class: 32  Affinity: f

              ~*e !clrstack 命令執行的結果,內容太多,摺疊了。

  1 0:000> ~*e !clrstack
  2 OS Thread Id: 0xc08 (0)
  3 Child SP       IP Call Site
  4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac] 
  5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  7 00f3f410 716ab275 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean, Boolean, Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205]
  8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
  9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
 10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
 11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
 12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
 13 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 13]
 14 00f3f62c 71faf036 [GCFrame: 00f3f62c] 
 15 OS Thread Id: 0x2cdc (1)
 16 Unable to walk the managed stack. The current thread is likely not a 
 17 managed thread. You can run !threads to get a list of managed threads in
 18 the process
 19 Failed to start stack walk: 80070057
 20 OS Thread Id: 0x3bec (2)
 21 Unable to walk the managed stack. The current thread is likely not a 
 22 managed thread. You can run !threads to get a list of managed threads in
 23 the process
 24 Failed to start stack walk: 80070057
 25 OS Thread Id: 0x1a34 (3)
 26 Unable to walk the managed stack. The current thread is likely not a 
 27 managed thread. You can run !threads to get a list of managed threads in
 28 the process
 29 Failed to start stack walk: 80070057
 30 OS Thread Id: 0x3858 (4)
 31 Unable to walk the managed stack. The current thread is likely not a 
 32 managed thread. You can run !threads to get a list of managed threads in
 33 the process
 34 Failed to start stack walk: 80070057
 35 OS Thread Id: 0x379c (5)
 36 Child SP       IP Call Site
 37 050cfd48 77c3166c [DebuggerU2MCatchHandlerFrame: 050cfd48] 
 38 OS Thread Id: 0x3088 (6)
 39 Unable to walk the managed stack. The current thread is likely not a 
 40 managed thread. You can run !threads to get a list of managed threads in
 41 the process
 42 Failed to start stack walk: 80070057
 43 OS Thread Id: 0x2c54 (7)
 44 Unable to walk the managed stack. The current thread is likely not a 
 45 managed thread. You can run !threads to get a list of managed threads in
 46 the process
 47 Failed to start stack walk: 80070057
 48 OS Thread Id: 0x20dc (8)
 49 Unable to walk the managed stack. The current thread is likely not a 
 50 managed thread. You can run !threads to get a list of managed threads in
 51 the process
 52 Failed to start stack walk: 80070057
 53 OS Thread Id: 0x2014 (9)
 54 Child SP       IP Call Site
 55 0596f060 77c3166c [GCFrame: 0596f060] 
 56 0596f1b0 77c3166c [HelperMethodFrame: 0596f1b0] System.Threading.Monitor.Enter(System.Object)
 57 0596f220 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
 58 0596f230 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
 59 0596f238 02e90b59 Example_7_1_1.Program.Run1() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 26]
 60 0596f274 02e90a94 Example_7_1_1.Program+c.b__1_0() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 18]
 61 0596f280 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
 62 0596f28c 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
 63 0596f2b0 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
 64 0596f2b4 70eb8604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
 65 0596f320 70eb8537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
 66 0596f334 70f1b4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
 67 0596f398 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
 68 0596f3a8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
 69 0596f3ac 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
 70 0596f3fc 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
 71 0596f61c 71faf036 [DebuggerU2MCatchHandlerFrame: 0596f61c] 
 72 OS Thread Id: 0x187c (10)
 73 Unable to walk the managed stack. The current thread is likely not a 
 74 managed thread. You can run !threads to get a list of managed threads in
 75 the process
 76 Failed to start stack walk: 80070057
 77 OS Thread Id: 0x2b64 (11)
 78 Child SP       IP Call Site
 79 05b2f018 77c3166c [GCFrame: 05b2f018] 
 80 05b2f0f8 77c3166c [HelperMethodFrame_1OBJ: 05b2f0f8] System.Threading.Monitor.Enter(System.Object)
 81 05b2f170 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
 82 05b2f180 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
 83 05b2f188 02e90c31 Example_7_1_1.Program.Run2() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 33]
 84 05b2f1c4 02e90acc Example_7_1_1.Program+c.b__1_1() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 19]
 85 05b2f1d0 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
 86 05b2f1dc 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
 87 05b2f200 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
 88 05b2f204 70eb8604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
 89 05b2f270 70eb8537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
 90 05b2f284 70f1b4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
 91 05b2f2e8 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
 92 05b2f2f8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
 93 05b2f2fc 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
 94 05b2f34c 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
 95 05b2f56c 71faf036 [DebuggerU2MCatchHandlerFrame: 05b2f56c] 
 96 OS Thread Id: 0x1358 (12)
 97 Child SP       IP Call Site
 98 05c6f480 77c3166c [GCFrame: 05c6f480] 
 99 05c6f5d0 77c3166c [HelperMethodFrame: 05c6f5d0] System.Threading.Monitor.Enter(System.Object)
100 05c6f640 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
101 05c6f650 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
102 05c6f658 02e90d41 Example_7_1_1.Program.Run3() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 40]
103 05c6f694 02e90cb4 Example_7_1_1.Program+c.b__1_2() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_7_1_1\Program.cs @ 20]
104 05c6f6a0 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
105 05c6f6ac 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
106 05c6f6d0 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
107 05c6f6d4 70eb8604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
108 05c6f740 70eb8537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
109 05c6f754 70f1b4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
110 05c6f7b8 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
111 05c6f7c8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
112 05c6f7cc 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
113 05c6f81c 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
114 05c6fa3c 71faf036 [DebuggerU2MCatchHandlerFrame: 05c6fa3c] 
115 OS Thread Id: 0x6e8 (13)
116 Child SP       IP Call Site
117 GetFrameContext failed: 1
118 00000000 00000000 
View Code


        2.7、使用【!dumpstack】命令檢視託管和非託管的執行緒棧。
              測試原始碼:Example_7_1_1
              需要切換到主執行緒,然後執行命令【!dumpstack】

 1 0:000> !dumpstack
 2 OS Thread Id: 0x710 (0)
 3 Current frame: ntdll!NtReadFile+0xc
 4 ChildEBP RetAddr  Caller, Callee
 5 00daef38 75dbf25c KERNELBASE!ReadFile+0xec, calling ntdll!NtReadFile
 ......
66 00daf7d0 71fb9704 clr!Alloc+0x142, calling clr!_EH_epilog3
67 00daf7d8 71fc3cbc clr!HndLogSetEvent+0x15, calling clr!GCEventEnabledSetGCHandle
68 00daf9b0 77c052fe ntdll!RtlAllocateHeap+0x3e, calling ntdll!RtlpAllocateHeapInternal
69 00daf9d0 7213ca2c clr!EEStartupHelper+0xabb, calling clr!_EH_epilog3
70 00daf9d4 7213b55b clr!EEStartup+0xb8, calling clr!_SEH_epilog4
71 00dafa0c 7215b8a8 clr!ExecuteEXE+0x4c, calling clr!SystemDomain::ExecuteMainMethod
72 00dafa64 7215b9ce clr!_CorExeMainInternal+0xdc, calling clr!ExecuteEXE
73 00dafaa4 72157305 clr!_CorExeMain+0x4d, calling clr!_CorExeMainInternal
74 00dafae0 7275fa84 mscoreei!_CorExeMain+0xd6
75 00dafafc 7636f4c4 KERNEL32!GetProcAddressStub+0x14, calling KERNELBASE!GetProcAddressForCaller
76 00dafb18 7285e81e MSCOREE!ShellShim__CorExeMain+0x9e
77 00dafb28 72864338 MSCOREE!_CorExeMain_Exported+0x8, calling MSCOREE!ShellShim__CorExeMain
78 00dafb30 7636f989 KERNEL32!BaseThreadInitThunk+0x19
79 00dafb40 77c27084 ntdll!__RtlUserThreadStart+0x2f
80 00dafb9c 77c27054 ntdll!_RtlUserThreadStart+0x1b, calling ntdll!__RtlUserThreadStart

              我們可以使用【!dumpstack -ee】只檢視託管棧。

 1 0:000> !dumpstack -ee
 2 OS Thread Id: 0x710 (0)
 3 Current frame: 
 4 ChildEBP RetAddr  Caller, Callee
 5 00daef9c 70f79b71 (MethodDesc 70c438c4 +0x69 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
 6 00daefc8 70f79b71 (MethodDesc 70c438c4 +0x69 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
 7 00daf00c 716ab275 (MethodDesc 70cf7a24 +0x89 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean, Boolean, Int32 ByRef))
 8 00daf038 716ab17b (MethodDesc 70cf7a4c +0x9f System.IO.__ConsoleStream.Read(Byte[], Int32, Int32))
 9 00daf064 70f5e6a3 (MethodDesc 70c2d964 +0x33 System.IO.StreamReader.ReadBuffer())
10 00daf07c 70f5eb5b (MethodDesc 70c2d96c +0xe3 System.IO.StreamReader.ReadLine())
11 00daf098 717f3786 (MethodDesc 70d22100 +0x1a System.IO.TextReader+SyncTextReader.ReadLine())
12 00daf0a8 71651845 (MethodDesc 70c19e00 +0x15 System.Console.ReadLine())
13 00daf0b0 0144088e (MethodDesc 01184d78 +0x46 Example_7_1_1.Program.Main(System.String[]))


        2.8、使用【!eestack】和【~*e !dumpstack】檢視所有的執行緒棧。
              測試原始碼:Example_7_1_1

1 0:000> !eestack
2 ---------------------------------------------
3 Thread   0
4 Current frame: ntdll!NtReadFile+0xc
5 ChildEBP RetAddr  Caller, Callee
6 。。。。
7 內容太多,省略了。

            ~*e !dumpstack執行效果

1 0:000> ~*e !dumpstack
2 OS Thread Id: 0x710 (0)
3 Current frame: ntdll!NtReadFile+0xc
4 ChildEBP RetAddr  Caller, Callee
5 00daef38 75dbf25c KERNELBASE!ReadFile+0xec, calling ntdll!NtReadFile
6 ......
7 內容太多,省略了。

             eestack 命令,可以增加引數,比如:-short,我們可以使用 SOS 的幫助命令檢視某個命令的解釋,比如:eestack。

 1 0:010> !sos.help eestack
 2 -------------------------------------------------------------------------------
 3 !EEStack [-short] [-EE]
 4 
 5 This command runs !DumpStack on all threads in the process. The -EE option is 
 6 passed directly to !DumpStack. The -short option tries to narrow down the 
 7 output to "interesting" threads only, which is defined by
 8 
 9 1) The thread has taken a lock.(可以顯示具有鎖的執行緒)
10 2) The thread has been "hijacked" in order to allow a garbage collection.(可以顯示被「劫持」的執行緒)
11 3) The thread is currently in managed code.(可以顯示託管執行緒)
12 
13 See the documentation for !DumpStack for more info.


四、總結
    終於寫完了,今天這篇文章是第六篇。我們瞭解了執行緒和執行緒呼叫棧,那偵錯起來我們就知道如何開始了,知道如何查詢引數和區域性變數,知道執行緒棧地址,哦我們可以輸出執行緒棧的內容,對值型別和參照型別瞭解的也更深入了,當然對執行緒瞭解也更深入了,終於做到知其一也知其二了。其實這些知識是相互作用的,不是獨立的,任何一個環節的偵錯,都需要很多技巧。好了,不說了,不忘初心,繼續努力,希望老天不要辜負努力的人。