翼度科技»论坛 编程开发 .net 查看内容

Net 高级调试之七:线程操作相关命令介绍

3

主题

3

帖子

9

积分

新手上路

Rank: 1

积分
9
一、简介
    今天是《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. 1 namespace Example_7_1_1
  2. 2 {
  3. 3     internal class Program
  4. 4     {
  5. 5         static void Main(string[] args)
  6. 6         {
  7. 7             int a = 10;
  8. 8             int b = 11;
  9. 9             Test(12);
  10. 10             Console.ReadLine();
  11. 11         }
  12. 12
  13. 13         private static void Test(int c)
  14. 14         {
  15. 15             Task.Run(() => { Run1(); });
  16. 16             Task.Run(() => { Run2(); });
  17. 17             Task.Run(() => { Run3(); });
  18. 18         }
  19. 19
  20. 20         private static void Run1()
  21. 21         {
  22. 22             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 正在运行");
  23. 23             Console.ReadLine();
  24. 24             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 结束运行");
  25. 25         }
  26. 26
  27. 27         private static void Run2()
  28. 28         {
  29. 29             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 正在运行");
  30. 30             Console.ReadLine();
  31. 31             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 结束运行");
  32. 32         }
  33. 33
  34. 34         private static void Run3()
  35. 35         {
  36. 36             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 正在运行");
  37. 37             Console.ReadLine();
  38. 38             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 结束运行");
  39. 39         }
  40. 40     }
  41. 41 }
复制代码
View Code
        1.2、Example_7_1_2(特别说明,这个项目是 Net 7.0)
  1. 1 namespace Example_7_1_2
  2. 2 {
  3. 3     internal class Program
  4. 4     {
  5. 5         static void Main(string[] args)
  6. 6         {
  7. 7             Console.WriteLine("Hello, World!");
  8. 8             Debugger.Break();
  9. 9         }
  10. 10     }
  11. 11 }
复制代码
View Code
    2、眼见为实
        项目的所有操作都是一样的,所以就在这里说明一下,但是每个测试例子,都需要重新启动,并加载相应的应用程序,加载方法都是一样的。流程如下:我们编译项目,打开 Windbg,点击【文件】----》【launch executable】附加程序,打开调试器的界面,程序已经处于中断状态。我们需要使用【g】命令,继续运行程序,然后到达指定地点停止后,我们可以点击【break】按钮,就可以调试程序了。有时候可能需要切换到主线程,可以使用【~0s】命令。

        2.1、使用 【!t】命令查看进程中有多少个托管线程。
              
测试源码:Example_7_1_1
  1. 1 0:012> !t
  2. 2 ThreadCount:      6
  3. 3 UnstartedThread:  0
  4. 4 BackgroundThread: 5
  5. 5 PendingThread:    0
  6. 6 DeadThread:       0
  7. 7 Hosted Runtime:   no
  8. 8                                                                          Lock  
  9. 9        ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
  10. 10    0    1 2ef4 00c73930     2a020 Preemptive  02B94F38:00000000 00c6d758 1     MTA
  11. 11    5    2 39c0 00cb0728     2b220 Preemptive  00000000:00000000 00c6d758 0     MTA (Finalizer)
  12. 12    9    3 17dc 00cdc010   3029220 Preemptive  02B9C6C8:00000000 00c6d758 0     MTA (Threadpool Worker)
  13. 13   10    4  a18 00cdc9b8   3029220 Preemptive  02B98350:00000000 00c6d758 0     MTA (Threadpool Worker)
  14. 14   11    5 31d0 00cdd360   3029220 Preemptive  02B9A350:00000000 00c6d758 0     MTA (Threadpool Worker)
  15. 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. 1 0:012> dp 00cdc010
  2. 2 00cdc010  72074bd4 <strong>03029220</strong> 00000000 055ff680
  3. 3 00cdc020  00000000 00c6d758 00000000 <strong>00000003</strong>
  4. 4 00cdc030  00cdc034 00cdc034 00cdc034 00000000
  5. 5 00cdc040  00000000 baad0000 00c6ed50 0094f000
  6. 6 00cdc050  02b9c6c8 02b9dfe8 00003d10 00000000
  7. 7 00cdc060  00000000 00000000 00000000 00000000
  8. 8 00cdc070  00000000 baadf00d 70ad2c60 00cdc850
  9. 9 00cdc080  00000000 00000000 00000000 00000000
复制代码
 
                第五列 State:CLR 层面的线程状态,03029220 就是托管线程的状态。我们可以点进去或者使用【!threadstate】命令查看线程状态详情,当前就是托管线程是3的状态。
  1. 1 0:012> !ThreadState 3029220
  2. 2     Legal to Join(可以执行 join 操作)
  3. 3     Background(是后台线程)
  4. 4     CLR Owns(是CLR 拥有的线程)
  5. 5     In Multi Threaded Apartment(是MTA模式)
  6. 6     Fully initialized(已经完全初始化)
  7. 7     Thread Pool Worker Thread(是线程池线程)
  8. 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. 1 0:000> !t
  2. 2 ThreadCount:      3
  3. 3 UnstartedThread:  0
  4. 4 BackgroundThread: 2
  5. 5 PendingThread:    0
  6. 6 DeadThread:       0
  7. 7 Hosted Runtime:   no
  8. 8                                                                                                             Lock  
  9. 9  DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
  10. 10    0    1      624 00000199DFD0CAE0    2a020 Preemptive  00000199E440AD60:00000199E440C750 00000199dfd02dd0 -00001 MTA
  11. 11    5    2     1344 00000199DFD51DD0    21220 Preemptive  0000000000000000:0000000000000000 00000199dfd02dd0 -00001 Ukn (Finalizer)
  12. 12    6    3     3b40 000001DA763B15E0    2b220 Preemptive  0000000000000000:0000000000000000 00000199dfd02dd0 -00001 MTA
