Debugging Tools for Windows |
!deadlock扩展显示通过驱动程序验证器(Driver Verifier)的Deadlock Detection选项搜集的死锁(deadlock)信息。
!deadlock 1
Windows 2000 | 不可用 |
Windows XP和之后 | Kdexts.dll |
该扩展命令只有在驱动程序验证器的Deadlock Detection选项检测到加锁层次违例(lock hierarchy violation)并产生bug check 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION)时,才能提供有用的信息。
不带任何参数时,!deadlock扩展显示基本的加锁的拓扑层次。如果问题不是一帮的循环死锁,该命令会描述遇到了什么情况。
!deadlock 1 扩展显示堆栈回溯。该堆栈是锁被请求时活动的调用堆栈。
下面是一个示例:
Deadlock detected (2 resources in 2 threads):
Thread 0: A B
Thread 1: B A
Where:
Thread 0 = 8d3ba030
Thread 1 = 8d15c030
Lock A = bba2af30 Type 'Spinlock'
Lock B = dummy!GlobalLock Type 'Spinlock'
显示出了相关的锁和线程。但是,这只是一个摘要信息,可能还不足以调试遇到的问题。
使用!deadlock 1来打印出死锁相关的每个锁被请求时的堆栈回溯。由于这是运行时堆栈回溯,所以在使用调试版时会更加完整。在free版上,它们可能在一行之后就被截断了。
Deadlock detected (2 resources in 2 threads):
Thread 0 (8D14F750) took locks in the following order:
Lock A -- b7906f30 (Spinlock)
Stack: dummy!DummyActivateVcComplete+0x63
dummy!dummyOpenVcChannels+0x2E1
dummy!DummyAllocateRecvBufferComplete+0x436
dummy!DummyAllocateComplete+0x55
NDIS!ndisMQueuedAllocateSharedHandler+0xC9
NDIS!ndisWorkerThread+0xEE
Lock B -- dummy!GlobalLock (Spinlock)
Stack: dummy!dummyQueueRecvBuffers+0x2D
dummy!DummyActivateVcComplete+0x90
dummy!dummyOpenVcChannels+0x2E1
dummy!DummyAllocateRecvBufferComplete+0x436
dummy!DummyAllocateComplete+0x55
Thread 1 (8D903030) took locks in the following order:
Lock B -- dummy!GlobalLock (Spinlock)
Stack: dummy!dummyRxInterruptOnCompletion+0x25D
dummy!DummyHandleInterrupt+0x32F
NDIS!ndisMDpcX+0x3C
ntkrnlpa!KiRetireDpcList+0x5D
Lock A -- b7906f30 (Spinlock)
Stack: << Current stack >>
除了当前堆栈之外,这些基本上就是所有需要的信息了。
ChildEBP RetAddr
f78aae6c 80664c58 ntkrnlpa!DbgBreakPoint
f78aae74 8066523f ntkrnlpa!ViDeadlockReportIssue+0x2f
f78aae9c 806665df ntkrnlpa!ViDeadlockAnalyze+0x253
f78aaee8 8065d944 ntkrnlpa!VfDeadlockAcquireResource+0x20b
f78aaf08 bfd6df46 ntkrnlpa!VerifierKeAcquireSpinLockAtDpcLevel+0x44
f78aafa4 b1bf2d2d dummy!dummyRxInterruptOnCompletion+0x2b5
f78aafc4 bfde9d8c dummy!DummyHandleInterrupt+0x32f
f78aafd8 804b393b NDIS!ndisMDpcX+0x3c
f78aaff4 804b922b ntkrnlpa!KiRetireDpcList+0x5d
从上面这些可以知道有哪些相关的锁,以及它们在什么地方被请求的。这对于调试死锁来说已经包含了足够信息。如果可以使用源码,则还可以使用调试器来查看问题具体出现在什么地方:
Line number information will be loaded
0: kd> u dummy!DummyActivateVcComplete+0x63 l1
dummy!DummyActivateVcComplete+63 [d:\nt\drivers\dummy\vc.c @ 2711]:
b1bfe6c9 837d0c00 cmp dword ptr [ebp+0xc],0x0
0: kd> u dummy!dummyQueueRecvBuffers+0x2D l1
dummy!dummyQueueRecvBuffers+2d [d:\nt\drivers\dummy\receive.c @ 2894]:
b1bf4e39 807d0c01 cmp byte ptr [ebp+0xc],0x1
0: kd> u dummy!dummyRxInterruptOnCompletion+0x25D l1
dummy!dummyRxInterruptOnCompletion+25d [d:\nt\drivers\dummy\receive.c @ 1424]:
b1bf5d05 85f6 test esi,esi
0: kd> u dummy!dummyRxInterruptOnCompletion+0x2b5 l1
dummy!dummyRxInterruptOnCompletion+2b5 [d:\nt\drivers\dummy\receive.c @ 1441]:
b1bf5d5d 8b4648 mov eax,[esi+0x48]
现在就知道了源文件的名字,以及请求锁的位置的行号。这种情况下,源文件表明了这些线程的行为如下:
通过这点,死锁原因就清楚了。
关于驱动程序验证器的信息,查看Windows Driver Kit (WDK) 文档。