Net 高级调试之九:SOSEX 扩展命令介绍


风晓
风晓 2023-12-29 11:49:10 52280 赞同 0 反对 0
分类: 资源
一、介绍     今天是《Net 高级调试》的第九篇文章。这篇文章设计的内容挺多的,比如:扩展的断点支持,如何查找元数据,栈回溯,对象检查,死锁检测等等,内容挺多的。功能特别强大,使用特别方便,但是需要说明一点,这些功能不是 SOS 的功能,是 SOSEX 的扩展功能,但是,这一系列功能只是支持 Net Framework,在 Net Core 跨平台版本是不支持的。虽然这些都是基础,如果这些掌握不好,以后的高级调试的道路,也不好走。当然了,第一次看视频或者看书,是很迷糊的,不知道如何操作,还是那句老话,一遍不行,那就再来一遍,还不行,那就再来一遍,俗话说的好,书读千遍,其意自现。      如果在没有说明的情况下,所有代码的测试环境都是 Net Framewok 4.8,但是,有些项目需要使用 Net Core 的项目,我会在项目章节里进行说明。好了,废话不多说,开始我们今天的调试工作。

二、基础知识

    1、SOSEX调试扩展
        不得不说在调试 Net Framework 程序的时候,这个扩展调试组件的使用率是仅次于官方的 SOS 插件的,这个插件的一个特点就是能看到大量的命令是以 m 开头的,对应于 非托管命令的托管命令的表示。

        这一篇文章只是介绍常用的几个命令,如果大家想了解更多,可以使用【!sosex.help】命令,查看 SOSEX 插件的所有命令。

    2、几个相当实用的扩展命令。

        2.1、!mbp 下断点命令。
            相信大家都用过 !bp 命令,这个命令是可以对非托管函数下断点,如果我们想对托管函数下断点,就可以使用 【!mbp】 这个命令,它是【bp】命令托管形式,可以给托管方法下断点。

            【!mbp】命令使用的时候要注意一点,命令后跟的是文件名,包含后缀名,如果类是独立的类文件,就写这个类文件的名称就可以,如果是多个类包含在一个类文件里,就写包含多个类文件的名称就可以。

        2.2、观察对象布局。
            一般我们使用【!do】命令观察一个对象,但是这样只能观察到一个平面图,不能查看到立体的对象,如果想更全面的了解一个对象,我们可以使用【!mdt】命令,立体对象是指:引用类型包含引用类型,具有多层,【!do】命令只能查看当前层对象的结构。

        2.3、查找托管堆中指定的字符串。
            这个在 dump 调试的过程中做托管的内存搜索很有用,使用【!strings -m:xxx】命令。

        2.4、搜索元数据。
            我们在以前的调试 Notepad 的 SaveFile 方法的时候,使用【x】命令,这里也有对应的托管版本的命令,就是【!mx】,这个命令对于我们查找函数特别拥有。
        2.5、观察 Free 块。
            这是一个比较高级的命令,在分析托管堆碎片的时侯比较有用,能够提高分析效率。我们可以使用【!mfrag】命令。

        2.6、死锁检测。
            大家都知道【死锁】相互等待对方释放锁资源造成的,一旦出现了死锁的问题,我们可以用手工的方式分析出来的,但是这样费时费力,SOSEX 提供了一个检测命令,就是【!dlk(deadlock)】命令,用来检测死锁问题。

三、调试过程
    废话不多说,这一节是具体的调试操作的过程,又可以说是眼见为实的过程,在开始之前,我还是要啰嗦两句,这一节分为两个部分,第一部分是测试的源码部分,没有代码,当然就谈不上测试了,调试必须有载体。第二部分就是根据具体的代码来证实我们学到的知识,是具体的眼见为实。

    1、测试源码
        1.1、Example_9_1_1 项目的源码
            Program 的代码:

 View Code


            Address的代码:

 View Code


            Person的代码:

 View Code


        1.2、Example_9_1_2 项目的源码

 View Code


    2、眼见为实
        项目的所有操作都是一样的,所以就在这里说明一下,但是每个测试例子,都需要重新启动,并加载相应的应用程序,加载方法都是一样的。流程如下:我们编译项目,打开 Windbg,点击【文件】----》【launch executable】附加程序,打开调试器的界面,程序已经处于中断状态。

        2.1、我们使用【!mbp】命令给托管函数下断点(CLR没加载就可以下断点)。
            调试代码:Example_9_1_1
            我们的任务:给 Program 类的 Main 方法的第十行:int b = 11;下断点。
            我们进入 Windbg 界面,不需要运行,就可以直接下断点,虽然这个时候 CLR 还没有加载。【!mbp】命令后是程序文件名,必须包含文件扩展名,否则无效。