复制代码
              然后,我们使用【dt】命令,查看线程的结构。
  1.   1 0:000> dt coreclr!Thread 00000199DFD0CAE0
  2.   2    +0x000 m_stackLocalAllocator : (null)
  3.   3    =00007ffd`027a8af0 m_DetachCount    : 0n0
  4.   4    =00007ffd`027a8af4 m_ActiveDetachCount : 0n0
  5.   5    +0x008 m_State          : Volatile<enum Thread::ThreadState>
  6.   6    +0x00c m_fPreemptiveGCDisabled : Volatile<unsigned long>
  7.   7    +0x010 m_pFrame         : 0x0000008a`24f7e478 Frame
  8.   8    +0x018 m_pDomain        : 0x00000199`dfd02dd0 AppDomain
  9.   9    +0x020 m_ThreadId       : 1
  10. 10    +0x028 m_pHead          : 0x00000199`dfd0cb10 LockEntry
  11. 11    +0x030 m_embeddedEntry  : LockEntry
  12. 12    +0x050 m_pBlockingLock  : VolatilePtr<DeadlockAwareLock,DeadlockAwareLock *>
  13. 13    +0x058 m_alloc_context  : gc_alloc_context
  14. 14    +0x090 m_thAllocContextObj : TypeHandle
  15. 15    +0x098 m_pTEB           : 0x0000008a`24c20000 _NT_TIB
  16. 16    +0x0a0 m_pRCWStack      : 0x00000199`dfd0d710 RCWStackHeader
  17. 17    +0x0a8 m_ThreadTasks    : 0 (No matching name)
  18. 18    +0x0ac m_StateNC        : 100 ( TSNC_ExistInThreadStore )
  19. 19    +0x0b0 m_dwForbidSuspendThread : Volatile<long>
  20. 20    +0x0b4 m_dwHashCodeSeed : 0xdfca504a
  21. 21    +0x0b8 m_pLoadLimiter   : (null)
  22. 22    +0x0c0 m_AbortType      : 0
  23. 23    +0x0c8 m_AbortEndTime   : 0xffffffff`ffffffff
  24. 24    +0x0d0 m_RudeAbortEndTime : 0xffffffff`ffffffff
  25. 25    +0x0d8 m_fRudeAbortInitiated : 0n0
  26. 26    +0x0dc m_AbortController : 0n0
  27. 27    +0x0e0 m_AbortRequestLock : 0n0
  28. 28    +0x0e4 m_ThrewControlForThread : 0
  29. 29    +0x0e8 m_OSContext      : 0x00000199`dfd0d210 _CONTEXT
  30. 30    +0x0f0 m_pPendingTypeLoad : (null)
  31. 31    +0x0f8 m_Link           : SLink
  32. 32    +0x100 m_dwLastError    : 0
  33. 33    +0x108 m_CacheStackBase : 0x0000008a`24f80000 Void
  34. 34    +0x110 m_CacheStackLimit : 0x0000008a`24e00000 Void
  35. 35    +0x118 m_CacheStackSufficientExecutionLimit : 0x0000008a`24e20000
  36. 36    +0x120 m_CacheStackStackAllocNonRiskyExecutionLimit : 0x0000008a`24e80000
  37. 37    +0x128 m_pvHJRetAddr    : 0xcccccccc`cccccccc Void
  38. 38    +0x130 m_ppvHJRetAddrPtr : 0xcccccccc`cccccccc  -> ????
  39. 39    +0x138 m_HijackedFunction : 0xbaadf00d`baadf00d MethodDesc
  40. 40    +0x140 m_UserInterrupt  : 0n0
  41. 41    +0x148 m_DebugSuspendEvent : CLREvent
  42. 42    +0x158 m_EventWait      : CLREvent
  43. 43    +0x168 m_WaitEventLink  : WaitEventLink
  44. 44    +0x198 m_ThreadHandle   : 0x00000000`000001e0 Void
  45. 45    +0x1a0 m_ThreadHandleForClose : 0xffffffff`ffffffff Void
  46. 46    +0x1a8 m_ThreadHandleForResume : 0xffffffff`ffffffff Void
  47. 47    +0x1b0 m_WeOwnThreadHandle : 0n1
  48. 48    +0x1b8 m_OSThreadId     : 0x624
  49. 49    +0x1c0 m_ExposedObject  : 0x00000199`dfc411f8 OBJECTHANDLE__
  50. 50    +0x1c8 m_StrongHndToExposedObject : 0x00000199`dfc413f8 OBJECTHANDLE__
  51. 51    +0x1d0 m_Priority       : 0x80000000
  52. 52    +0x1d4 m_ExternalRefCount : 1
  53. 53    +0x1d8 m_TraceCallCount : 0n0
  54. 54    +0x1e0 m_LastThrownObjectHandle : (null)
  55. 55    +0x1e8 m_ltoIsUnhandled : 0n0
  56. 56    +0x1f0 m_ExceptionState : ThreadExceptionState
  57. 57    +0x398 m_debuggerFilterContext : (null)
  58. 58    +0x3a0 m_pProfilerFilterContext : (null)
  59. 59    +0x3a8 m_hijackLock     : Volatile<long>
  60. 60    +0x3b0 m_hCurrNotification : 0xbaadf00d`baadf00d OBJECTHANDLE__
  61. 61    +0x3b8 m_fInteropDebuggingHijacked : 0n0
  62. 62    +0x3bc m_profilerCallbackState : 0
  63. 63    +0x3c0 m_dwProfilerEvacuationCounters : [33] Volatile<unsigned long>
  64. 64    +0x444 m_workerThreadPoolCompletionCount : 0
  65. 65    =00007ffd`027b3cc0 s_workerThreadPoolCompletionCountOverflow : 0
  66. 66    +0x448 m_ioThreadPoolCompletionCount : 0
  67. 67    =00007ffd`027b3cc8 s_ioThreadPoolCompletionCountOverflow : 0
  68. 68    +0x44c m_monitorLockContentionCount : 0
  69. 69    =00007ffd`027a8ad8 s_monitorLockContentionCountOverflow : 0
  70. 70    +0x450 m_PreventAsync   : 0n0
  71. 71    =00007ffd`027a6204 m_DebugWillSyncCount : 0n-1
  72. 72    +0x458 m_pSavedRedirectContext : (null)
  73. 73    +0x460 m_pOSContextBuffer : (null)
  74. 74    +0x468 m_ThreadLocalBlock : ThreadLocalBlock
  75. 75    +0x490 m_tailCallTls    : TailCallTls
  76. 76    +0x4a0 m_dwAVInRuntimeImplOkayCount : 0
  77. 77    +0x4a8 m_pExceptionDuringStartup : (null)
  78. 78    +0x4b0 m_debuggerActivePatchSkipper : VolatilePtr<DebuggerPatchSkip,DebuggerPatchSkip *>
  79. 79    +0x4b8 m_fAllowProfilerCallbacks : 0n1
  80. 80    +0x4c0 m_pIOCompletionContext : 0x00000199`dfd0da40 Void
  81. 81    +0x4c8 m_dwThreadHandleBeingUsed : Volatile<long>
  82. 82    =00007ffd`027a8ad0 s_fCleanFinalizedThread : 0n0
  83. 83    +0x4d0 m_pCreatingThrowableForException : (null)
  84. 84    +0x4d8 m_dwIndexClauseForCatch : 0
  85. 85    +0x4e0 m_sfEstablisherOfActualHandlerFrame : StackFrame
  86. 86    +0x4e8 DebugBlockingInfo : ThreadDebugBlockingInfo
  87. 87    +0x4f0 m_fDisableComObjectEagerCleanup : 0
  88. 88    +0x4f1 m_fHasDeadThreadBeenConsideredForGCTrigger : 0
  89. 89    +0x4f4 m_random         : CLRRandom
  90. 90    +0x5e0 m_uliInitializeSpyCookie : _ULARGE_INTEGER 0x0
  91. 91    +0x5e8 m_fInitializeSpyRegistered : 0
  92. 92    +0x5f0 m_pLastSTACtxCookie : (null)
  93. 93    +0x5f8 m_fGCSpecial     : 0
  94. 94    +0x600 m_pGCFrame       : 0x0000008a`24f7e790 GCFrame
  95. 95    +0x608 m_wCPUGroup      : 0
  96. 96    +0x610 m_pAffinityMask  : 0
  97. 97    +0x618 m_pAllLoggedTypes : (null)
  98. 98    +0x620 m_gcModeOnSuspension : Volatile<unsigned long>
  99. 99    +0x624 m_activityId     : _GUID {00000000-0000-0000-0000-000000000000}
  100. 100    +0x634 m_HijackReturnKind : ff ( RT_Illegal )
  101. 101    =00007ffd`027a8b40 dead_threads_non_alloc_bytes : 0
  102. 102    +0x638 m_currentPrepareCodeConfig : (null)
  103. 103    +0x640 m_isInForbidSuspendForDebuggerRegion : 0
  104. 104    =00007ffd`027ba3d0 s_pfnQueueUserAPC2Proc : (null)
  105. 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. 1 0:000> dx -r1 (*((coreclr!gc_alloc_context *)0x199dfd0cb38))
  2. 2 (*((coreclr!gc_alloc_context *)0x199dfd0cb38))                 [Type: gc_alloc_context]
  3. 3     [+0x000] alloc_ptr        : 0x199e440ad60 : 0x0 [Type: unsigned char *]
  4. 4     [+0x008] alloc_limit      : 0x199e440c750 : 0x0 [Type: unsigned char *]
  5. 5     [+0x010] alloc_bytes      : 50920 [Type: __int64](小对象堆的大小)
  6. 6     [+0x018] alloc_bytes_uoh  : 17416 [Type: __int64](大对象堆的大小)
  7. 7     [+0x020] gc_reserved_1    : 0x0 [Type: void *]
  8. 8     [+0x028] gc_reserved_2    : 0x0 [Type: void *]
  9. 9     [+0x030] alloc_count      : 0 [Type: int]
