Condividi tramite


!Deadlock

L'estensione !deadlock visualizza informazioni sui deadlock raccolti dall'opzione Rilevamento deadlock di Driver Verifier.

!deadlock 
!deadlock 1

DLL

Kdexts.dll

Informazioni aggiuntive

Per informazioni su Driver Verifier, vedere la documentazione di Windows Driver Kit (WDK).

Osservazioni:

Questa estensione fornirà informazioni utili solo se l'opzione Di rilevamento deadlock di Driver Verifier ha rilevato una violazione della gerarchia di blocchi e ha emesso il controllo dei bug 0xC4 (DRIVER_VERIFIER_DETECTED_VIOLATION).

Senza argomenti, l'estensione !deadlock determina la visualizzazione della topologia della gerarchia di blocchi di base. Se il problema non è un semplice deadlock ciclico, questo comando descriverà la situazione che si è verificata.

L'estensione !deadlock 1 determina la visualizzazione delle analisi dello stack. Gli stack visualizzati saranno quelli attivi al momento dell'acquisizione dei blocchi.

Ecco un esempio:

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'

Questo indica quali thread e quali blocchi sono coinvolti. Tuttavia, è destinato a essere un riepilogo e potrebbe non essere sufficiente informazioni per eseguire il debug adeguato della situazione.

Usare !deadlock 1 per stampare il contenuto degli stack di chiamate al momento dell'acquisizione di ogni blocco che partecipa al deadlock. Poiché si tratta di analisi dello stack di runtime, saranno più complete se viene usata una compilazione controllata. Le build controllate erano disponibili nelle versioni precedenti di Windows precedenti a Windows 10, versione 1803. In una compilazione gratuita, possono essere troncati dopo appena una riga.

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

Con queste informazioni sono disponibili quasi tutti gli elementi necessari, ad eccezione dello stack corrente:

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

Da questo è possibile vedere quali blocchi sono stati coinvolti e dove sono stati acquisiti. Queste informazioni dovrebbero essere sufficienti per eseguire il debug del deadlock. Se il codice sorgente è disponibile, è possibile usare il debugger per verificare esattamente dove si è verificato il problema:

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]

Ora si conosce il nome del file di origine e il numero di riga in cui è stata eseguita l'acquisizione. In questo caso, i file di origine mostreranno che i thread si comportavano nel modo seguente:

  • Thread 1: DummyActivateVcComplete ha preso il blocco miniport fittizio . Ha poi chiamato dummyQueueRecvBuffers, che ha preso il blocco globale fittizio .

  • Thread 2: dummyRxInterruptOnCompletion ha preso il blocco globale. Poi, qualche riga più tardi, ha preso il blocco miniport.

A questo punto, il deadlock diventa completamente chiaro.