windbg-!cs、~~[TID](经典死锁)

原文链接 https://blog.csdn.net/hgy413/article/details/7572097#comments,这位大神对windbg和汇编都有很多优秀的原创文章

运行,生成release版本,去掉pdb,运行,程序停住了,windbg加载到进程,

先用~*kb查看下所有的线程堆栈:

0:005> ~*kn
 
   0  Id: 2d68.b3b8 Suspend: 1 Teb: 00772000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0098fb24 76bdae72 ntdll!ZwWaitForSingleObject+0xc
01 0098fb38 729dbd40 KERNELBASE!WaitForSingleObject+0x12
02 0098fbbc 729dc702 MSVCR90!wunlink+0x5bf
03 0098fbe0 729dc84b MSVCR90!spawnv+0xb7
04 0098fc18 729dcc71 MSVCR90!spawnve+0x12a
05 0098fc50 008810a8 MSVCR90!system+0x8e
06 0098fca0 76a462c4 Test+0x10a8
07 0098fcb4 776f0fd9 KERNEL32!BaseThreadInitThunk+0x24
08 0098fcfc 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
09 0098fd0c 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404
 
   1  Id: 2d68.aef8 Suspend: 1 Teb: 00775000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 00cefc68 76a462c4 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 00cefc7c 776f0fd9 KERNEL32!BaseThreadInitThunk+0x24
02 00cefcc4 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
03 00cefcd4 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404
 
   2  Id: 2d68.8f38 Suspend: 1 Teb: 00778000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 00e2fe94 76a462c4 ntdll!NtWaitForWorkViaWorkerFactory+0xc
01 00e2fea8 776f0fd9 KERNEL32!BaseThreadInitThunk+0x24
02 00e2fef0 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
03 00e2ff00 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404
 
   3  Id: 2d68.b1b4 Suspend: 1 Teb: 0077b000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 00f6fb80 776b6f0d ntdll!NtWaitForAlertByThreadId+0xc
01 00f6fbc4 776b6dff ntdll!RtlWaitOnAddress+0x1dd
02 00f6fc00 776d0045 ntdll!RtlWaitOnAddress+0xcf
03 00f6fc20 776cff65 ntdll!RtlEnterCriticalSection+0x125
04 00f6fc2c 0088101d ntdll!RtlEnterCriticalSection+0x45
05 00f6fc4c 776f0fd9 Test+0x101d
06 00f6fc94 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
07 00f6fca4 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404
 
   4  Id: 2d68.20bc Suspend: 1 Teb: 0077e000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 010ffce0 776b6f0d ntdll!NtWaitForAlertByThreadId+0xc
01 010ffd24 776b6dff ntdll!RtlWaitOnAddress+0x1dd
02 010ffd60 776d0045 ntdll!RtlWaitOnAddress+0xcf
03 010ffd80 776cff65 ntdll!RtlEnterCriticalSection+0x125
04 010ffd8c 0088104d ntdll!RtlEnterCriticalSection+0x45
05 010ffdac 776f0fd9 Test+0x104d
06 010ffdf4 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
07 010ffe04 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404
 
#  5  Id: 2d68.1f98 Suspend: 1 Teb: 00781000 Unfrozen
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 0153fecc 76a462c4 ntdll!DbgBreakPoint
01 0153fee0 776f0fd9 KERNEL32!BaseThreadInitThunk+0x24
02 0153ff28 776f0fa4 ntdll!RtlSubscribeWnfStateChangeNotification+0x439
03 0153ff38 00000000 ntdll!RtlSubscribeWnfStateChangeNotification+0x404

我们注意到3,4号线程的线程堆栈是从ntdll!RtlEnterCriticalSection中开始的,那么ntdll!RtlEnterCriticalSection又是什么函数的入口呢,首先猜到的是EnterCriticalSection,这个函数是kernel32.dll中的,为了验证猜测,我们用dump查看到kernel32.dll的导出函数:

!cs

!cs 扩展显示一个或多个临界区(critical section)或者整个临界区树

前面说的ntdll!RtlEnterCriticalSection的第一个参数是临界区的地址,事实上用uf反汇编它,可以看到是ret 4,说明就只有一个参数

那么,
!cs Address 指定要显示的临界区地址。 如果省略该参数,调试器显示当前进程中所有临界区。 !cs -s 如果可能的话,显示每个临界区的初始堆栈回溯。 !cs -l 仅显示锁定的临界区。

从底层来讲,关键区机制是通过_RTL_CRITICAL_SECTION来实现的

扫描二维码关注公众号,回复: 13426469 查看本文章

这意思就是3号线程等待的 临界区 00883374拥有者是4号线程,4号线程等待的 临界区 0088338c 拥有者是3号线程

这里LockCount为1意思为除了一个线程拥有它外,另外还有一个线程在等待它,它是由EnterCriticalSection增加,LeaveCriticalSection来减小的,比如我再加一点代码:

可以发现LockCount变成了2,如果 临界区是有信号的,则显示NOT LOCKED(值为-1) OwningThread表示拥有这个 临界区的线程ID,RecursionCount表示拥有线程调了几次 EnterCriticalSection,这其实也影响到了LockCount,如果拥有线程多调用一次 EnterCriticalSection,那么 LockCount也会相应加1,因为LockCount标识了任意线程调用 EnterCriticalSection请求这个互斥量的次数减1,(所以0-1=-1为NOT LOCKED)当然,前面如果调用了 LeaveCriticalSection,那么 LockCount也会相应减1
 

!cs starAddress EndAddress指定要搜索临界区的地址范围

猜你喜欢

转载自blog.csdn.net/u014421422/article/details/115510142
Tid
cs
今日推荐