复制代码
        2.3、使用 Windbg 的【k】命令查看非托管函数。
              测试源码:Example_7_1_1
              这里操作需要切换到主线程上,执行命令【~0s】,然后使用【k】命令。
  1. 1 0:010> ~0s
  2. 2 eax=00000000 ebx=00000090 ecx=00000000 edx=00000000 esi=00f3f444 edi=00000000
  3. 3 eip=77c310fc esp=00f3f32c ebp=00f3f38c iopl=0         nv up ei pl nz na po nc
  4. 4 cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
  5. 5 ntdll!NtReadFile+0xc:
  6. 6 77c310fc c22400          ret     24h
  7. 7
  8. 8
  9. 9 0:000> k
  10. 10  # ChildEBP RetAddr      
  11. 11 00 00f3f38c 75dbf25c     ntdll!NtReadFile+0xc
  12. 12 01 00f3f38c 70f79b71     KERNELBASE!ReadFile+0xec
  13. 13 02 00f3f3fc 716ab275     mscorlib_ni+0x4b9b71
  14. 14 03 00f3f428 716ab17b     ...
  15. 15<strong> WARNING: Frame IP not in any known module. Following frames may be wrong.(无法显示托管函数)
  16. </strong>16 09 00f3f4b8 71faf036     0x2e9088e
  17. 17 0a 00f3f4c4 71fb22da     clr!CallDescrWorkerInternal+0x34
  18. 18 0b 00f3f518 71fb859b     clr!CallDescrWorkerWithHandler+0x6b
  19. 19 0c 00f3f588 7215b11b     clr!MethodDescCallSite::CallTargetWorker+0x16a
  20. 20 0d 00f3f6ac 7215b7fa     clr!RunMain+0x1b3
  21. 21 0e 00f3f918 7215b727     clr!Assembly::ExecuteMainMethod+0xf7
  22. 22 0f 00f3fdfc 7215b8a8     clr!SystemDomain::ExecuteMainMethod+0x5ef
  23. 23 10 00f3fe54 7215b9ce     clr!ExecuteEXE+0x4c
  24. 24 11 00f3fe94 72157305     clr!_CorExeMainInternal+0xdc
  25. 25 12 00f3fed0 7275fa84     clr!_CorExeMain+0x4d
  26. 26 13 00f3ff08 7285e81e     mscoreei!_CorExeMain+0xd6
  27. 27 14 00f3ff18 72864338     MSCOREE!ShellShim__CorExeMain+0x9e
  28. 28 15 00f3ff30 7636f989     MSCOREE!_CorExeMain_Exported+0x8
  29. 29 16 00f3ff30 77c27084     KERNEL32!BaseThreadInitThunk+0x19
  30. 30 17 00f3ff8c 77c27054     ntdll!__RtlUserThreadStart+0x2f
  31. 31 18 00f3ff9c 00000000     ntdll!_RtlUserThreadStart+0x1b
