!deadlock

L’extension !deadlock affiche des informations sur les deadlocks collectés par l’option de détection de deadlock de Driver Verifier.

!deadlock 
!deadlock 1

DLL

Kdexts.dll

Informations supplémentaires

Pour des informations sur le Vérificateur de pilote, consultez la documentation du Kit de développement de pilotes Windows (WDK).

Notes

Cette extension fournira des informations utiles uniquement si l’option de détection de deadlock de Driver Verifier a détecté une violation de hiérarchie de verrouillage et a émis bug check 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).

Sans aucun argument, l’extension !deadlock provoque l’affichage de la topologie de base de la hiérarchie des verrous. Si le problème n’est pas un deadlock cyclique simple, cette commande décrira la situation qui s’est produite.

L’extension !deadlock 1 provoque l’affichage des traces de pile. Les piles affichées seront celles actives au moment de l’acquisition des verrous.

Voici un exemple :

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'

Cela vous indique quels threads et quels verrous sont impliqués. Cependant, cela est destiné à être un résumé et peut ne pas être suffisant pour déboguer adéquatement la situation.

Utilisez !deadlock 1 pour imprimer le contenu des piles d’appels au moment où chaque verrou participant au deadlock a été acquis. Comme il s’agit de traces de pile en cours d’exécution, elles seront plus complètes si une version compilée avec des vérifications est utilisée. Les versions compilées avec des vérifications étaient disponibles sur des versions plus anciennes de Windows avant Windows 10, version 1803. Sur une version non vérifiée, elles peuvent être tronquées dès une ligne.

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

Avec ces informations, vous avez presque tout ce dont vous avez besoin, sauf la pile actuelle :

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

À partir de cela, vous pouvez voir quels verrous étaient impliqués et où ils ont été acquis. Cela devrait être suffisant pour vous permettre de déboguer le deadlock. Si le code source est disponible, vous pouvez utiliser le débogueur pour voir exactement où le problème s’est produit :

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]

Maintenant, vous connaissez le nom du fichier source et le numéro de ligne où l’acquisition a eu lieu. Dans ce cas, les fichiers source montreront que les threads se sont comportés comme suit :

  • Thread 1 : DummyActivateVcComplete a pris le verrou miniport dummy. Il a ensuite appelé dummyQueueRecvBuffers, qui a pris le verrou global dummy.

  • Thread 2 : dummyRxInterruptOnCompletion a pris le verrou global. Puis, quelques lignes plus tard, il a pris le verrou miniport.

À ce stade, le deadlock devient entièrement clair.