1 0:000> !mbp Program.cs 10
2 The CLR has not yet been initialized in the process.(CLR还没有被初始化)
3 Breakpoint resolution will be attempted when the CLR is initialized.

            我们已经成功下了断点,但是英文提示 CLR 还没有被加载,我们使用【lm】命令查看一下加载模块信息,显示如下。

复制代码
1 0:000> lm
2 start    end        module name
3 00a20000 00a28000   Example_9_1_1 C (pdb symbols)          C:\ProgramData\Dbg\sym\Example_9_1_1.pdb\...\Example_9_1_1.pdb
4 5bff0000 5c08f000   apphelp    (deferred)             
5 71520000 71572000   MSCOREE    (deferred)             
6 762f0000 76503000   KERNELBASE   (deferred)             
7 76ca0000 76d90000   KERNEL32   (deferred)             
8 76f10000 770b2000   ntdll      (pdb symbols)          C:\ProgramData\Dbg\sym\wntdll.pdb\DBC8C8F74C0E3696E951B77F0BB8569F1\wntdll.pdb
复制代码

            的确如此,加载的模块很少,根本没又看到 CLR 的影子。
            然后,我们【g】一下,就会到我们下的断点处暂停。效果如图:
            

            接下来,我们在另外一个类中给一个方法直接下断点,看看效果怎么样,如截图:
            

             我们执行【!mbp】命令,后面跟类名,包含后缀名和行号。

1 0:000> !mbp Person.cs 13
2 The CLR has not yet been initialized in the process.
3 Breakpoint resolution will be attempted when the CLR is initialized.

             然后,我们【g】一下,就会到我们下的断点处暂停。效果如图:
             

        2.2、我们如何立体的观察一个对象。
            调试代码:Example_9_1_1
            我们来看看 Person 对象的结构,它包含 string 类型的 Name 字段,包含 Address 引用类型,Address 又包含 String 类型的 Name字段,我们如何立体的查看它的结构呢?
            我们进入到 Windbg 调试界面,如果有断点存在,我们可以使用【bc *】命令将所有的断点全部清除,然后再使用【g】命令,运行程序,会在【Console.ReadLine();】这样代码处暂停,然后我们点击【Break】按钮,就是调试程序了。
            我们现在托管堆中查找一下 Person 对象,有了对象,才可以查看它的结构,使用【!dumpheap -type Person】命令查找。

复制代码
1 0:006> !dumpheap -type Person
2  Address       MT     Size
3 029324c8 00ee4e28       16     
4 
5 Statistics:
6       MT    Count    TotalSize Class Name
7 00ee4e28        1           16 Example_9_1_1.Person
8 Total 1 objects
复制代码

            上面列表中有了Person 对象地址和方法表的地址。

复制代码
1 0:006> !mdt 029324c8
2 029324c8 (Example_9_1_1.Person)
3     <Name>k__BackingField:NULL (System.String)
4     <Address>k__BackingField:029324ec (Example_9_1_1.Address)
5 0:006> !mdt 029324c8 -r
6 029324c8 (Example_9_1_1.Person)
7     <Name>k__BackingField:NULL (System.String)
8     <Address>k__BackingField:029324ec (Example_9_1_1.Address)
9         <Name>k__BackingField:029324d8 (System.String) Length=3, String="河北省"
复制代码

            如果我们想看【!mdt】如何使用,可以使用【!sosex.help !mdt】,这个输出太多,折叠了,可以自行查看。

 View Code


        2.3、使用【!strings】命令在托管堆中查找字符串。
            调试代码:Example_9_1_1
            我们进入到 Windbg 调试界面,如果有断点存在,我们可以使用【bc *】命令将所有的断点全部清除,然后再使用【g】命令,运行程序,会在【Console.ReadLine();】这样代码处暂停,然后我们点击【Break】按钮,就是调试程序了。
            如果我们直接使用【!strings】命令,没有任何参数,会把托管堆中的所有字符串全部打印出来。