复制代码
              但是我们可以使用 SOS的【!clrstack】命令显示托管函数。
  1. 1 0:000> !clrstack
  2. 2 OS Thread Id: 0xc08 (0)
  3. 3 Child SP       IP Call Site
  4. 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5. 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6. 6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(..., Int32, Int32 ByRef, IntPtr)
  7. 7 00f3f410 716ab275 System.IO.__ConsoleStream.ReadFileNative(.., Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205]
  8. 8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
  9. 9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
  10. 10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
  11. 11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  12. 12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  13. 13 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
  14. 14 00f3f62c 71faf036 [GCFrame: 00f3f62c]
复制代码
        2.4、使用【kb】命令查看线程栈,提取 ntdll!NtReadFile 的第一个参数。
              测试源码:Example_7_1_1              
  1. 1 0:000> kb
  2. 2  # ChildEBP RetAddr      Args to Child              
  3. 3 00 00f3f38c 75dbf25c     <strong>00000090</strong> 00000000 00000000 <strong>ntdll!NtReadFile</strong>+0xc
  4. 4 01 00f3f38c 70f79b71     00000090 02f35d18 00000100 KERNELBASE!ReadFile+0xec
  5. 5 02 00f3f3fc 716ab275     00000000 00f3f444 00000100 mscorlib_ni+0x4b9b71
  6. 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. 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. 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. 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. 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. 11 08 00f3f4a0 02e9088e     00000000 0000000b 0000000a mscorlib_ni!System.Console.ReadLine+0x15 [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  12. 12 WARNING: Frame IP not in any known module. Following frames may be wrong.
  13. 13 09 00f3f4b8 71faf036     0116a628 00f3f518 71fb22da 0x2e9088e
  14. 14 0a 00f3f4c4 71fb22da     00f3f55c 00f3f508 720a23d0 clr!CallDescrWorkerInternal+0x34
  15. 15 0b 00f3f518 71fb859b     00f3f570 02f324bc 00000000 clr!CallDescrWorkerWithHandler+0x6b
  16. 16 0c 00f3f588 7215b11b     00f3f664 6a38df42 02d04d78 clr!MethodDescCallSite::CallTargetWorker+0x16a
  17. 17 0d 00f3f6ac 7215b7fa     00f3f6f0 00000000 6a38d0f6 clr!RunMain+0x1b3
  18. 18 0e 00f3f918 7215b727     00000000 6a38d412 00b70000 clr!Assembly::ExecuteMainMethod+0xf7
  19. 19 0f 00f3fdfc 7215b8a8     6a38d7ba 00000000 00000000 clr!SystemDomain::ExecuteMainMethod+0x5ef
  20. 20 10 00f3fe54 7215b9ce     6a38d77a 00000000 721572e0 clr!ExecuteEXE+0x4c
  21. 21 11 00f3fe94 72157305     6a38d73e 00000000 721572e0 clr!_CorExeMainInternal+0xdc
  22. 22 12 00f3fed0 7275fa84     8ee8ef1f 72864330 7275fa20 clr!_CorExeMain+0x4d
  23. 23 13 00f3ff08 7285e81e     72864330 72750000 00f3ff30 mscoreei!_CorExeMain+0xd6
  24. 24 14 00f3ff18 72864338     72864330 7636f989 00c95000 MSCOREE!ShellShim__CorExeMain+0x9e
  25. 25 15 00f3ff30 7636f989     00c95000 7636f970 00f3ff8c MSCOREE!_CorExeMain_Exported+0x8
  26. 26 16 00f3ff30 77c27084     00c95000 281a60a3 00000000 KERNEL32!BaseThreadInitThunk+0x19
  27. 27 17 00f3ff8c 77c27054     ffffffff 77c462ae 00000000 ntdll!__RtlUserThreadStart+0x2f
  28. 28 18 00f3ff9c 00000000     00000000 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b
复制代码
              ntdll!NtReadFile 方法的第一个参数是一个 Handle,我们可以使用【!handle】命令+ f 参数显示详情。Console.ReadLine()方法底层就是 File 的句柄。
  1. 1 0:000> !handle 00000090 f
  2. 2 Handle 90
  3. 3   Type             File
  4. 4   Attributes       0
  5. 5   GrantedAccess    0x12019f:
  6. 6          ReadControl,Synch
  7. 7          Read/List,Write/Add,Append/SubDir/CreatePipe,ReadEA,WriteEA,ReadAttr,WriteAttr
  8. 8   HandleCount      2
  9. 9   PointerCount     65531
  10. 10   No Object Specific Information available
复制代码
        2.5、我们使用【!clrstack】命令查看托管函数。
              测试源码:Example_7_1_1
              !clrstack 执行效果
  1. 1 0:000> !clrstack
  2. 2 OS Thread Id: 0xc08 (0)
  3. 3 Child SP       IP Call Site
  4. 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5. 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(..., Byte*, Int32, Int32 ByRef, IntPtr)
  6. 6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(... Byte*, Int32, Int32 ByRef, IntPtr)
  7. 7 00f3f410 716ab275 System.IO.__ConsoleStream.ReadFileNative(.. Int32 ByRef) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 205]
  8. 8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
  9. 9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
  10. 10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
  11. 11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  12. 12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  13. 13 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
  14. 14 00f3f62c 71faf036 [GCFrame: 00f3f62c]
