Introduzione a WinDbg (modalità kernel)
WinDbg è un debugger in modalità kernel e in modalità utente incluso in Strumenti di debug per Windows. Questo articolo fornisce esercizi utili per iniziare a usare WinDbg come debugger in modalità kernel.
Per informazioni su come ottenere gli strumenti di debug per Windows, vedere Scaricare e installare il debugger Windows WinDbg. Dopo aver installato gli strumenti di debug, individuare le directory di installazione per le versioni a 64 bit (x64) e a 32 bit (x86) degli strumenti. Ad esempio:
- C:\Programmi (x86)\Windows Kits\10\Debuggers\x64
- C:\Programmi (x86)\Windows Kits\10\Debuggers\x86
Configurare un debug in modalità kernel
Un ambiente di debug in modalità kernel ha in genere due computer, il computer host e il computer di destinazione. Il debugger viene eseguito nel computer host e il codice sottoposto a debug viene eseguito nel computer di destinazione. L'host e la destinazione sono collegati da un cavo di debug.
I debugger di Windows supportano i tipi di cavi seguenti:
- Ethernet
- USB 3.0
- Seriale (detto anche modem Null)
Per garantire velocità e affidabilità, è consigliabile usare un cavo Ethernet con un hub di rete locale. Il diagramma seguente illustra un host e un computer di destinazione connessi per il debug con un cavo Ethernet.
Un'opzione per le versioni precedenti di Windows consiste nell'usare un cavo diretto, ad esempio un cavo seriale.
Per informazioni dettagliate su come configurare i computer host e di destinazione, vedere Configurazione manuale del debug in modalità kernel.
Macchina virtuale - VM
Per informazioni sulla connessione di un debugger a una macchina virtuale Hyper-V, vedere Configurazione del debug di rete di una macchina virtuale - KDNET.
Stabilire una sessione di debug in modalità kernel
Dopo aver configurato il computer host e di destinazione e connetterli con un cavo di debug, è possibile stabilire una sessione di debug in modalità kernel. Seguire le istruzioni riportate nello stesso argomento usato per la configurazione. Ad esempio, se si decide di configurare i computer host e di destinazione per il debug su Ethernet, è possibile trovare istruzioni per stabilire una sessione di debug in modalità kernel nell'articolo seguente:
Introduzione all'uso di WinDbg
Nel computer host aprire WinDbg e stabilire una sessione di debug in modalità kernel con il computer di destinazione.
Per aprire il file CHM della documentazione del debugger, passare al menu ? e selezionare Contenuto. La documentazione del debugger è disponibile online anche in Strumenti di debug per Windows.
Quando si stabilisce una sessione di debug in modalità kernel, WinDbg potrebbe entrare automaticamente nel computer di destinazione. Se WinDbg non si interrompe, passare al menu Debug e selezionare Interrompi.
Nella riga di comando nella parte inferiore della finestra di WinDbg immettere il comando seguente:
L'output è simile all'esempio seguente:
Symbol search path is: srv* Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols
Il percorso di ricerca dei simboli indica a WinDbg dove cercare i file di simboli (PDB). Il debugger necessita di file di simboli per ottenere informazioni sui moduli di codice, ad esempio nomi di funzione e nomi di variabili.
Immettere il comando seguente, che indica a WinDbg di eseguire la ricerca iniziale e il caricamento dei file di simboli:
Per visualizzare un elenco di moduli caricati, immettere il comando seguente:
L'output è simile all'esempio seguente:
0:000>3: kd> lm start end module name fffff800`00000000 fffff800`00088000 CI (deferred) ... fffff800`01143000 fffff800`01151000 BasicRender (deferred) fffff800`01151000 fffff800`01163000 BasicDisplay (deferred) ... fffff800`02a0e000 fffff800`03191000 nt (pdb symbols) C:\...\ntkrnlmp.pdb fffff800`03191000 fffff800`03200000 hal (deferred) ...
Per avviare il computer di destinazione in esecuzione, immettere il comando seguente:
Per eseguire di nuovo l'interruzione, passare al menu Debug e selezionare Interrompi.
Immettere il comando seguente per esaminare il
_FILE_OBJECT
tipo di dati nelnt
modulo:L'output è simile all'esempio seguente:
0:000>0: kd> dt nt!_FILE_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x008 DeviceObject : Ptr64 _DEVICE_OBJECT +0x010 Vpb : Ptr64 _VPB ... +0x0c0 IrpList : _LIST_ENTRY +0x0d0 FileObjectExtension : Ptr64 Void
Immettere il comando seguente per esaminare alcuni dei simboli nel
nt
modulo:L'output è simile all'esempio seguente:
0:000>0: kd> x nt!*CreateProcess* fffff800`030821cc nt!ViCreateProcessCallbackInternal (<no parameter info>) ... fffff800`02e03904 nt!MmCreateProcessAddressSpace (<no parameter info>) fffff800`02cece00 nt!PspCreateProcessNotifyRoutine = <no type information> ...
Immettere il comando seguente per inserire un punto di interruzione in MmCreateProcessAddressSpace:
bu nt! MmCreateProcessAddressSpace
Per verificare che il punto di interruzione sia impostato, immettere il comando seguente:
L'output è simile all'esempio seguente:
0:000>0: kd> bu nt!MmCreateProcessAddressSpace 0: kd> bl 0 e fffff800`02e03904 0001 (0001) nt!MmCreateProcessAddressSpace
Immettere g per consentire l'esecuzione del computer di destinazione.
Se il computer di destinazione non si interrompe immediatamente nel debugger, eseguire alcune azioni nel computer di destinazione, ad esempio aprire Blocco note. Il computer di destinazione si interromperà nel debugger quando viene chiamato MmCreateProcessAddressSpace . Per visualizzare l'analisi dello stack, immettere i comandi seguenti:
L'output è simile all'esempio seguente:
0:000>2: kd> k Child-SP RetAddr Call Site ffffd000`224b4c88 fffff800`02d96834 nt!MmCreateProcessAddressSpace ffffd000`224b4c90 fffff800`02dfef17 nt!PspAllocateProcess+0x5d4 ffffd000`224b5060 fffff800`02b698b3 nt!NtCreateUserProcess+0x55b ... 000000d7`4167fbb0 00007ffd`14b064ad KERNEL32!BaseThreadInitThunk+0xd 000000d7`4167fbe0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
Scegliere Disassembly dal menu Visualizza.
Scegliere Esegui istruzione/routine dal menu Debug oppure premere F10. Immettere i comandi dei passaggi più volte quando si guarda la finestra Disassembly.
Cancellare il punto di interruzione immettendo il comando seguente:
Immettere g per consentire l'esecuzione del computer di destinazione. Per eseguire di nuovo l'interruzione, passare al menu Debug e selezionare Interrompi oppure premere CTRL+INTERR.
Per visualizzare un elenco di tutti i processi, immettere il comando seguente:
L'output è simile all'esempio seguente:
0:000>0: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS ffffe000002287c0 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001aa000 ObjectTable: ffffc00000003000 HandleCount: <Data Not Accessible> Image: System PROCESS ffffe00001e5a900 SessionId: none Cid: 0124 Peb: 7ff7809df000 ParentCid: 0004 DirBase: 100595000 ObjectTable: ffffc000002c5680 HandleCount: <Data Not Accessible> Image: smss.exe ... PROCESS ffffe00000d52900 SessionId: 1 Cid: 0910 Peb: 7ff669b8e000 ParentCid: 0a98 DirBase: 3fdba000 ObjectTable: ffffc00007bfd540 HandleCount: <Data Not Accessible> Image: explorer.exe
Copiare l'indirizzo di un processo e immettere il comando seguente:
Ad esempio:
!process ffffe00000d5290 2
L'output mostra i thread nel processo.
0:000>0:000>0: kd> !process ffffe00000d52900 2 PROCESS ffffe00000d52900 SessionId: 1 Cid: 0910 Peb: 7ff669b8e000 ParentCid: 0a98 DirBase: 3fdba000 ObjectTable: ffffc00007bfd540 HandleCount: Image: explorer.exe THREAD ffffe00000a0d880 Cid 0910.090c Teb: 00007ff669b8c000 ffffe00000d57700 SynchronizationEvent THREAD ffffe00000e48880 Cid 0910.0ad8 Teb: 00007ff669b8a000 ffffe00000d8e230 NotificationEvent ffffe00000cf6870 Semaphore Limit 0xffff ffffe000039c48c0 SynchronizationEvent ... THREAD ffffe00000e6d080 Cid 0910.0cc0 Teb: 00007ff669a10000 ffffe0000089a300 QueueObject
Copiare l'indirizzo di un thread e immettere il comando seguente:
Ad esempio:
!thread ffffe00000e6d080
L'output mostra informazioni sul singolo thread.
0: kd> !thread ffffe00000e6d080 THREAD ffffe00000e6d080 Cid 0910.0cc0 Teb: 00007ff669a10000 Win32Thread: 0000000000000000 WAIT: ... ffffe0000089a300 QueueObject Not impersonating DeviceMap ffffc000034e7840 Owning Process ffffe00000d52900 Image: explorer.exe Attached Process N/A Image: N/A Wait Start TickCount 13777 Ticks: 2 (0:00:00:00.031) Context Switch Count 2 IdealProcessor: 1 UserTime 00:00:00.000 KernelTime 00:00:00.000 Win32 Start Address ntdll!TppWorkerThread (0x00007ffd14ab2850) Stack Init ffffd00021bf1dd0 Current ffffd00021bf1580 Base ffffd00021bf2000 Limit ffffd00021bec000 Call 0 Priority 13 BasePriority 13 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5 ...
Per visualizzare tutti i nodi del dispositivo nell'albero dei dispositivi Plug and Play, immettere il comando seguente:
0:000>0: kd> !devnode 0 1 Dumping IopRootDeviceNode (= 0xffffe000002dbd30) DevNode 0xffffe000002dbd30 for PDO 0xffffe000002dc9e0 InstancePath is "HTREE\ROOT\0" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe000002d9d30 for PDO 0xffffe000002daa40 InstancePath is "ROOT\volmgr\0000" ServiceName is "volmgr" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe00001d49290 for PDO 0xffffe000002a9a90 InstancePath is "STORAGE\Volume\{3007dfd3-df8d-11e3-824c-806e6f6e6963}#0000000000100000" ServiceName is "volsnap" TargetDeviceNotify List - f 0xffffc0000031b520 b 0xffffc0000008d0f0 State = DeviceNodeStarted (0x308) Previous State = DeviceNodeStartPostWork (0x307) ...
Per visualizzare i nodi del dispositivo e le relative risorse hardware, immettere il comando seguente:
0:000>... DevNode 0xffffe000010fa770 for PDO 0xffffe000010c2060 InstancePath is "PCI\VEN_8086&DEV_2937&SUBSYS_2819103C&REV_02\3&33fd14ca&0&D0" ServiceName is "usbuhci" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) TranslatedResourceList at 0xffffc00003c78b00 Version 1.1 Interface 0x5 Bus #0 Entry 0 - Port (0x1) Device Exclusive (0x1) Flags (0x131) - PORT_MEMORY PORT_IO 16_BIT_DECODE POSITIVE_DECODE Range starts at 0x3120 for 0x20 bytes Entry 1 - DevicePrivate (0x81) Device Exclusive (0x1) Flags (0000) - Data - {0x00000001, 0x00000004, 0000000000} Entry 2 - Interrupt (0x2) Shared (0x3) Flags (0000) - LEVEL_SENSITIVE Level 0x8, Vector 0x81, Group 0, Affinity 0xf ...
Per visualizzare un nodo del dispositivo con un nome di servizio del disco, immettere il comando seguente:
0: kd> !devnode 0 1 disk Dumping IopRootDeviceNode (= 0xffffe000002dbd30) DevNode 0xffffe0000114fd30 for PDO 0xffffe00001159610 InstancePath is "IDE\DiskST3250820AS_____________________________3.CHL___\5&14544e82&0&0.0.0" ServiceName is "disk" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) ...
L'output di !devnode 0 1 mostra l'indirizzo dell'oggetto dispositivo fisico (PDO) per il nodo. Copiare l'indirizzo di un oggetto dispositivo fisico (PDO) e immettere il comando seguente:
Ad esempio:
<PdoAddress>!devstack 0xffffe00001159610
0:000>0: kd> !devstack 0xffffe00001159610 !DevObj !DrvObj !DevExt ObjectName ffffe00001d50040 \Driver\partmgr ffffe00001d50190 ffffe00001d51450 \Driver\disk ffffe00001d515a0 DR0 ffffe00001156e50 \Driver\ACPI ffffe000010d8bf0
Per ottenere informazioni sul driver disk.sys, immettere il comando seguente:
0:000>0: kd> !drvobj disk 2 Driver object (ffffe00001d52680) is for: \Driver\disk DriverEntry: fffff800006b1270 disk!GsDriverEntry DriverStartIo: 00000000 DriverUnload: fffff800010b0b5c CLASSPNP!ClassUnload AddDevice: fffff800010aa110 CLASSPNP!ClassAddDevice Dispatch routines: [00] IRP_MJ_CREATE fffff8000106d160 CLASSPNP!ClassGlobalDispatch [01] IRP_MJ_CREATE_NAMED_PIPE fffff80002b0ab24 nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE fffff8000106d160 CLASSPNP!ClassGlobalDispatch [03] IRP_MJ_READ fffff8000106d160 CLASSPNP!ClassGlobalDispatch ... [1b] IRP_MJ_PNP fffff8000106d160 CLASSPNP!ClassGlobalDispatch
L'output di
!drvobj
mostra gli indirizzi delle routine dispatch. Ad esempio:CLASSPNP!ClassGlobalDispatch
. Per impostare e verificare un punto di interruzione inClassGlobalDispatch
, immettere i comandi seguenti:bu CLASSPNP! ClassGlobalDispatch
Immettere
g
per consentire l'esecuzione del computer di destinazione.Se il computer di destinazione non si interrompe immediatamente nel debugger, eseguire alcune azioni nel computer di destinazione, ad esempio aprire il Blocco note e salvare un file. Il computer di destinazione si interromperà nel debugger quando
ClassGlobalDispatch
viene chiamato. Per visualizzare l'analisi dello stack, immettere i comandi seguenti:L'output è simile all'esempio seguente:
2: kd> k Child-SP RetAddr Call Site ffffd000`21d06cf8 fffff800`0056c14e CLASSPNP!ClassGlobalDispatch ffffd000`21d06d00 fffff800`00f2c31d volmgr!VmReadWrite+0x13e ffffd000`21d06d40 fffff800`0064515d fvevol!FveFilterRundownReadWrite+0x28d ffffd000`21d06e20 fffff800`0064578b rdyboost!SmdProcessReadWrite+0x14d ffffd000`21d06ef0 fffff800`00fb06ad rdyboost!SmdDispatchReadWrite+0x8b ffffd000`21d06f20 fffff800`0085cef5 volsnap!VolSnapReadFilter+0x5d ffffd000`21d06f50 fffff800`02b619f7 Ntfs!NtfsStorageDriverCallout+0x16 ...
Per terminare la sessione di debug, immettere il comando seguente:
Riepilogo dei comandi
- Comando Contenuto nel menu ?
- .sympath (Imposta percorso simbolo)
- Ricaricamento (modulo ricaricamento)
- x (esaminare i simboli)
- g (Vai)
- dt (tipo di visualizzazione)
- Comando Interrompi dal menu Debug
- lm (elencare i moduli caricati)
- k (backtrace dello stack di visualizzazione)
- bu (Imposta punto di interruzione)
- bl (elenco punti di interruzione)
- bc (punto di interruzione non crittografato)
- Comando Esegui istruzione nel menu Debug (F11)
- !processo
- !filo
- !devnode
- !devstack
- !drvobj
- qd (esci e scollega)