复制代码
 1 0:006> !strings
 2 Address    Gen    Length   Value
 3 ---------------------------------------
 4 02931228    0          0   
 5 02931254    0         94   E:\Visual Studio 2022\...\Example_9_1_1\bin\Debug\
 6 02931320    0        118   E:\Visual Studio 2022\...\Example_9_1_1\bin\Debug\Example_9_1_1.exe.Config
 7 0293148c    0          4   true
 8 029314a4    0         32   PARTIAL_TRUST_VISIBLE_ASSEMBLIES
 9 02931538    0        111   E:\Visual Studio 2022\..\Example_9_1_1\bin\Debug\Example_9_1_1.exe
10 ...(省略很多)
11 02933d8c    0          8   encoding
12 02933dac    0          6   stream
13 0293421c    0          5   bytes
14 02934234    0          5   chars
15 0293424c    0          9   charCount
16 0293426c    0          9   charIndex
17 0293428c    0          9   byteCount
18 029349fc    0          5   count
19 02934a14    0          6   offset
20 ---------------------------------------
21 167 strings
复制代码

            上面的内容太多,我省略了,没必要全部显示出来。

复制代码
 1 0:006> !strings -m:河北*
 2 Address    Gen    Length   Value
 3 ---------------------------------------
 4 029324d8    0          3   河北省
 5 ---------------------------------------
 6 1 matching string
 7 0:006> !strings /m:河北*
 8 Address    Gen    Length   Value
 9 ---------------------------------------
10 029324d8    0          3   河北省
11 ---------------------------------------
12 1 matching string
复制代码

            m 前的可以是英文横线-,也可以是英文/斜线,可以使用 * 进行模糊匹配。有一点要注意:值是:河北省,可以通过 -m:河北*,这个参数是有效的,如果是 -m:河北省* 就是找不到的,体会使用的细节吧,完整字符串不需要增加 * 星号,增加时找不到的。

复制代码
1 0:006> !strings /m:河北省
2 Address    Gen    Length   Value
3 ---------------------------------------
4 029324d8    0          3   河北省
5 ---------------------------------------
6 1 matching string
复制代码


        2.4、我们在托管堆中使用【!mx】命令查找 Person 类型的 Show 方法。
            调试代码:Example_9_1_1
            我们进入到 Windbg 调试界面,如果有断点存在,我们可以使用【bc *】命令将所有的断点全部清除,然后再使用【g】命令,运行程序,会在【Console.ReadLine();】这样代码处暂停,然后我们点击【Break】按钮,就是调试程序了。

复制代码
1 0:006> !mx Example_9_1_1!*Show*
2 AppDomain 6e9fc7a8 (Shared Domain)
3 ---------------------------------------------------------
4 
5 AppDomain 00920db8 (Example_9_1_1.exe)
6 ---------------------------------------------------------
7 module: Example_9_1_1
8   class: Example_9_1_1.Person
9     Show()
复制代码

            【!mx】命令的参数是:模块名!*方法名*,* 星号表示模糊匹配。也可以通过【命名空间.类名.方法名】 来查找。

复制代码
1 0:006> !mx Example_9_1_1!Example_9_1_1.Person.Show
2 AppDomain 6e9fc7a8 (Shared Domain)
3 ---------------------------------------------------------
4 
5 AppDomain 00920db8 (Example_9_1_1.exe)
6 ---------------------------------------------------------
7 module: Example_9_1_1
8   class: Example_9_1_1.Person
9     Show()
复制代码

            红色标记的 Show 方法,在 Windbg 里是可以点击的,就相当于执行【!dumpmd】命令,查看方法的描述符。