复制代码
              !clrstack -a:显示所有参数和局部变量,关注红色标注的。
  1. 1 0:000> !clrstack -a
  2. 2 OS Thread Id: 0xc08 (0)
  3. 3 Child SP       IP Call Site
  4. 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5. 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6. 6     PARAMETERS:
  7. 7         <no data>
  8. 8         <no data>
  9. 9         <no data>
  10. 10         <no data>
  11. 11         <no data>
  12. 12 ...(内容太多,就省略了,也没用)
  13. 13
  14. 14 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\..\Example_7_1_1\Program.cs @ 13]
  15. 15 <strong>    PARAMETERS:(参数)
  16. </strong>16         args (0x00f3f4b4) = 0x02f324bc(参数)
  17. 17 <strong>    LOCALS:(局部变量)
  18. </strong>18         0x00f3f4b0 = 0x0000000a
  19. 19         0x00f3f4ac = 0x0000000b
  20. 20
  21. 21 00f3f62c 71faf036 [GCFrame: 00f3f62c]
复制代码
              !clrstack -l:显示所有局部变量,关注红色标注的。
  1. 1 0:000> !clrstack -l
  2. 2 OS Thread Id: 0xc08 (0)
  3. 3 Child SP       IP Call Site
  4. 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5. 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6. 6 ...(内容太多,就省略了,也没用)
  7. 7
  8. 8 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
  9. 9 <strong>    LOCALS:(只有局部变量)
  10. </strong>10         0x00f3f4b0 = 0x0000000a
  11. 11         0x00f3f4ac = 0x0000000b
  12. 12
  13. 13 00f3f62c 71faf036 [GCFrame: 00f3f62c]
复制代码
              !clrstack -p:显示所有参数,关注红色标注的。
  1. 1 0:000> !clrstack -p
  2. 2 OS Thread Id: 0xc08 (0)
  3. 3 Child SP       IP Call Site
  4. 4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5. 5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6. 6     PARAMETERS:
  7. 7         <no data>
  8. 8         <no data>
  9. 9         <no data>
  10. 10         <no data>
  11. 11         <no data>
  12. 12
  13. 13 ...(内容太多,就省略了,也没用)
  14. 14
  15. 15 00f3f4a8 02e9088e Example_7_1_1.Program.Main(System.String[]) [E:\Visual Studio 2022\...\Example_7_1_1\Program.cs @ 13]
  16. 16 <strong>    PARAMETERS:(只有参数)
  17. </strong>17         args (0x00f3f4b4) = 0x02f324bc
  18. 18
  19. 19 00f3f62c 71faf036 [GCFrame: 00f3f62c]
复制代码
        2.6、使用【~*e】查看所有托管线程栈。
              测试源码:Example_7_1_1
              ~ 命令输出所有线程列表。
  1. 1 0:000> ~
  2. 2 .  0  Id: 2074.c08 Suspend: 1 Teb: 00c98000 Unfrozen
  3. 3    1  Id: 2074.2cdc Suspend: 1 Teb: 00c9b000 Unfrozen
  4. 4    2  Id: 2074.3bec Suspend: 1 Teb: 00c9e000 Unfrozen
  5. 5    3  Id: 2074.1a34 Suspend: 1 Teb: 00ca1000 Unfrozen
  6. 6    4  Id: 2074.3858 Suspend: 1 Teb: 00ca4000 Unfrozen
  7. 7    5  Id: 2074.379c Suspend: 1 Teb: 00ca7000 Unfrozen
  8. 8    6  Id: 2074.3088 Suspend: 1 Teb: 00caa000 Unfrozen
  9. 9    7  Id: 2074.2c54 Suspend: 1 Teb: 00cad000 Unfrozen
  10. 10    8  Id: 2074.20dc Suspend: 1 Teb: 00cb0000 Unfrozen
  11. 11    9  Id: 2074.2014 Suspend: 1 Teb: 00cb3000 Unfrozen
  12. 12 # 10  Id: 2074.187c Suspend: 1 Teb: 00cc2000 Unfrozen
  13. 13   11  Id: 2074.2b64 Suspend: 1 Teb: 00cb9000 Unfrozen
  14. 14   12  Id: 2074.1358 Suspend: 1 Teb: 00cbc000 Unfrozen
  15. 15   13  Id: 2074.6e8 Suspend: 1 Teb: 00cbf000 Unfrozen
