一、簡介
今天是《Net 高級調(diào)試》的第七篇文章。上一篇文章我們說了值類型,引用類型,數(shù)組等的內(nèi)存表現(xiàn)形式。有了這個基礎,我們可以更好的了解我們的程序在運行時的狀態(tài),內(nèi)存里有什么東西,它們的結構組成是什么樣子的,對我們調(diào)試程序是更有幫助的。今天,我們要說一些和線程有關的話題,雖然和線程相關,但是不是多線程的知識,不是線程安全的知識。今天我們討論的是如何查看線程,它的表現(xiàn)形式,以及線程的調(diào)用棧,調(diào)用棧,又分為托管線程的調(diào)用棧和非托管線程的調(diào)用棧,這些也是我們高級調(diào)試必須掌握的。有了這些基礎,我們就知道了程序的開始端點,調(diào)試的起點我們就找到了。雖然這些都是基礎,如果這些掌握不好,以后的高級調(diào)試的道路,也不好走。當然了,第一次看視頻或者看書,是很迷糊的,不知道如何操作,還是那句老話,一遍不行,那就再來一遍,還不行,那就再來一遍,俗話說的好,書讀千遍,其意自現(xiàn)。
如果在沒有說明的情況下,所有代碼的測試環(huán)境都是 Net Framewok 4.8,但是,有時候為了查看源碼,可能需要使用 Net Core 的項目,我會在項目章節(jié)里進行說明。好了,廢話不多說,開始我們今天的調(diào)試工作。
?? 調(diào)試環(huán)境我需要進行說明,以防大家不清楚,具體情況我已經(jīng)羅列出來。
操作系統(tǒng):Windows Professional 10
調(diào)試工具:Windbg Preview(可以去Microsoft Store 去下載)
開發(fā)工具:Visual Studio 2022
Net 版本:Net Framework 4.8
CoreCLR源碼:源碼下載
二、基礎知識
1、線程類相關介紹
1.1、簡介
在高級調(diào)試的過程中,很難不和 線程、線程棧 打交道,所以好好的學習并掌握有關線程操作的命令是很有必要的。
2、獲取 線程列表 的命令
2.1、查看線程列表。
可以使用【!t】命令獲取所有的托管線程。
2.2、使用 Net 7.0 查看線程列表
可以使用【!t】命令獲取所有的托管線程,如果我們想查看 CLR 的線程對象的結構就只能使用開源版本了,這里使用Net 7.0。
3、查看非托管線程棧
Windbg 是隨 Windows 成長起來的非托管調(diào)試器,它自帶的命令只能查看非托管調(diào)用棧,因為 C# 中的線程棧是托管函數(shù),而托管函數(shù)是一種運行時編譯的,所以這個命令往往看不到托管部分。
3.1、使用 k 命令查看非托管線程棧
【k】命令可以查看線程棧,但是么有辦法展示托管函數(shù),作為補充,可以使用【!clrstack】命令。
3.2、使用 kb 命令查看線程棧。
很多時候我們需要獲取非托管函數(shù)的參數(shù),這個時候我們可以使用【kb】命令。
3.3、查看托管函數(shù)棧
SOS 提供了一個專門查看托管函數(shù)調(diào)用棧的命令,畢竟只有 JIT更熟悉托管函數(shù),也知道編譯后的機器碼放在什么位置。
這個命令就是【!clrstack】。
!clrstack -a:這個命令表示將線程棧中的所有局部變量和參數(shù)全部輸出。
!clrstack -p:這個命令表示將線程棧中的參數(shù)全部輸出。
!clrstack -l:這個命令表示將線程棧中的所有局部變量全部輸出。
我們還可以查看所有托管線程棧,可以使用【~*e】命令。
3.4、查看托管和非托管合體
使用【!dumpstack】命令查看托管和非托管的線程棧。
3.5、執(zhí)行所有線程的 DumpStack。
如果我們想查看所有線程的線程棧,可以使用【!EEStack】,也可以使用【~*e !dumpstack】,結果是一樣的。
三、測試過程
廢話不多說,這一節(jié)是具體的調(diào)試操作的過程,又可以說是眼見為實的過程,在開始之前,我還是要啰嗦兩句,這一節(jié)分為兩個部分,第一部分是測試的源碼部分,沒有代碼,當然就談不上測試了,調(diào)試必須有載體。第二部分就是根據(jù)具體的代碼來證實我們學到的知識,是具體的眼見為實。
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 }
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 }
2、眼見為實
項目的所有操作都是一樣的,所以就在這里說明一下,但是每個測試例子,都需要重新啟動,并加載相應的應用程序,加載方法都是一樣的。流程如下:我們編譯項目,打開 Windbg,點擊【文件】----》【launch executable】附加程序,打開調(diào)試器的界面,程序已經(jīng)處于中斷狀態(tài)。我們需要使用【g】命令,繼續(xù)運行程序,然后到達指定地點停止后,我們可以點擊【break】按鈕,就可以調(diào)試程序了。有時候可能需要切換到主線程,可以使用【~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:已經(jīng)創(chuàng)建,但是還沒有使用的線程,當前數(shù)量是0。
BackgroundThread:后臺線程的數(shù)量,這個進程里面有5個。
PendingThread:阻塞的線程的數(shù)量,當前這個進程是0個阻塞的線程。
DeadThread:當一個線程完成任務,但是還沒有被回收,這個階段的線程就是死線程,也就是說這個線程對象底層的數(shù)據(jù)結構的 OSID 已經(jīng)銷毀。
以上就是介紹的主要名稱,下面接著介紹,列表的每一項。我們使用 C# Thread 類型聲明一個線程的時候,其實在操作系統(tǒng)和CLR都有一個數(shù)據(jù)結構相對應,有了 OSID我們才可以在任務管理器中看到線程對象。
第一列,沒有標題,是 WindbgThreadId,Windbg 自己的給 Thread 打了一個標記,便于以后使用,也可以區(qū)分托管線程和非托管線程。
第二列 ID:是托管線程,也就是我們 Thread 類型的標識符 Id,就是 這段代碼的值:Environment.CurrentManagedThreadId
第三列 OSID:操作系統(tǒng)線程的 ID,
第四列 ThreadOBJ:CLR 底層的 Thread 線程對象,可以使用【dp】命令觀察其中的內(nèi)容,我們查看托管線程 ID=3 的【00cdc010】內(nèi)容,紅色標注就是托管線程的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 層面的線程狀態(tài),03029220 就是托管線程的狀態(tài)。我們可以點進去或者使用【!threadstate】命令查看線程狀態(tài)詳情,當前就是托管線程是3的狀態(tài)。
1 0:012> !ThreadState 3029220 2 Legal to Join(可以執(zhí)行 join 操作) 3 Background(是后臺線程) 4 CLR Owns(是CLR 擁有的線程) 5 In Multi Threaded Apartment(是MTA模式) 6 Fully initialized(已經(jīng)完全初始化) 7 Thread Pool Worker Thread(是線程池線程) 8 Interruptible(可執(zhí)行中斷操作)
?
第六列 GC Mode:表示當前的線程有沒有操作托管堆的權限。
第七列 GC Alloc Context:緩沖區(qū)的開始節(jié)點和結束節(jié)點,每個線程在托管堆中分配一個對象,都有一個緩沖區(qū),這個就是確定了緩沖區(qū)起始和結束。
第八列 Domain:表示當前線程所屬于的域。
第九列 Lock Count:表示當前的線程有多少個托管鎖。
第十列 Apt:表示線程是 STA(線程串行模式,WPF、WinForm) 模式還是 MTA (多線程并行模式)模式。
第十一列 Exception:在當前線程上發(fā)生了異常,會把這個異常和這個線程關聯(lián)起來。
Finalizer 表示當前是終結器線程,Threadpool Worker 表示線程是線程池的線程。
2.2、如何查看 CLR Thread 的結構,也就是查看 ThreadOBJ 的結構。
測試源碼:Example_7_1_2(Net 7.0項目)
如果我們想在 Net Framework 環(huán)境下查看 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
+0x020 m_ThreadId : 1表示托管線程的ID。因為我打印的是 ThreadOBJ 為00000199DFD0CAE0 線程的結構。m 表示Management 托管的。
我們可以繼續(xù)看看 GC Alloc Context,在輸出的結構中有這樣一行代碼:+0x058 m_alloc_context : gc_alloc_context,藍色的字體,可以點擊,相當于執(zhí)行【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】命令查看非托管函數(shù)。
測試源碼:Example_7_1_1
這里操作需要切換到主線程上,執(zhí)行命令【~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.(無法顯示托管函數(shù)) 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】命令顯示托管函數(shù)。
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 的第一個參數(shù)。
測試源碼: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 方法的第一個參數(shù)是一個 Handle,我們可以使用【!handle】命令+ f 參數(shù)顯示詳情。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】命令查看托管函數(shù)。
測試源碼:Example_7_1_1
!clrstack 執(zhí)行效果
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:顯示所有參數(shù)和局部變量,關注紅色標注的。
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 ...(內(nèi)容太多,就省略了,也沒用) 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:(參數(shù)) 16 args (0x00f3f4b4) = 0x02f324bc(參數(shù)) 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 ...(內(nèi)容太多,就省略了,也沒用) 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:顯示所有參數(shù),關注紅色標注的。
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 ...(內(nèi)容太多,就省略了,也沒用) 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:(只有參數(shù)) 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
~* 命令,顯示所有線程列表和入口函數(shù)。
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 命令執(zhí)行的結果,內(nèi)容太多,折疊了。


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
2.7、使用【!dumpstack】命令查看托管和非托管的線程棧。
測試源碼:Example_7_1_1
需要切換到主線程,然后執(zhí)行命令【!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 內(nèi)容太多,省略了。
~*e !dumpstack執(zhí)行效果
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 內(nèi)容太多,省略了。
? eestack 命令,可以增加參數(shù),比如:-short,我們可以使用 SOS 的幫助命令查看某個命令的解釋,比如:eestack。文章來源:http://www.zghlxwxcb.cn/news/detail-746186.html
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.
四、總結
終于寫完了,今天這篇文章是第七篇。我們了解了線程和線程調(diào)用棧,那調(diào)試起來我們就知道如何開始了,知道如何查找參數(shù)和局部變量,知道線程棧地址,哦我們可以輸出線程棧的內(nèi)容,對值類型和引用類型了解的也更深入了,當然對線程了解也更深入了,終于做到知其一也知其二了。其實這些知識是相互作用的,不是獨立的,任何一個環(huán)節(jié)的調(diào)試,都需要很多技巧。好了,不說了,不忘初心,繼續(xù)努力,希望老天不要辜負努力的人。文章來源地址http://www.zghlxwxcb.cn/news/detail-746186.html
到了這里,關于Net 高級調(diào)試之七:線程操作相關命令介紹的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!