复制代码
1 0:006> !dumpmd 00ee4e08
2 Method Name:  Example_9_1_1.Person.Show()
3 Class:        00ee1340
4 MethodTable:  00ee4e28
5 mdToken:      06000008
6 Module:       00ee4044
7 IsJitted:     yes
8 CodeAddr:     00f309d0
9 Transparency: Critical
复制代码

            【!name2ee】可以查找方法,但是不支持模糊匹配,要把完整路径,类名、方法名全部写出来才可以,否则找不到。

复制代码
0:006> !name2ee Example_9_1_1!Example_9_1_1.Person.Show
Module:      00ee4044
Assembly:    Example_9_1_1.exe
Token:       06000008
MethodDesc:  00ee4e08
Name:        Example_9_1_1.Person.Show()
JITTED Code Address: 00f309d0
复制代码

            省略模式是找不到的。

复制代码
 1 0:006> !name2ee Example_9_1_1!*Show*
 2 Module:      00ee4044
 3 Assembly:    Example_9_1_1.exe
 4 0:006> !name2ee Example_9_1_1!Example_9_1_1.Show*
 5 Module:      00ee4044
 6 Assembly:    Example_9_1_1.exe
 7 0:006> !name2ee Example_9_1_1!Example_9_1_1.Person.S*
 8 Module:      00ee4044
 9 Assembly:    Example_9_1_1.exe
10 0:006> !name2ee Example_9_1_1!Example_9_1_1.Person.Sho*
11 Module:      00ee4044
12 Assembly:    Example_9_1_1.exe
复制代码

            【!mx】命令可以支持模糊查询,方法,类型都能查找,比如:我们能查找 Person 类型,Person 的成员都显示出来了。

复制代码
 1 0:006> !mx Example_9_1_1!*Person*
 2 AppDomain 6e9fc7a8 (Shared Domain)
 3 ---------------------------------------------------------
 4 
 5 AppDomain 00920db8 (Example_9_1_1.exe)
 6 ---------------------------------------------------------
 7 module: Example_9_1_1
 8   class: Example_9_1_1.Person
 9     get_Name()
10     set_Name(string)
11     get_Address()
12     set_Address(Example_9_1_1.Address)
13     Show()
14     .ctor()
15     k__BackingField {fieldtype: string} 
16     k__BackingField {fieldtype: Example_9_1_1.Address} 
复制代码


        2.5、观察 Free 块。
            调试代码:Example_9_1_1
            我们进入到 Windbg 调试界面,如果有断点存在,我们可以使用【bc *】命令将所有的断点全部清除,然后再使用【g】命令,运行程序,会在【Console.ReadLine();】这样代码处暂停,然后我们点击【Break】按钮,就是调试程序了。
            

复制代码
1 0:006> !mfrag
2 Searching for pinned handles...
3 FreeBlock          Size   NextObject   MT         Name
4 -----------------------------------------------------------------
5 03931010             14   03931020     6ceb2788   System.Object[] (Pinned Handle @ 00ec13fc)
6 03932328             14   03932338     6ceb2788   System.Object[] (Pinned Handle @ 00ec13f4)
7 03932548             14   03932558     6ceb2788   System.Object[] (Pinned Handle @ 00ec13f0)
8 03933558             14   03933568     6ceb2788   System.Object[] (Pinned Handle @ 00ec13ec)
9 4 free blocks, 56 bytes
复制代码

            如果大家不知道什么是 free 块,我们可以使用【!dumpheap -stat】命令,查看一下托管堆的统计情况。

复制代码
 1 0:006> !dumpheap -stat
 2 Statistics:
 3       MT    Count    TotalSize Class Name
 4 6ceb5468        1           12 System.Collections.Generic.GenericEqualityComparer`1[[System.String, mscorlib]]
 5 6ceb4888        1           12 System.Security.HostSecurityManager
 6 6ceb3d78        1           12 System.Collections.Generic.ObjectEqualityComparer`1[[System.Type, mscorlib]]
 7 ...
 8 00919e18       10          116      Free(这就是 free 块,我们可以点击前面的地址)
 9 ...
10 6ceb5c40        3          806 System.Byte[]
11 6ceb2c60       10         2988 System.Char[]
12 6ceb24e4      167         5906 System.String
13 6ceb2788        6        17748 System.Object[]
14 Total 335 objects
复制代码

            这十个 free 块的详情如下:

复制代码
 1 0:006> !DumpHeap /d -mt 00919e18
 2  Address       MT     Size
 3 02931000 00919e18       10 Free
 4 0293100c 00919e18       10 Free
 5 02931018 00919e18       10 Free
 6 02931fd0 00919e18       10 Free
 7 02933df4 00919e18       10 Free
 8 03931000 00919e18       10 Free
 9 03931010 00919e18       14 Free
10 03932328 00919e18       14 Free
11 03932548 00919e18       14 Free
12 03933558 00919e18       14 Free
13 
14 Statistics:
15       MT    Count    TotalSize Class Name
16 00919e18       10          116      Free
17 Total 10 objects
复制代码


        2.6、我们使用【!dlk】命令检测死锁的问题。
            调试代码:Example_9_1_2
            这个项目的调试过程有些不同,我们可以直接运行我们的应用程序,然后打开 Windbg,通过【File】菜单选择【Attach to process】附加进程来调试程序。
            程序运行的结果如图:
            

            只会输出这两行文字,其他的无法输出,因为已经死锁了。剩下的就交给 Windbg 吧,Windbg 附加进程完毕,直接输入【!dlk】命令来检查。

复制代码
 1 0:005> !dlk
 2 Examining SyncBlocks...
 3 Scanning for ReaderWriterLock instances...
 4 Scanning for holders of ReaderWriterLock locks...
 5 Scanning for ReaderWriterLockSlim instances...
 6 Scanning for holders of ReaderWriterLockSlim locks...
 7 Examining CriticalSections...
 8 Scanning for threads waiting on SyncBlocks...
 9 Scanning for threads waiting on ReaderWriterLock locks...
10 Scanning for threads waiting on ReaderWriterLocksSlim locks...
11 Scanning for threads waiting on CriticalSections...
12 *DEADLOCK DETECTED*
13 CLR thread 0x4 holds the lock on SyncBlock 016d038c OBJ:033024d4[Example_9_1_2.Student](Clr 4号线程拥有 Student 的锁)
14 ...and is waiting for the lock on SyncBlock 016d0358 OBJ:033024c8[Example_9_1_2.Person](等待 Person 释放锁)
15 CLR thread 0x3 holds the lock on SyncBlock 016d0358 OBJ:033024c8[Example_9_1_2.Person](CLR 3 号线程拥有 Person 的锁)
16 ...and is waiting for the lock on SyncBlock 016d038c OBJ:033024d4[Example_9_1_2.Student](等待 Student 对象释放锁)
17 CLR Thread 0x4 is waiting at System.Threading.Monitor.Enter(System.Object, Boolean ByRef)(+0x18 Native) [f:\dd\ndp\clr\src\BCL\system\threading\monitor.cs @ 62,9]
18 CLR Thread 0x3 is waiting at System.Threading.Monitor.Enter(System.Object, Boolean ByRef)(+0x18 Native) [f:\dd\ndp\clr\src\BCL\system\threading\monitor.cs @ 62,9]
19 
20 
21 1 deadlock detected.(检测到死锁)
复制代码

            如果我们通过手工检查,需要检测同步块索引。

复制代码
 1 0:005> !syncblk
 2 Index         SyncBlock MonitorHeld Recursion Owning Thread Info          SyncBlock Owner
 3     8 016d0358            3         1 016e6710 43a8   3   033024c8 Example_9_1_2.Person
 4     9 016d038c            3         1 016e7738 3698   4   033024d4 Example_9_1_2.Student
 5 -----------------------------
 6 Total           9
 7 CCW             1
 8 RCW             2
 9 ComClassFactory 0
10 Free            0
复制代码

            我们继续使用【!t】命令,查看一下线程的信息。

复制代码
 1 0:005> !t
 2 ThreadCount:      4
 3 UnstartedThread:  0
 4 BackgroundThread: 3
 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 2314 016a70d0     2a020 Preemptive  03304F08:00000000 016a03b8 1     MTA 