复制代码
              ~* 命令,显示所有线程列表和入口函数。
  1. 1 0:000> ~*
  2. 2 .  0  Id: 2074.c08 Suspend: 1 Teb: 00c98000 Unfrozen
  3. 3       Start: 00402bca
  4. 4       Priority: 0  Priority class: 32  Affinity: f
  5. 5    1  Id: 2074.2cdc Suspend: 1 Teb: 00c9b000 Unfrozen
  6. 6       Start: ntdll!TppWorkerThread (77c10c90)
  7. 7       Priority: 0  Priority class: 32  Affinity: f
  8. 8    2  Id: 2074.3bec Suspend: 1 Teb: 00c9e000 Unfrozen
  9. 9       Start: ntdll!TppWorkerThread (77c10c90)
  10. 10       Priority: 0  Priority class: 32  Affinity: f
  11. 11    3  Id: 2074.1a34 Suspend: 1 Teb: 00ca1000 Unfrozen
  12. 12       Start: ntdll!TppWorkerThread (77c10c90)
  13. 13       Priority: 0  Priority class: 32  Affinity: f
  14. 14    4  Id: 2074.3858 Suspend: 1 Teb: 00ca4000 Unfrozen
  15. 15       Start: clr!DebuggerRCThread::ThreadProcStatic (721565d0)
  16. 16       Priority: 0  Priority class: 32  Affinity: f
  17. 17    5  Id: 2074.379c Suspend: 1 Teb: 00ca7000 Unfrozen
  18. 18       Start: clr!Thread::intermediateThreadProc (72074b60)
  19. 19       Priority: 2  Priority class: 32  Affinity: f
  20. 20    6  Id: 2074.3088 Suspend: 1 Teb: 00caa000 Unfrozen
  21. 21       Start: combase!CRpcThreadCache::RpcWorkerThreadEntry (7731bcc0)
  22. 22       Priority: 0  Priority class: 32  Affinity: f
  23. 23    7  Id: 2074.2c54 Suspend: 1 Teb: 00cad000 Unfrozen
  24. 24       Start: ntdll!TppWorkerThread (77c10c90)
  25. 25       Priority: 0  Priority class: 32  Affinity: f
  26. 26    8  Id: 2074.20dc Suspend: 1 Teb: 00cb0000 Unfrozen
  27. 27       Start: ntdll!TppWorkerThread (77c10c90)
  28. 28       Priority: 0  Priority class: 32  Affinity: f
  29. 29    9  Id: 2074.2014 Suspend: 1 Teb: 00cb3000 Unfrozen
  30. 30       Start: clr!Thread::intermediateThreadProc (72074b60)
  31. 31       Priority: 0  Priority class: 32  Affinity: f
  32. 32 # 10  Id: 2074.187c Suspend: 1 Teb: 00cc2000 Unfrozen
  33. 33       Start: ntdll!DbgUiRemoteBreakin (77c6cee0)
  34. 34       Priority: 0  Priority class: 32  Affinity: f
  35. 35   11  Id: 2074.2b64 Suspend: 1 Teb: 00cb9000 Unfrozen
  36. 36       Start: clr!Thread::intermediateThreadProc (72074b60)
  37. 37       Priority: 0  Priority class: 32  Affinity: f
  38. 38   12  Id: 2074.1358 Suspend: 1 Teb: 00cbc000 Unfrozen
  39. 39       Start: clr!Thread::intermediateThreadProc (72074b60)
  40. 40       Priority: 0  Priority class: 32  Affinity: f
  41. 41   13  Id: 2074.6e8 Suspend: 1 Teb: 00cbf000 Unfrozen
  42. 42       Start: clr!Thread::intermediateThreadProc (72074b60)
  43. 43       Priority: 0  Priority class: 32  Affinity: f
