Поделиться через


!Взаимоблокировки

Расширение !взаимоблокировки отображает сведения о взаимоблокировках, собранных параметром обнаружения взаимоблокировок средства проверки драйверов.

!deadlock 
!deadlock 1

DLL-библиотеки

Kdexts.dll

Дополнительная информация

Сведения о средстве проверки драйверов см. в документации по комплекту драйверов Windows (WDK).

Замечания

Это расширение предоставляет только полезную информацию, если параметр обнаружения взаимоблокировки средства проверки драйверов обнаружил нарушение иерархии блокировки и выдал ошибку проверка 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).

Без каких-либо аргументов расширение !взаимоблокировки приводит к отображению базовой топологии иерархии блокировки. Если проблема не является простой циклической взаимоблокировкой, эта команда описывает ситуацию, которая произошла.

Расширение !взаимоблокировки 1 приводит к отображению трассировок стека. Отображаемые стеки будут активными во время приобретения блокировок.

Рассмотрим пример:

0:kd> !deadlock

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'

Это указывает, какие потоки и какие блокировки участвуют. Однако она предназначена для сводки и может оказаться недостаточной информацией для адекватной отладки ситуации.

Используйте !взаимоблокировку 1 , чтобы распечатать содержимое стека вызовов во время получения каждой блокировки, участвующих в взаимоблокировке. Так как это трассировки стека во время выполнения, они будут более полными, если используется проверка сборка. Проверенные сборки были доступны в более ранних версиях Windows до Windows 10 версии 1803. В свободной сборке они могут быть усечены после одной строки.

0:kd> !deadlock 1

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 >>

С этой информацией у вас почти все необходимое, кроме текущего стека:

0: kd> k
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

Из этого можно увидеть, какие замки были вовлечены и где они были приобретены. Это должно быть достаточно информации для отладки взаимоблокировки. Если исходный код доступен, можно использовать отладчик, чтобы увидеть, где возникла проблема:

0: kd> .lines
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]

Теперь вы знаете имя исходного файла и номер строки, в которой произошло приобретение. В этом случае исходные файлы показывают, что потоки ведут себя следующим образом:

  • Поток 1: DummyActivateVcComplete взял фиктивную минипорт-блокировку. Затем она называется dummyQueueRecvBuffers, которая взяла фиктивную глобальную блокировку.

  • Поток 2: dummyRxInterruptOnCompletion взял глобальную блокировку. Затем, несколько строк позже, он взял минипорт блокировки.

На этом этапе взаимоблокировка становится совершенно ясной.