11    2    2 43b8 016b8088     2b220 Preemptive  00000000:00000000 016a03b8 0     MTA (Finalizer) 
12    3    3 43a8 016e6710   3029220 Preemptive  03306444:00000000 016a03b8 1     MTA (Threadpool Worker) 
13    4    4 3698 016e7738   3029220 Preemptive  0330E6E0:00000000 016a03b8 1     MTA (Threadpool Worker) 
复制代码

            然后我们切换到3和4号线程分别看一下线程栈的情况。
            以下是3号线程的情况。

复制代码
 1 0:005> ~~[43a8]s
 2 eax=00000000 ebx=00000001 ecx=00000000 edx=00000000 esi=00000001 edi=00000001
 3 eip=76f8166c esp=05c4f0f8 ebp=05c4f288 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!NtWaitForMultipleObjects+0xc:
 6 76f8166c c21400          ret     14h
 7 
 8 0:003> !clrstack
 9 OS Thread Id: 0x43a8 (3)
10 Child SP       IP Call Site
11 05c4f450 76f8166c [GCFrame: 05c4f450] 
12 05c4f530 76f8166c [GCFrame: 05c4f530] 
13 05c4f54c 76f8166c [HelperMethodFrame_1OBJ: 05c4f54c] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
14 05c4f5c8 6d298468 System.Threading.Monitor.Enter(System.Object, Boolean ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\monitor.cs @ 62]
15 05c4f5d8 01560d03 Example_9_1_2.Program+c.b__2_0() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_9_1_2\Program.cs @ 20]
16 05c4f640 6d2fd4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
17 05c4f64c 6d2fb731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
18 05c4f670 6d2fb6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
19 05c4f674 6d298604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
20 05c4f6e0 6d298537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
21 05c4f6f4 6d2fb4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
22 05c4f758 6d2fb357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
23 05c4f768 6d2fb29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
24 05c4f76c 6d26eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
25 05c4f7bc 6d26e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
26 05c4f9dc 6e2bf036 [DebuggerU2MCatchHandlerFrame: 05c4f9dc] 
复制代码

            我们看看 4 号线程栈的情况。

复制代码
 1 0:003> ~~[3698]s
 2 eax=00000000 ebx=00000001 ecx=00000000 edx=00000000 esi=00000001 edi=00000001
 3 eip=76f8166c esp=05e0eba8 ebp=05e0ed38 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!NtWaitForMultipleObjects+0xc:
 6 76f8166c c21400          ret     14h
 7 
 8 
 9 0:004> !clrstack
10 OS Thread Id: 0x3698 (4)
11 Child SP       IP Call Site
12 05e0ef00 76f8166c [GCFrame: 05e0ef00] 
13 05e0efe0 76f8166c [GCFrame: 05e0efe0] 
14 05e0effc 76f8166c [HelperMethodFrame_1OBJ: 05e0effc] System.Threading.Monitor.ReliableEnter(System.Object, Boolean ByRef)
15 05e0f078 6d298468 System.Threading.Monitor.Enter(System.Object, Boolean ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\monitor.cs @ 62]
16 05e0f088 01560b73 Example_9_1_2.Program+c.b__2_1() [E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\Example_9_1_2\Program.cs @ 34]
17 05e0f0f0 6d2fd4bb System.Threading.Tasks.Task.InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2884]
18 05e0f0fc 6d2fb731 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
19 05e0f120 6d2fb6fc System.Threading.Tasks.Task.ExecutionContextCallback(System.Object) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2861]
20 05e0f124 6d298604 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
21 05e0f190 6d298537 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
22 05e0f1a4 6d2fb4b2 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
23 05e0f208 6d2fb357 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
24 05e0f218 6d2fb29d System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2704]
25 05e0f21c 6d26eb7d System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]
26 05e0f26c 6d26e9db System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 1161]
27 05e0f48c 6e2bf036 [DebuggerU2MCatchHandlerFrame: 05e0f48c] 
复制代码

            红色部分是需要特别关注的

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  126
统信桌面专业版【全盘安装UOS系统】介绍  121
银河麒麟桌面操作系统安装佳能打印机驱动方法  114
银河麒麟桌面操作系统 V10-SP1用户密码修改  105
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益209.03元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!