复制代码
              ~*e !clrstack 命令执行的结果,内容太多,折叠了。
  1.   1 0:000> ~*e !clrstack
  2.   2 OS Thread Id: 0xc08 (0)
  3.   3 Child SP       IP Call Site
  4.   4 00f3f3ac 77c310fc [InlinedCallFrame: 00f3f3ac]
  5.   5 00f3f3a8 70f79b71 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  6.   6 00f3f3ac 716ab275 [InlinedCallFrame: 00f3f3ac] Microsoft.Win32.Win32Native.ReadFile(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr)
  7.   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.   8 00f3f444 716ab17b System.IO.__ConsoleStream.Read(Byte[], Int32, Int32) [f:\dd\ndp\clr\src\BCL\system\io\__consolestream.cs @ 134]
  9.   9 00f3f464 70f5e6a3 System.IO.StreamReader.ReadBuffer() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 595]
  10. 10 00f3f474 70f5eb5b System.IO.StreamReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\streamreader.cs @ 748]
  11. 11 00f3f490 717f3786 System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  12. 12 00f3f4a0 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  13. 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. 14 00f3f62c 71faf036 [GCFrame: 00f3f62c]
  15. 15 OS Thread Id: 0x2cdc (1)
  16. 16 Unable to walk the managed stack. The current thread is likely not a
  17. 17 managed thread. You can run !threads to get a list of managed threads in
  18. 18 the process
  19. 19 Failed to start stack walk: 80070057
  20. 20 OS Thread Id: 0x3bec (2)
  21. 21 Unable to walk the managed stack. The current thread is likely not a
  22. 22 managed thread. You can run !threads to get a list of managed threads in
  23. 23 the process
  24. 24 Failed to start stack walk: 80070057
  25. 25 OS Thread Id: 0x1a34 (3)
  26. 26 Unable to walk the managed stack. The current thread is likely not a
  27. 27 managed thread. You can run !threads to get a list of managed threads in
  28. 28 the process
  29. 29 Failed to start stack walk: 80070057
  30. 30 OS Thread Id: 0x3858 (4)
  31. 31 Unable to walk the managed stack. The current thread is likely not a
  32. 32 managed thread. You can run !threads to get a list of managed threads in
  33. 33 the process
  34. 34 Failed to start stack walk: 80070057
  35. 35 OS Thread Id: 0x379c (5)
  36. 36 Child SP       IP Call Site
  37. 37 050cfd48 77c3166c [DebuggerU2MCatchHandlerFrame: 050cfd48]
  38. 38 OS Thread Id: 0x3088 (6)
  39. 39 Unable to walk the managed stack. The current thread is likely not a
  40. 40 managed thread. You can run !threads to get a list of managed threads in
  41. 41 the process
  42. 42 Failed to start stack walk: 80070057
  43. 43 OS Thread Id: 0x2c54 (7)
  44. 44 Unable to walk the managed stack. The current thread is likely not a
  45. 45 managed thread. You can run !threads to get a list of managed threads in
  46. 46 the process
  47. 47 Failed to start stack walk: 80070057
  48. 48 OS Thread Id: 0x20dc (8)
  49. 49 Unable to walk the managed stack. The current thread is likely not a
  50. 50 managed thread. You can run !threads to get a list of managed threads in
  51. 51 the process
  52. 52 Failed to start stack walk: 80070057
  53. 53 OS Thread Id: 0x2014 (9)
  54. 54 Child SP       IP Call Site
  55. 55 0596f060 77c3166c [GCFrame: 0596f060]
  56. 56 0596f1b0 77c3166c [HelperMethodFrame: 0596f1b0] System.Threading.Monitor.Enter(System.Object)
  57. 57 0596f220 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  58. 58 0596f230 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  59. 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. 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. 61 0596f280 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
  62. 62 0596f28c 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
  63. 63 0596f2b0 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
  64. 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. 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. 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. 67 0596f398 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
  68. 68 0596f3a8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
  69. 69 0596f3ac 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
  70. 70 0596f3fc 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
  71. 71 0596f61c 71faf036 [DebuggerU2MCatchHandlerFrame: 0596f61c]
  72. 72 OS Thread Id: 0x187c (10)
  73. 73 Unable to walk the managed stack. The current thread is likely not a
  74. 74 managed thread. You can run !threads to get a list of managed threads in
  75. 75 the process
  76. 76 Failed to start stack walk: 80070057
  77. 77 OS Thread Id: 0x2b64 (11)
  78. 78 Child SP       IP Call Site
  79. 79 05b2f018 77c3166c [GCFrame: 05b2f018]
  80. 80 05b2f0f8 77c3166c [HelperMethodFrame_1OBJ: 05b2f0f8] System.Threading.Monitor.Enter(System.Object)
  81. 81 05b2f170 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  82. 82 05b2f180 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  83. 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. 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. 85 05b2f1d0 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
  86. 86 05b2f1dc 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
  87. 87 05b2f200 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
  88. 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. 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. 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. 91 05b2f2e8 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
  92. 92 05b2f2f8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
  93. 93 05b2f2fc 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
  94. 94 05b2f34c 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
  95. 95 05b2f56c 71faf036 [DebuggerU2MCatchHandlerFrame: 05b2f56c]
  96. 96 OS Thread Id: 0x1358 (12)
  97. 97 Child SP       IP Call Site
  98. 98 05c6f480 77c3166c [GCFrame: 05c6f480]
  99. 99 05c6f5d0 77c3166c [HelperMethodFrame: 05c6f5d0] System.Threading.Monitor.Enter(System.Object)
  100. 100 05c6f640 717f377b System.IO.TextReader+SyncTextReader.ReadLine() [f:\dd\ndp\clr\src\BCL\system\io\textreader.cs @ 363]
  101. 101 05c6f650 71651845 System.Console.ReadLine() [f:\dd\ndp\clr\src\BCL\system\console.cs @ 1984]
  102. 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. 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. 104 05c6f6a0 70f1d4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
  105. 105 05c6f6ac 70f1b731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
  106. 106 05c6f6d0 70f1b6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
  107. 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. 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. 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. 110 05c6f7b8 70f1b357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
  111. 111 05c6f7c8 70f1b29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
  112. 112 05c6f7cc 70e8eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
  113. 113 05c6f81c 70e8e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
  114. 114 05c6fa3c 71faf036 [DebuggerU2MCatchHandlerFrame: 05c6fa3c]
  115. 115 OS Thread Id: 0x6e8 (13)
  116. 116 Child SP       IP Call Site
  117. 117 GetFrameContext failed: 1
  118. 118 00000000 00000000
复制代码
View Code
        2.7、使用【!dumpstack】命令查看托管和非托管的线程栈。
              测试源码:Example_7_1_1
              需要切换到主线程,然后执行命令【!dumpstack】
  1. 1 0:000> !dumpstack
  2. 2 OS Thread Id: 0x710 (0)
  3. 3 Current frame: ntdll!NtReadFile+0xc
  4. 4 ChildEBP RetAddr  Caller, Callee
  5. 5 00daef38 75dbf25c KERNELBASE!ReadFile+0xec, calling ntdll!NtReadFile
  6. ......
  7. 66 00daf7d0 71fb9704 clr!Alloc+0x142, calling clr!_EH_epilog3
  8. 67 00daf7d8 71fc3cbc clr!HndLogSetEvent+0x15, calling clr!GCEventEnabledSetGCHandle
  9. 68 00daf9b0 77c052fe ntdll!RtlAllocateHeap+0x3e, calling ntdll!RtlpAllocateHeapInternal
  10. 69 00daf9d0 7213ca2c clr!EEStartupHelper+0xabb, calling clr!_EH_epilog3
  11. 70 00daf9d4 7213b55b clr!EEStartup+0xb8, calling clr!_SEH_epilog4
  12. 71 00dafa0c 7215b8a8 clr!ExecuteEXE+0x4c, calling clr!SystemDomain::ExecuteMainMethod
  13. 72 00dafa64 7215b9ce clr!_CorExeMainInternal+0xdc, calling clr!ExecuteEXE
  14. 73 00dafaa4 72157305 clr!_CorExeMain+0x4d, calling clr!_CorExeMainInternal
  15. 74 00dafae0 7275fa84 mscoreei!_CorExeMain+0xd6
  16. 75 00dafafc 7636f4c4 KERNEL32!GetProcAddressStub+0x14, calling KERNELBASE!GetProcAddressForCaller
  17. 76 00dafb18 7285e81e MSCOREE!ShellShim__CorExeMain+0x9e
  18. 77 00dafb28 72864338 MSCOREE!_CorExeMain_Exported+0x8, calling MSCOREE!ShellShim__CorExeMain
  19. 78 00dafb30 7636f989 KERNEL32!BaseThreadInitThunk+0x19
  20. 79 00dafb40 77c27084 ntdll!__RtlUserThreadStart+0x2f
  21. 80 00dafb9c 77c27054 ntdll!_RtlUserThreadStart+0x1b, calling ntdll!__RtlUserThreadStart
复制代码
              我们可以使用【!dumpstack -ee】只查看托管栈。
  1. 1 0:000> !dumpstack -ee
  2. 2 OS Thread Id: 0x710 (0)
  3. 3 Current frame:
  4. 4 ChildEBP RetAddr  Caller, Callee
  5. 5 00daef9c 70f79b71 (MethodDesc 70c438c4 +0x69 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
  6. 6 00daefc8 70f79b71 (MethodDesc 70c438c4 +0x69 DomainNeutralILStubClass.IL_STUB_PInvoke(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte*, Int32, Int32 ByRef, IntPtr))
  7. 7 00daf00c 716ab275 (MethodDesc 70cf7a24 +0x89 System.IO.__ConsoleStream.ReadFileNative(Microsoft.Win32.SafeHandles.SafeFileHandle, Byte[], Int32, Int32, Boolean, Boolean, Int32 ByRef))
  8. 8 00daf038 716ab17b (MethodDesc 70cf7a4c +0x9f System.IO.__ConsoleStream.Read(Byte[], Int32, Int32))
  9. 9 00daf064 70f5e6a3 (MethodDesc 70c2d964 +0x33 System.IO.StreamReader.ReadBuffer())
  10. 10 00daf07c 70f5eb5b (MethodDesc 70c2d96c +0xe3 System.IO.StreamReader.ReadLine())
  11. 11 00daf098 717f3786 (MethodDesc 70d22100 +0x1a System.IO.TextReader+SyncTextReader.ReadLine())
  12. 12 00daf0a8 71651845 (MethodDesc 70c19e00 +0x15 System.Console.ReadLine())
  13. 13 00daf0b0 0144088e (MethodDesc 01184d78 +0x46 Example_7_1_1.Program.Main(System.String[]))
复制代码
        2.8、使用【!eestack】和【~*e !dumpstack】查看所有的线程栈。
              测试源码:Example_7_1_1
  1. 1 0:000> !eestack
  2. 2 ---------------------------------------------
  3. 3 Thread   0
  4. 4 Current frame: ntdll!NtReadFile+0xc
  5. 5 ChildEBP RetAddr  Caller, Callee
  6. 6 。。。。
  7. 7 内容太多,省略了。
复制代码
            ~*e !dumpstack执行效果
  1. 1 0:000> ~*e !dumpstack
  2. 2 OS Thread Id: 0x710 (0)
  3. 3 Current frame: ntdll!NtReadFile+0xc
  4. 4 ChildEBP RetAddr  Caller, Callee
  5. 5 00daef38 75dbf25c KERNELBASE!ReadFile+0xec, calling ntdll!NtReadFile
  6. 6 ......
  7. 7 内容太多,省略了。
复制代码
             eestack 命令,可以增加参数,比如:-short,我们可以使用 SOS 的帮助命令查看某个命令的解释,比如:eestack。
  1. 1 0:010> !sos.help eestack
  2. 2 -------------------------------------------------------------------------------
  3. 3 !EEStack [-short] [-EE]
  4. 4
  5. 5 This command runs !DumpStack on all threads in the process. The -EE option is
  6. 6 passed directly to !DumpStack. The -short option tries to narrow down the
  7. 7 output to "interesting" threads only, which is defined by
  8. 8
  9. 9 1) The thread has taken a lock.(可以显示具有锁的线程)
  10. 10 2) The thread has been "hijacked" in order to allow a garbage collection.(可以显示被“劫持”的线程)
  11. 11 3) The thread is currently in managed code.(可以显示托管线程)
  12. 12
  13. 13 See the documentation for !DumpStack for more info.
复制代码
四、总结
    终于写完了,今天这篇文章是第六篇。我们了解了线程和线程调用栈,那调试起来我们就知道如何开始了,知道如何查找参数和局部变量,知道线程栈地址,哦我们可以输出线程栈的内容,对值类型和引用类型了解的也更深入了,当然对线程了解也更深入了,终于做到知其一也知其二了。其实这些知识是相互作用的,不是独立的,任何一个环节的调试,都需要很多技巧。好了,不说了,不忘初心,继续努力,希望老天不要辜负努力的人。

来源:https://www.cnblogs.com/PatrickLiu/archive/2023/11/10/17819104.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具