Eseguire il debug dei driver windows step-by-step lab (modalità kernel echo)

Questo lab introduce il debugger del kernel WinDbg. Si usa WinDbg per eseguire il debug del codice del driver di esempio in modalità kernel echo.

Obiettivi del lab

Questo lab include esercizi che introducono gli strumenti di debug, insegnano i comandi di debug comuni, illustrano l'uso dei punti di interruzione e illustrano come usare le estensioni di debug.

In questo lab si usa una connessione di debug del kernel live per esplorare le azioni seguenti:

  • Usare i comandi del debugger di Windows
  • Usare comandi standard (stack di chiamate, variabili, thread, IRQL)
  • Usare i comandi avanzati di debug dei driver (!commands)
  • Usare i simboli
  • Impostare punti di interruzione nel debug in tempo reale
  • Visualizzare gli stack di chiamate
  • Visualizzare l'albero dei dispositivi Plug and Play
  • Usare il contesto del thread e del processo

Debug in modalità utente e kernel

Quando si usa il debugger Windows, è possibile eseguire due tipi di debug:

Modalità utente: le applicazioni e i sottosistemi vengono eseguiti nel computer in modalità utente. I processi eseguiti in modalità utente eseguono questa operazione all'interno dei propri spazi indirizzi virtuali. Sono limitati a ottenere l'accesso diretto a molte parti del sistema, tra cui hardware di sistema, memoria non allocata per il loro uso e altre parti del sistema che potrebbero compromettere l'integrità del sistema. Poiché i processi eseguiti in modalità utente sono effettivamente isolati dal sistema e da altri processi in modalità utente, non possono interferire con queste risorse.

Modalità kernel: il sistema operativo e i programmi con privilegi vengono eseguiti in modalità kernel. Il codice in modalità kernel ha l'autorizzazione per accedere a qualsiasi parte del sistema. Non è limitato come il codice in modalità utente. Può ottenere l'accesso a qualsiasi parte di qualsiasi altro processo in esecuzione in modalità utente o kernel. Gran parte delle funzionalità principali del sistema operativo e molti driver di dispositivo hardware vengono eseguiti in modalità kernel.

Questo esercizio illustra i comandi di debug usati di frequente durante il debug in modalità utente e in modalità kernel. L'esercizio illustra anche le estensioni di debug, talvolta denominate "bang" !commands, usate per il debug in modalità kernel.

Configurazione del laboratorio

Per completare il lab sono necessari gli hardware seguenti:

  • Un computer portatile o desktop (host) che esegue Windows 10
  • Un secondo computer portatile o desktop (destinazione) che esegue Windows 10
  • Un hub di rete o un router e cavi di rete per connettere i due computer
  • Accesso a Internet per scaricare i file di simboli

Per completare il lab, è necessario il software seguente:

  • Visual Studio
  • Windows Software Development Kit (SDK) per Windows 10
  • Windows Driver Kit (WDK) per Windows 10
  • Il driver echo di esempio per Windows 10

Il lab include le sezioni seguenti:

Connettersi a una sessione WinDbg in modalità kernel

In questa sezione configurare il debug di rete nel sistema host e di destinazione.

I computer in questo lab devono essere configurati per usare una connessione di rete Ethernet per il debug del kernel.

Questo lab usa due computer. Il debugger Windows viene eseguito nel sistema host e il driver echo KMDF (Kernel Mode Driver Framework) viene eseguito nel sistema di destinazione .

Usare un hub di rete o un router e cavi di rete per connettere i due computer.

Diagramma che illustra due computer connessi tramite un hub di rete o un router.

Per usare applicazioni in modalità kernel e usare WinDbg, è consigliabile usare il trasporto KDNET su Ethernet. Per informazioni su come usare il protocollo di trasporto Ethernet, vedere Introduzione a WinDbg (modalità kernel). Per altre informazioni sulla configurazione del computer di destinazione, vedere Preparazione di un computer per la distribuzione manuale dei driver e Configurazione automatica del debug del kernel di rete KDNET.

Configurare il debug in modalità kernel tramite Ethernet

Per abilitare il debug in modalità kernel nel sistema di destinazione:

  1. Nel sistema host aprire una finestra del prompt dei comandi e immettere ipconfig per determinare l'indirizzo IPv4.

    Windows IP Configuration
    Ethernet adapter Ethernet:
       Connection-specific DNS Suffix  . :
       Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b%3
       Autoconfiguration IPv4 Address. . : 169.182.1.1
       Subnet Mask . . . . . . . . . . . : 255.255.0.0
       Default Gateway . . . . . . . . . :
    
  2. Registrare l'indirizzo IP del sistema host: ______________________________________

  3. Nel sistema di destinazione aprire una finestra del prompt dei comandi e usare il comando per verificare la ping connettività di rete tra i due sistemi.

    ping 169.182.1.1
    

    Usare l'indirizzo IP effettivo del sistema host registrato anziché 169.182.1.1 visualizzato nell'output di esempio.

    Pinging 169.182.1.1 with 32 bytes of data:
    Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    
    Ping statistics for 169.182.1.1:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 0ms, Maximum = 1ms, Average = 0ms
    

Abilitare il debug in modalità kernel nel sistema di destinazione completando i passaggi seguenti.

Importante

Prima di usare BCDEdit per modificare le informazioni di avvio, potrebbe essere necessario sospendere temporaneamente le funzionalità di sicurezza di Windows, ad esempio BitLocker e Avvio protetto nel computer di test. Riabilitare queste funzionalità di sicurezza al termine del test. Gestire in modo appropriato il computer di test quando le funzionalità di sicurezza sono disabilitate. L'avvio protetto è in genere disabilitato in UEFI. Per accedere all'impostazione UEFI, usa sistema, ripristino, avvio avanzato. Al riavvio selezionare Risoluzione dei problemi, Opzioni avanzate, Impostazioni firmware UEFI. Prestare attenzione, poiché l'impostazione non corretta delle opzioni UEFI o la disabilitazione di BitLocker possono rendere il sistema inutilizzabile.

  1. Nel computer di destinazione aprire una finestra del prompt dei comandi come amministratore. Immettere questo comando per abilitare il debug:

    bcdedit /set {default} DEBUG YES
    
  2. Immettere questo comando per abilitare la firma di test:

    bcdedit /set TESTSIGNING ON 
    
  3. Immettere questo comando per impostare l'indirizzo IP del sistema host. Usare l'indirizzo IP del sistema host registrato in precedenza, non quello visualizzato.

    bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    

    Avviso

    Per aumentare la sicurezza della connessione e ridurre il rischio delle richieste di connessione casuali del debugger client, usare una chiave casuale generata automaticamente. Per altre informazioni, vedere Configurazione automatica del debug del kernel di rete KDNET.

  4. Immettere questo comando per verificare che i valori per dbgsettings siano impostati correttamente:

    bcdedit /dbgsettings
    
    key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    debugtype               NET
    hostip                  169.168.1.1
    port                    50000
    dhcp                    Yes
    The operation completed successfully.
    

    Nota

    Se si riceve un messaggio dal firewall e si vuole usare il debugger, selezionare tutte e tre le caselle.

    Screenshot della finestra di dialogo avviso Sicurezza di Windows che indica che Windows Firewall ha bloccato alcune funzionalità di un'app.

  5. Nel computer host aprire una finestra del prompt dei comandi come amministratore. Questo lab usa la versione x64 di WinDbg.exe di Windows Driver Kit (WDK) installata nell'ambito dell'installazione di Windows Kit. Passare alla directory WinDbg predefinita. Il percorso predefinito è illustrato di seguito.

    cd C:\Program Files(x86)\Windows Kits\10\Debuggers\x64 
    

    Questo lab presuppone che entrambi i computer eseguano una versione a 64 bit di Windows sia nella destinazione che nell'host. In caso contrario, l'approccio migliore consiste nell'eseguire lo stesso bit degli strumenti nell'host eseguito dalla destinazione. Ad esempio, se la destinazione esegue Windows a 32 bit, eseguire una versione a 32 bit del debugger nell'host. Per altre informazioni, vedere Scelta degli strumenti di debug a 32 bit o a 64 bit.

  6. Aprire WinDbg con il debug dell'utente remoto usando il comando seguente. I valori per la chiave e la porta corrispondono ai valori impostati in precedenza usando BCDEdit nel computer di destinazione.

    WinDbg –k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  7. Riavviare il sistema di destinazione.

  8. In un minuto o due, l'output di debug deve essere visualizzato nel sistema host.

    Microsoft (R) Windows Debugger Version 10.0.17074.1002 AMD64
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    Using NET for debugging
    Opened WinSock 2.0
    Waiting to reconnect...
    Connected to target 169.182.1.1 on port 50005 on local IP 169.182.1.2
    You can get the target MAC address by running .kdtargetmac command.
    Connected to Windows 10 16299 x64 target at (Wed Feb 28 17:16:23.051 2018 (UTC - 8:00)), ptr64 TRUE
    Kernel Debugger connection established.  (Initial Breakpoint requested)
    Symbol search path is: srv*
    Executable search path is: 
    Windows 10 Kernel Version 16299 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 16299.15.amd64fre.rs3_release.170928-1534
    Machine Name:
    Kernel base = 0xfffff800`9540d000 PsLoadedModuleList = 0xfffff800`95774110
    Debug session time: Wed Feb 28 17:16:23.816 2018 (UTC - 8:00)
    System Uptime: 0 days 0:00:20.534
    

La finestra Comando debugger è la finestra principale delle informazioni di debug in WinDbg. È possibile immettere i comandi del debugger e visualizzare l'output del comando in questa finestra.

La finestra Comando debugger è suddivisa in due riquadri. Immettere i comandi nel riquadro più piccolo, ovvero il riquadro di immissione dei comandi nella parte inferiore della finestra e visualizzare l'output del comando nel riquadro più grande nella parte superiore della finestra.

Nel riquadro della voce di comando usare i tasti freccia SU e Freccia GIÙ per scorrere la cronologia dei comandi. Quando viene visualizzato un comando, è possibile modificarlo o premere INVIO per eseguire il comando.

Comandi e tecniche di debug in modalità kernel

In questa sezione usare i comandi di debug per visualizzare informazioni sul sistema di destinazione.

Alcuni comandi di debug visualizzano testo usando DML (Debugger Markup Language) che è possibile selezionare per raccogliere rapidamente altre informazioni.

  1. Nel sistema host usare CTRL+Scroll Lock in WinDBg per suddividere il codice in esecuzione nel sistema di destinazione. La risposta del sistema di destinazione potrebbe richiedere del tempo.

    Schermata principale del debugger che mostra l'output della finestra di comando da una connessione kernel dinamica.

  2. Immettere il comando seguente per abilitare DML nella finestra Di comando del debugger:

    0: kd> .prefer_dml 1
    DML versions of commands on by default
    
  3. È possibile accedere alla Guida del comando di riferimento usando il .hh comando . Immettere il comando seguente per visualizzare la Guida di riferimento ai comandi per .prefer_dml:

    0: kd> .hh .prefer_dml
    

    Il file della Guida del debugger visualizza la Guida per il .prefer_dml comando .

    Screenshot dell'applicazione della Guida del debugger che mostra la Guida per il comando .prefer-dml.

  4. Per visualizzare informazioni dettagliate sulla versione nel sistema di destinazione, immettere il comando vertarget (Mostra versione computer di destinazione) nella finestra WinDbg:

    0: kd> vertarget
    Windows 10 Kernel Version 9926 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 9926.0.amd64fre.fbl_awesome1501.150119-1648
    Machine Name: ""
    Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0
    Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)
    System Uptime: 0 days 01:31:58.931
    
  5. Per verificare di usare il processo in modalità kernel corretto, immettere il comando lm (Elenca moduli caricati) nella finestra WinDbg per visualizzare i moduli caricati:

    0: Kd> lm
    start             end                 module name
    fffff801`09200000 fffff801`0925f000   volmgrx    (no symbols)
    fffff801`09261000 fffff801`092de000   mcupdate_GenuineIntel   (no symbols)
    fffff801`092de000 fffff801`092ec000   werkernel   (export symbols)       werkernel.sys
    fffff801`092ec000 fffff801`0934d000   CLFS       (export symbols)       CLFS.SYS
    fffff801`0934d000 fffff801`0936f000   tm         (export symbols)       tm.sys
    fffff801`0936f000 fffff801`09384000   PSHED      (export symbols)       PSHED.dll
    fffff801`09384000 fffff801`0938e000   BOOTVID    (export symbols)       BOOTVID.dll
    fffff801`0938e000 fffff801`093f7000   spaceport   (no symbols)
    fffff801`09400000 fffff801`094cf000   Wdf01000   (no symbols)
    fffff801`094d9000 fffff801`09561000   CI         (export symbols)       CI.dll
    ...
    

    L'output omesso è indicato con "..." in questo lab.

  6. Per richiedere informazioni dettagliate su un modulo specifico, usare l'opzione v (dettagliata):

    0: Kd> lm v m tcpip
    Browse full module list
    start             end                 module name
    fffff801`09eeb000 fffff801`0a157000   tcpip      (no symbols)           
        Loaded symbol image file: tcpip.sys
        Image path: \SystemRoot\System32\drivers\tcpip.sys
        Image name: tcpip.sys
        Browse all global symbols  functions  data
        Timestamp:        Sun Nov 09 18:59:03 2014 (546029F7)
        CheckSum:         00263DB1
        ImageSize:        0026C000
        Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    
    Unable to enumerate user-mode unloaded modules, Win32 error 0n30
    

    Non sono presenti percorsi di simboli impostati e simboli caricati, quindi nel debugger sono disponibili informazioni limitate.

Scaricare e compilare il driver echo KMDF

In questa sezione scaricare e compilare il driver echo KMDF.

In genere, si sta usando il proprio codice driver quando si usa WinDbg. Per acquisire familiarità con l'operazione WinDbg, questo lab usa il driver di esempio "Echo" del modello KMDF. Il codice sorgente è disponibile per comprendere le informazioni visualizzate in WinDbg. Questo esempio viene usato anche per illustrare come è possibile eseguire codice in modalità kernel nativo in un unico passaggio. Questa tecnica può essere utile per il debug di problemi complessi di codice in modalità kernel.

Per scaricare e compilare il driver audio di esempio Echo:

  1. Scaricare ed estrarre l'esempio Echo kmDF da GitHub.

    L'esempio Echo KMDF si trova nella cartella generale .

    Screenshot della pagina windows-driver-samples di GitHub che evidenzia la cartella generale e il pulsante ZIP di download.

    1. Scaricare gli esempi di driver in un unico file ZIP: Esempi di driver

    2. Scaricare il file ZIP nel disco rigido locale.

    3. Selezionare e tenere premuto o fare clic con il pulsante destro del mouse sul file ZIP e scegliere Estrai tutto. Specificare una nuova cartella oppure passare a una cartella esistente per archiviare i file estratti. Ad esempio, è possibile specificare C:\DriverSamples\ come nuova cartella in cui estrarre i file.

    4. Dopo aver estratto i file, passare alla sottocartella seguente: C:\DriverSamples\general\echo\kmdf

  2. In Microsoft Visual Studio selezionare File>Apri>progetto/soluzione e passare alla cartella contenente i file estratti, ad esempio C:\DriverSamples\general\echo\kmdf. Fare doppio clic sul file della soluzione kmdfecho per aprirlo.

    In Visual Studio individuare il Esplora soluzioni. Se questa finestra non è già aperta, selezionare Esplora soluzioni dal menu Visualizza. In Esplora soluzioni è possibile visualizzare una soluzione con tre progetti.

    Screenshot di Visual Studio che mostra il file device.c caricato dal progetto kmdfecho.

  3. Impostare la configurazione e la piattaforma dell'esempio. In Esplora soluzioni selezionare e tenere premuto o fare clic con il pulsante destro del mouse su Soluzione 'kmdfecho' (3 progetti) e selezionare Configuration Manager. Assicurarsi che le impostazioni di configurazione e piattaforma siano le stesse per i tre progetti. Per impostazione predefinita, la configurazione è impostata su Debug Win10 e la piattaforma è impostata su Win64 per tutti i progetti. Se si apportano modifiche alla configurazione o alla piattaforma per un progetto, apportare le stesse modifiche per i tre progetti rimanenti.

  4. Gli esempi di driver devono essere modificati per usare valori che non si sovrappongono ai driver esistenti. Fare riferimento a From Sample Code to Production Driver - What to Change in the Samples on how to create a unique driver sample that will coesistere with existing real drivers installed in Windows.Refer to From Sample Code to Production Driver - What to Change in the Samples on how to create a unique driver sample that will coesiste with existing real drivers installed in Windows.

  5. Impostare la libreria di runtime. Aprire la pagina delle proprietà del driver echo e individuare la generazione di codice C/C++>. Modificare la libreria di runtime in Debug multithread (/MTd). Per altre informazioni sulle opzioni di compilazione, vedere /MD, /MT, /LD (Usare la libreria di runtime).For more information about the build options, see /MD, /MT, /LD (Use Run-Time Library).

    Screenshot della pagina delle proprietà echo in Visual Studio che evidenzia l'impostazione della libreria di runtime.

  6. Nelle proprietà del driver verificare che la modalità di>firma del driver sia impostata su Test Sign (Firma del driver).

    Screenshot della pagina delle proprietà echo in Visual Studio che evidenzia l'impostazione della modalità di firma.

  7. In Visual Studio selezionare Compila soluzione di>compilazione.

    Le finestre di compilazione devono visualizzare un messaggio che indica che la compilazione per tutti e tre i progetti è riuscita.

Suggerimento

Se viene visualizzato un messaggio di errore di compilazione, usare il numero di errore di compilazione per determinare una correzione. Ad esempio, l'errore di MSBuild MSB8040 descrive come usare le librerie con mitigazione spectre.

  1. In Esplora file passare alla cartella contenente i file estratti per l'esempio. Ad esempio, passare a C:\DriverSamples\general\echo\kmdf, se si tratta della cartella specificata in precedenza. All'interno di tale cartella, il percorso dei file del driver compilati varia a seconda delle impostazioni di configurazione e piattaforma selezionate in Configuration Manager. Se le impostazioni predefinite sono rimaste invariate, i file del driver compilati vengono salvati in una cartella denominata \x64\Debug per una build di debug a 64 bit.

    Passare alla cartella contenente i file compilati per il driver di sincronizzazione automatica: C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug.

    La cartella deve contenere questi file:

    File Descrizione
    Echo.sys File del driver.
    Echo.inf File di informazioni (INF) che contiene le informazioni necessarie per installare il driver.

    Inoltre, il file echoapp.exe è stato compilato e dovrebbe trovarsi qui: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug.

    File Descrizione
    EchoApp.exe File di test eseguibile del prompt dei comandi che comunica con il driver echo.sys.
  2. Individuare un'unità usb o configurare una condivisione di rete per copiare i file del driver compilati e il test EchoApp dall'host al sistema di destinazione.

Nella sezione successiva copiare il codice nel sistema di destinazione e installare e testare il driver.

Installare l'esempio di echo driver KMDF nel sistema di destinazione

In questa sezione usare lo strumento DevCon per installare il driver di esempio echo.

Il computer in cui si installa il driver viene chiamato computer di destinazione o computer di test. In genere, questo computer è separato dal computer in cui si sviluppa e si compila il pacchetto driver. Il computer in cui si sviluppa e si compila il driver viene chiamato computer host.

Il processo di spostamento del pacchetto driver nel computer di destinazione e l'installazione del driver viene chiamato distribuzione del driver.

Prima di distribuire un driver firmato per il test, preparare il computer di destinazione abilitando la firma dei test. È anche necessario individuare lo strumento DevCon nell'installazione di WDK e copiarlo nel sistema di destinazione.

Per installare il driver nel sistema di destinazione, seguire questa procedura.

Nel sistema di destinazione abilitare i driver firmati di test:

  1. Aprire Impostazioni di Windows.

  2. In Aggiornamento e sicurezza selezionare Ripristino.

  3. In Avvio avanzato selezionare Riavvia ora.

  4. Al riavvio del computer, selezionare Opzioni di avvio. In Windows 10 selezionare Risoluzione dei problemi Opzioni>avanzate>Impostazioni di avvio, quindi selezionare Riavvia.

  5. Selezionare Disabilita l'imposizione della firma del driver premendo F7.

  6. Riavviare il computer di destinazione.

Nel sistema host passare alla cartella Strumenti nell'installazione di WDK e individuare lo strumento DevCon. Ad esempio, cercare nella cartella seguente: C:\Programmi (x86)\Windows Kits\10\Tools\x64\devcon.exe.

Creare una cartella nella destinazione per il pacchetto driver compilato, ad esempio C:\EchoDriver. Copiare devcon.exe nel sistema di destinazione. Individuare il certificato .cer nel sistema host. Si trova nella stessa cartella del computer host nella cartella che contiene i file del driver compilati. Copiare tutti i file dal driver compilato descritto in precedenza nel computer host e salvarli nella stessa cartella creata nel computer di destinazione.

Nel computer di destinazione selezionare e tenere premuto o fare clic con il pulsante destro del mouse sul file del certificato e selezionare Installa, quindi seguire le istruzioni per installare il certificato di test.

Se sono necessarie istruzioni più dettagliate per la configurazione del computer di destinazione, vedere Preparazione di un computer per la distribuzione manuale dei driver.

Le istruzioni seguenti illustrano come installare e testare il driver di esempio. Ecco la sintassi generale per lo strumento devcon che si usa per installare il driver:

devcon install <INF file> <hardware ID>

Il file INF necessario per l'installazione di questo driver è echo.inf. Il file inf contiene l'ID hardware per l'installazione del echo.sys. Per l'esempio echo, l'ID hardware è root\ECHO.

Nel computer di destinazione aprire una finestra del prompt dei comandi come amministratore. Passare alla cartella del pacchetto driver e immettere il comando seguente:

devcon install echo.inf root\ECHO

Se viene visualizzato un messaggio di errore relativo a devcon non riconosciuto, provare ad aggiungere il percorso allo strumento devcon . Ad esempio, se è stato copiato in una cartella denominata C:\Tools, provare a usare il comando seguente:

c:\tools\devcon install echo.inf root\ECHO

Viene visualizzata una finestra di dialogo che indica che il driver di test è un driver non firmato. Selezionare Installa questo driver comunque per continuare.

Screenshot di Sicurezza di Windows avviso che informa che Windows non è in grado di verificare l'autore del software driver.

Suggerimento

 Se si verificano problemi con l'installazione, controllare il file seguente per altre informazioni. %windir%\inf\setupapi.dev.log

Dopo aver installato correttamente il driver di esempio, è possibile testarlo.

Nel computer di destinazione, in una finestra del prompt dei comandi, immettere devmgmt per aprire Gestione dispositivi. In Gestione dispositivi scegliere Dispositivi per tipo dal menu Visualizza. Nell'albero dei dispositivi individuare Sample WDF Echo Driver (Driver Echo WDF di esempio) nel nodo Sample Device (Dispositivo di esempio).

Screenshot dell'albero Gestione dispositivi che evidenzia il driver echo WDF di esempio.

Immettere echoapp per avviare l'app echo di test per verificare che il driver sia funzionante.

C:\Samples\KMDF_Echo_Sample> echoapp
DevicePath: \\?\root#sample#0005#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a}
Opened device successfully
512 Pattern Bytes Written successfully
512 Pattern Bytes Read successfully
Pattern Verified successfully
30720 Pattern Bytes Written successfully
30720 Pattern Bytes Read successfully
Pattern Verified successfully

Usare WinDbg per visualizzare informazioni sul driver

In questa sezione impostare il percorso del simbolo e usare i comandi del debugger del kernel per visualizzare informazioni sul driver echo echo kmDF.

Per visualizzare informazioni sul driver:

  1. Nel sistema host, se il debugger è stato chiuso, aprirlo di nuovo usando il comando seguente nella finestra del prompt dei comandi dell'amministratore.

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Usare CTRL+INTERR (blocco di scorrimento) per suddividere il codice in esecuzione nel sistema di destinazione.

  3. Per impostare il percorso dei simboli sul server dei simboli Microsoft nell'ambiente WinDbg, usare il .symfix comando .

    0: kd> .symfix
    
  4. Per aggiungere la posizione del simbolo locale per usare i simboli locali, aggiungere il percorso usando .sympath+ e quindi .reload /f.

    0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf
    0: kd> .reload /f
    

    Il .reload comando con l'opzione /f force elimina tutte le informazioni sui simboli per il modulo specificato e ricarica i simboli. In alcuni casi, questo comando ricarica o scarica il modulo stesso.

È necessario caricare i simboli appropriati per usare funzionalità avanzate fornite da WinDbg. Se i simboli non sono configurati correttamente, quando si tenta di usare funzionalità dipendenti dai simboli, si ricevono messaggi che indicano che i simboli non sono disponibili.

0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type “.hh dbgerr005” for details.

Esistono molti approcci che possono essere usati per lavorare con i simboli. In molte situazioni, è possibile configurare il computer per accedere ai simboli da un server di simboli fornito da Microsoft quando sono necessari. Questo lab usa questo approccio. Se i simboli nell'ambiente si trovano in una posizione diversa, modificare i passaggi per usare tale posizione. Per altre informazioni, vedere Percorso dei simboli per il debugger di Windows.

Per eseguire il debug di origine, è necessario compilare una versione controllata (debug) dei file binari. Il compilatore crea file di simboli (file con estensione pdb ). Questi file di simboli mostrano al debugger il modo in cui le istruzioni binarie corrispondono alle righe di origine. Anche i file di origine effettivi devono essere accessibili al debugger.

I file di simboli non contengono il testo del codice sorgente. Per il debug, è preferibile se il linker non ottimizza il codice. Il debug dell'origine e l'accesso alle variabili locali sono più difficili e talvolta quasi impossibili, se il codice è stato ottimizzato. Se si verificano problemi durante la visualizzazione di variabili locali o righe di origine, impostare le opzioni di compilazione seguenti:

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. Immettere il comando seguente nell'area di comando del debugger per visualizzare informazioni sul driver echo:

    0: kd> lm m echo* v
    Browse full module list
    start             end                 module name
    fffff801`4ae80000 fffff801`4ae89000   ECHO       (private pdb symbols)  C:\Samples\KMDF_ECHO_SAMPLE\echo.pdb
        Loaded symbol image file: ECHO.sys
        Image path: \SystemRoot\system32\DRIVERS\ECHO.sys
        Image name: ECHO.sys
    ...  
    

    Per altre informazioni, vedere lm.

  2. Poiché questo lab impostato prefer_dml in precedenza, alcuni elementi dell'output sono collegamenti ad accesso frequente che è possibile selezionare. Selezionare il collegamento Sfoglia tutti i simboli globali nell'output di debug per visualizzare informazioni sui simboli degli elementi che iniziano con la lettera "a".

    0: kd> x /D Echo!a*
    
  3. L'esempio echo non contiene simboli che iniziano con la lettera "a", quindi digitare x ECHO!Echo* per visualizzare informazioni su tutti i simboli associati al driver echo che iniziano con "Echo".

    0: kd> x ECHO!Echo*
    fffff801`0bf95690 ECHO!EchoEvtIoQueueContextDestroy (void *)
    fffff801`0bf95000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    fffff801`0bf95ac0 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    fffff801`0bf9b120 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    ...
    

    Per altre informazioni, vedere x (Esaminare i simboli).

  4. L'estensione !lmi visualizza informazioni dettagliate su un modulo. Immetti !lmi echo. L'output dovrebbe essere simile al testo illustrato in questo esempio:

    0: kd> !lmi echo
    Loaded Module Info: [echo] 
             Module: ECHO
       Base Address: fffff8010bf94000
         Image Name: ECHO.sys
    … 
    
  5. Usare l'estensione per visualizzare le informazioni sull'intestazione !dh , come illustrato in questo esempio:

    0: kd> !dh echo
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
         14C machine (i386)
           6 number of sections
    54AD8A42 time date stamp Wed Jan 07 11:34:26 2015
    ...
    
  6. Immettere quanto segue per modificare la maschera di bit di debug predefinita in modo che tutti i messaggi di debug dal sistema di destinazione vengano visualizzati nel debugger:

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    

    Alcuni driver visualizzano informazioni aggiuntive quando viene usata la maschera di 0xFFFFFFFF. Impostare la maschera su 0x00000000 se si vuole ridurre la quantità di informazioni visualizzate.

    0: kd> ed nt!Kd_DEFAULT_MASK 0x00000000
    

    Usare il dd comando per verificare che la maschera sia impostata per visualizzare tutti i messaggi del debugger.

    0: kd> dd nt!kd_DEFAULT_MASK 
    fffff802`bb4057c0  ffffffff 00000000 00000000 00000000
    fffff802`bb4057d0  00000000 00000000 00000000 00000000
    fffff802`bb4057e0  00000001 00000000 00000000 00000000
    fffff802`bb4057f0  00000000 00000000 00000000 00000000
    fffff802`bb405800  00000000 00000000 00000000 00000000
    fffff802`bb405810  00000000 00000000 00000000 00000000
    fffff802`bb405820  00000000 00000000 00000000 00000000
    fffff802`bb405830  00000000 00000000 00000000 00000000
    

Visualizzare le informazioni sull'albero dei dispositivi Plug and Play

In questa sezione vengono visualizzate informazioni sul driver di dispositivo echo sample e sulla posizione in cui si trova nell'albero dei dispositivi Plug and Play.

Le informazioni sul driver di dispositivo nell'albero dei dispositivi Plug and Play possono essere utili per la risoluzione dei problemi. Ad esempio, se un driver di dispositivo non è residente nell'albero dei dispositivi, potrebbe verificarsi un problema con l'installazione del driver di dispositivo.

Per altre informazioni sull'estensione di debug del nodo del dispositivo, vedere !devnode.

  1. Nel sistema host immettere il !devnode 0 1 comando per visualizzare tutti i nodi del dispositivo nell'albero dei dispositivi Plug and Play.

    0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30)
    DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0…
    …
    
  2. Usare CTRL+F per cercare nell'output generato per cercare il nome del driver di dispositivo, echo.

    Screenshot della finestra di dialogo Trova in WinDbg che cerca il termine

  3. Il driver del dispositivo echo deve essere caricato. Usare il !devnode 0 1 echo comando per visualizzare le informazioni di Plug and Play associate al driver di dispositivo echo, come illustrato in questo esempio:

    0: Kd> !devnode 0 1 echo
    Dumping IopRootDeviceNode (= 0xffffe0007b725d30)
    DevNode 0xffffe0007b71a630 for PDO 0xffffe0007b71a960
      InstancePath is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    …
    
  4. L'output visualizzato nel comando precedente include il PDO associato all'istanza in esecuzione del driver, in questo esempio 0xffffe0007b71a960. Immettere il !devobj <PDO address> comando per visualizzare le informazioni di Plug and Play associate al driver di dispositivo echo. Usare l'indirizzo PDO visualizzato !devnode nel computer, non quello mostrato qui.

    0: kd> !devobj 0xffffe0007b71a960
    Device object (ffffe0007b71a960) is for:
     0000000e \Driver\PnpManager DriverObject ffffe0007b727e60
    Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
    Dacl ffffc102c9b36031 DevExt 00000000 DevObjExt ffffe0007b71aab0 DevNode ffffe0007b71a630 
    ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe000801fee20 \Driver\ECHO
    Device queue is not busy.
    
  5. L'output visualizzato nel !devnode 0 1 comando include l'indirizzo PDO associato all'istanza in esecuzione del driver, in questo esempio è 0xffffe0007b71a960. Immettere il !devstack <PDO address> comando per visualizzare le informazioni di Plug and Play associate al driver di dispositivo. Usare l'indirizzo PDO visualizzato !devnode nel computer, non quello illustrato in questo esempio.

    0: kd> !devstack 0xffffe0007b71a960
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe000801fee20  \Driver\ECHO       ffffe0007f72eff0  
    > ffffe0007b71a960  \Driver\PnpManager 00000000  0000000e
    !DevNode ffffe0007b71a630 :
      DeviceInst is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
    

L'output mostra che si dispone di uno stack di driver di dispositivo abbastanza semplice. Il driver echo è un elemento figlio del nodo PnPManager . PnPManager è un nodo radice.

\Driver\ECHO
\Driver\PnpManager

Questo diagramma mostra un albero dei nodi del dispositivo più complesso.

Diagramma che illustra un albero dei nodi del dispositivo costituito da circa 20 nodi.

Per altre informazioni sugli stack di driver più complessi, vedere Stack di driver e nodi del dispositivo e stack di dispositivi.

Usare punti di interruzione e codice sorgente

In questa sezione impostare i punti di interruzione e il codice sorgente in modalità kernel in un unico passaggio.

Per poter eseguire il codice e controllare i valori delle variabili in tempo reale, abilitare i punti di interruzione e impostare un percorso al codice sorgente.

I punti di interruzione arrestano l'esecuzione del codice in una determinata riga di codice. Procedere nel codice da quel punto per eseguire il debug di tale sezione specifica del codice.

Per impostare un punto di interruzione usando un comando di debug, usare uno dei comandi seguenti b .

Comando Descrizione
bp Imposta un punto di interruzione attivo fino a quando il modulo in cui si trova non viene scaricato.
bu Imposta un punto di interruzione non risolto quando il modulo viene scaricato e riattiva quando il modulo viene ricaricato.
bm Imposta un punto di interruzione per un simbolo. Questo comando usa bu o bp in modo appropriato e consente l'uso di caratteri jolly (*) per impostare punti di interruzione su ogni simbolo corrispondente, come tutti i metodi di una classe.

Per altre informazioni, vedere Debug del codice sorgente in WinDbg.

  1. Nel sistema host usare l'interfaccia utente winDbg per verificare che la modalità di origine di debug>sia abilitata nella sessione WinDbg corrente.

  2. Immettere il comando seguente per aggiungere il percorso del codice locale al percorso di origine:

    .srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  3. Immettere il comando seguente per aggiungere la posizione del simbolo locale al percorso del simbolo:

    .sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  4. Usare il x comando per esaminare i simboli associati al driver echo per determinare il nome della funzione da usare per il punto di interruzione. È possibile usare un carattere jolly o CTRL+F per individuare il nome della DeviceAdd funzione.

    0: kd> x ECHO!EchoEvt*
    8b4c7490          ECHO!EchoEvtIoQueueContextDestroy (void *)
    8b4c7000          ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    8b4c7820          ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    8b4cb0e0          ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    8b4c75d0          ECHO!EchoEvtIoWrite (struct WDFQUEUE__ *, struct WDFREQUEST__ *, unsigned int)
    8b4cb170          ECHO!EchoEvtDeviceAdd (struct WDFDRIVER__ *, struct 
    …
    

    L'output mostra che il DeviceAdd metodo per il driver echo è ECHO!EchoEvtDeviceAdd.

    In alternativa, esaminare il codice sorgente per trovare il nome della funzione per il punto di interruzione.

  5. Impostare il punto di interruzione con il bm comando usando il nome del driver, seguito dal nome della funzione, ad esempio , AddDevicedove si vuole impostare il punto di interruzione, separato da un punto esclamativo. Questo lab usa AddDevice per controllare il driver caricato.

    0: kd> bm ECHO!EchoEvtDeviceAdd
      1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
    

    È possibile usare una sintassi diversa insieme all'impostazione di variabili come <module>!<symbol>, <class>::<method>'<file.cpp>:<line number>'o ignorare un numero di volte <condition> <#>. Per altre informazioni, vedere Punti di interruzione condizionali in WinDbg e altri debugger Windows.

  6. Elencare i punti di interruzione correnti per verificare che il punto di interruzione sia stato impostato immettendo il bl comando :

    0: kd> bl
    1 e fffff801`0bf9b1c0     0001 (0001) ECHO!EchoEvtDeviceAdd
    

    L'output "e" illustrato di seguito indica che il punto di interruzione numero 1 è abilitato per l'attivazione.

  7. Riavviare l'esecuzione del codice nel sistema di destinazione immettendo il g comando (vai).

  8. Nel sistema di destinazione, in Windows, aprire Gestione dispositivi usando l'icona o immettendo mmc devmgmt.msc. In Gestione dispositivi espandere il nodo Esempi.

  9. Selezionare e tenere premuto o fare clic con il pulsante destro del mouse sulla voce del driver echo KMDF e scegliere Disabilita dal menu.

  10. Selezionare e tenere premuto o fare di nuovo clic con il pulsante destro del mouse sulla voce del driver echo KMDF e scegliere Abilita dal menu.

  11. Nel sistema host, quando il driver è abilitato, verrà attivato il punto di interruzione di debug AddDevice . L'esecuzione del codice driver nel sistema di destinazione deve interrompersi. Quando viene raggiunto il punto di interruzione, l'esecuzione deve essere arrestata all'inizio della routine AddDevice . L'output del comando di debug visualizza Breakpoint 1 hit.

    Screenshot di WinDbg che mostra le variabili locali del codice di esempio e le finestre dei comandi.

  12. Scorrere la riga di codice in base alla riga immettendo il p comando o premendo F10 fino a raggiungere la fine seguente della routine AddDevice . Il carattere parentesi graffa (}) è evidenziato come illustrato.

    Screenshot della finestra del codice con il carattere parentesi graffa evidenziato all'inizio della routine AddDevice.

Nella sezione successiva esaminare lo stato delle variabili dopo l'esecuzione del codice DeviceAdd.

È possibile modificare i punti di interruzione esistenti usando i comandi seguenti:

Comando Descrizione
bl Elenca i punti di interruzione.
bc Cancella un punto di interruzione dall'elenco. Utilizzare bc * per cancellare tutti i punti di interruzione.
bd Disabilita un punto di interruzione. Usare bd * per disabilitare tutti i punti di interruzione.
be Abilita un punto di interruzione. Usare be * per abilitare tutti i punti di interruzione.

In alternativa, è anche possibile modificare i punti di interruzione nell'interfaccia utente di WinDbg.

È anche possibile impostare punti di interruzione attivati quando si accede a una posizione di memoria. Usare il ba comando (interruzione all'accesso) con la sintassi seguente:

ba <access> <size> <address> {options}
Opzione Descrizione
e execute: quando la CPU recupera un'istruzione dall'indirizzo
r lettura/scrittura: quando la CPU legge o scrive nell'indirizzo
w write: quando la CPU scrive nell'indirizzo

È possibile impostare solo quattro punti di interruzione dei dati in un determinato momento. Spetta all'utente assicurarsi di allineare correttamente i dati per attivare il punto di interruzione. Le parole devono terminare in indirizzi divisibile per 2, dwords deve essere divisibile per 4 e quad parole per 0 o 8.

Ad esempio, per impostare un punto di interruzione di lettura/scrittura in un indirizzo di memoria specifico, è possibile usare un comando come questo esempio.

ba r 4 0x0003f7bf0

È possibile usare i comandi seguenti per scorrere il codice con i tagli brevi della tastiera associati visualizzati tra parentesi.

  • Interrompi (CTRL+INTERR). Questo comando interrompe un sistema finché il sistema è in esecuzione ed è in comunicazione con WinDbg. La sequenza nel debugger del kernel è CTRL+C.
  • Esegui fino al cursore (F7 o CTRL+F10). Posizionare il cursore in una finestra di origine o disassembly in cui si desidera interrompere l'esecuzione, quindi premere F7. L'esecuzione del codice viene eseguita a quel punto. Se il flusso di esecuzione del codice non raggiunge il punto indicato dal cursore, WinDbg non interromperà. Questa situazione può verificarsi se un'istruzione IF non viene eseguita.
  • Esegui (F5). Eseguire fino a quando non viene rilevato un punto di interruzione o si verifica un evento come un controllo di bug.
  • Eseguire il passaggio (F10). Questo comando fa sì che l'esecuzione del codice proceda a un'istruzione o a un'istruzione alla volta. Se viene rilevata una chiamata, l'esecuzione del codice passa attraverso la chiamata senza immettere la routine chiamata. Se il linguaggio di programmazione è C o C++ e WinDbg è in modalità di origine, la modalità di origine può essere attivata o disattivata tramite la modalità di origine di debug>.
  • Eseguire l'istruzione in (F11). Questo comando è simile al passaggio, ad eccezione del fatto che l'esecuzione di una chiamata passa alla routine chiamata.
  • Esci (MAIUSC+F11). Questo comando causa l'esecuzione e l'uscita dalla routine corrente o dalla posizione corrente nello stack di chiamate. Questo comando è utile se si è visto abbastanza della routine.

Per altre informazioni, vedere Debug del codice sorgente in WinDbg.

Visualizzare variabili e stack di chiamate

In questa sezione vengono visualizzate informazioni sulle variabili e sugli stack di chiamate.

Questo lab presuppone che l'utente venga arrestato nella routine AddDevice usando il processo descritto in precedenza. Per visualizzare l'output illustrato qui, ripetere i passaggi descritti in precedenza, se necessario.

Nel sistema host, per visualizzare le variabili, usare la voce di menu locale di visualizzazione>per visualizzare le variabili locali.

Screenshot di WinDbg che mostra la finestra delle variabili locali.

Per trovare la posizione di un indirizzo variabile globale, immettere ? <variable name>.

  • Esci (MAIUSC+F11): questo comando causa l'esecuzione e l'uscita dalla routine corrente (posizione corrente nello stack di chiamate). Questo è utile se hai visto abbastanza della routine.

Per altre informazioni, vedere Debug del codice sorgente in WinDbg (versione classica) nella documentazione di riferimento sul debug.

Sezione 8: Visualizzazione di variabili e stack di chiamate

Nella sezione 8 verranno visualizzate informazioni sulle variabili e sugli stack di chiamate.

Questo lab presuppone che l'utente venga arrestato nella routine AddDevice usando il processo descritto in precedenza. Per visualizzare l'output qui, ripetere i passaggi descritti in precedenza, se necessario.

<- Nel sistema host

Visualizzare le variabili

Usare la voce di menu locale di visualizzazione>per visualizzare le variabili locali.

Screenshot di WinDbg che mostra la finestra delle variabili locali.

Variabili globali

È possibile trovare la posizione di un indirizzo di variabile globale digitando ? <nome> della variabile.

Variabili locali

È possibile visualizzare i nomi e i valori di tutte le variabili locali per un determinato frame digitando il comando dv . Per visualizzare i nomi e i valori di tutte le variabili locali per un frame specifico, immettere il dv comando :

0: kd> dv
         Driver = 0x00001fff`7ff9c838
     DeviceInit = 0xffffd001`51978190
         status = 0n0

Lo stack di chiamate è la catena di chiamate di funzione che hanno portato alla posizione corrente del contatore del programma. La funzione principale nello stack di chiamate è la funzione corrente e la funzione successiva è la funzione che ha chiamato la funzione corrente e così via.

Per visualizzare lo stack di chiamate, usare i k* comandi .

Comando Descrizione
kb Visualizza lo stack e i primi tre parametri.
kp Visualizza gli stack e l'elenco completo dei parametri.
kn Consente di visualizzare lo stack con le informazioni sul frame accanto.
  1. Nel sistema host, se si vuole mantenere disponibile lo stack di chiamate, selezionare Visualizza>stack di chiamate per visualizzarlo. Selezionare le colonne nella parte superiore della finestra per attivare o disattivare la visualizzazione di informazioni aggiuntive.

    Screenshot di WinDbg che mostra la finestra stack di chiamate.

  2. Usare il kn comando per visualizzare lo stack di chiamate durante il debug del codice dell'adattatore di esempio in uno stato di interruzione.

    3: kd> kn
    # Child-SP          RetAddr           Call Site
    00 ffffd001`51978110 fffff801`0942f55b ECHO!EchoEvtDeviceAdd+0x66 [c:\Samples\kmdf echo sample\c++\driver\autosync\driver.c @ 138]
    01 (Inline Function) --------`-------- Wdf01000!FxDriverDeviceAdd::Invoke+0x30 [d:\wbrtm\minkernel\wdf\framework\shared\inc\private\common\fxdrivercallbacks.hpp @ 61]
    02 ffffd001`51978150 fffff801`eed8097d Wdf01000!FxDriver::AddDevice+0xab [d:\wbrtm\minkernel\wdf\framework\shared\core\km\fxdriverkm.cpp @ 72]
    03 ffffd001`51978570 fffff801`ef129423 nt!PpvUtilCallAddDevice+0x35 [d:\9142\minkernel\ntos\io\pnpmgr\verifier.c @ 104]
    04 ffffd001`519785b0 fffff801`ef0c4112 nt!PnpCallAddDevice+0x63 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 7397]
    05 ffffd001`51978630 fffff801`ef0c344f nt!PipCallDriverAddDevice+0x6e2 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 3390]
    ...
    

Lo stack di chiamate mostra che il kernel (nt) chiamato nel codice Plug and Play (PnP) che ha chiamato codice del framework driver (WDF) che in seguito ha chiamato la funzione del driver DeviceAdd echo.

Visualizzare processi e thread

In questa sezione vengono visualizzate informazioni sui processi e sui thread in esecuzione in modalità kernel.

Processi

È possibile visualizzare o impostare le informazioni sul processo usando l'estensione del debugger !process . Impostare un punto di interruzione per esaminare il processo usato quando viene riprodotto un suono.

  1. Nel sistema host immettere il dv comando per esaminare le variabili delle impostazioni locali associate alla EchoEvtIo routine:

    0: kd> dv ECHO!EchoEvtIo*
    ECHO!EchoEvtIoQueueContextDestroy
    ECHO!EchoEvtIoWrite
    ECHO!EchoEvtIoRead         
    
  2. Cancellare i punti di interruzione precedenti usando bc *:

    0: kd> bc *  
    
  3. Impostare un punto di interruzione dei simboli nelle EchoEvtIo routine usando il comando seguente:

    0: kd> bm ECHO!EchoEvtIo*
      2: aade5490          @!”ECHO!EchoEvtIoQueueContextDestroy”
      3: aade55d0          @!”ECHO!EchoEvtIoWrite”
      4: aade54c0          @!”ECHO!EchoEvtIoRead”
    
  4. Elencare i punti di interruzione per verificare che il punto di interruzione sia impostato correttamente:

    0: kd> bl
    1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197]    0001 (0001) ECHO!EchoEvtIoQueueContextDestroy
    ...
    
  5. Immettere g per riavviare l'esecuzione del codice:

    0: kd> g
    
  6. Nel sistema di destinazione eseguire il EchoApp.exe programma di test driver nel sistema di destinazione.

  7. Nel sistema host, quando viene eseguita l'app di test, viene chiamata la routine di I/O nel driver. Questa chiamata fa sì che il punto di interruzione venga attivato e l'esecuzione del codice driver nel sistema di destinazione si arresta.

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. Usare il !process comando per visualizzare il processo corrente coinvolto nell'esecuzione di echoapp.exe:

    0: kd> !process
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 03c4    Peb: 7ff7cfec4000  ParentCid: 0f34
        DirBase: 1efd1b000  ObjectTable: ffffc001d77978c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000802c79f0 Vads 30 Clone 0 Private 135. Modified 5. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf270050
        ElapsedTime                       00:00:00.052
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (682, 50, 345) (2728KB, 200KB, 1380KB)
        PeakWorkingSetSize                652
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    688
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe00080e32080  Cid 03c4.0ec0  Teb: 00007ff7cfece000 Win32Thread: 0000000000000000 RUNNING on processor 1
    

    L'output mostra che il processo è associato al thread echoapp.exe , che era in esecuzione quando è stato raggiunto il punto di interruzione nell'evento di scrittura del driver. Per altre informazioni, vedere !process.

  9. Utilizzare per !process 0 0 visualizzare le informazioni di riepilogo per tutti i processi. Nell'output usare CTRL+F per individuare lo stesso indirizzo del processo associato all'immagine echoapp.exe . Nell'esempio l'indirizzo del processo è ffffe0007e6a7780.

    ...
    
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
        DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
        Image: echoapp.exe
    
    ...
    
  10. Registrare l'ID del processo associato a echoapp.exe da usare più avanti in questo lab. È anche possibile usare CTRL+C per copiare l'indirizzo nel buffer di copia per usarlo in un secondo momento.

    _____________________________________________________(indirizzo del processo di echoapp.exe)

  11. Immettere g come richiesto nel debugger per eseguire il codice in avanti fino al termine dell'esecuzione di echoapp.exe . Raggiunge il punto di interruzione nell'evento di lettura e scrittura più volte. Al termine echoapp.exe , eseguire l'interruzione nel debugger premendo CTRL+SCRLk (CTRL+INTERR).

  12. Usare il !process comando per verificare che sia in esecuzione un processo diverso. Nell'output illustrato di seguito, il processo con il valore Image di System è diverso dal valore Echo Image.

    1: kd> !process
    PROCESS ffffe0007b65d900
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001ab000  ObjectTable: ffffc001c9a03000  HandleCount: 786.
        Image: System
        VadRoot ffffe0007ce45930 Vads 14 Clone 0 Private 22. Modified 131605. Locked 64.
        DeviceMap ffffc001c9a0c220
        Token                             ffffc001c9a05530
        ElapsedTime                       21:31:02.516
    ...
    

    L'output mostra che un processo di sistema ffffe0007b65d900 era in esecuzione quando il sistema operativo è stato arrestato.

  13. Usare il !process comando per provare a esaminare l'ID processo associato a echoapp.exe registrato in precedenza. Specificare l'indirizzo del processo di echoapp.exe registrato in precedenza, anziché l'indirizzo del processo di esempio illustrato in questo esempio.

    0: kd> !process ffffe0007e6a7780
    TYPE mismatch for process object at 82a9acc0
    

    L'oggetto processo non è più disponibile perché il processo di echoapp.exe non è più in esecuzione.

Threads

I comandi per visualizzare e impostare i thread sono simili ai comandi per i processi. Usare il comando !thread per visualizzare i thread. Usare .thread per impostare i thread correnti.

  1. Nel sistema host immettere g nel debugger per riavviare l'esecuzione del codice nel sistema di destinazione.

  2. Nel sistema di destinazione eseguire il programma di test del driver EchoApp.exe.

  3. Nel sistema host il punto di interruzione viene raggiunto e l'esecuzione del codice si interrompe.

    Breakpoint 4 hit
    ECHO!EchoEvtIoRead:
    aade54c0 55              push    ebp
    
  4. Per visualizzare i thread in esecuzione, immettere !thread. Verranno visualizzate informazioni simili all'esempio seguente:

    0: kd>  !thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    ...
    

    Prendere nota del nome dell'immagine di echoapp.exe. Ciò indica che si sta esaminando il thread associato all'app di test.

  5. Usare il !process comando per determinare se questo thread è l'unico thread in esecuzione nel processo associato a echoapp.exe. Il numero di thread del thread in esecuzione nel processo è lo stesso thread che esegue il !thread comando visualizzato.

    0: kd> !process
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    
  6. Usare il !process 0 0 comando per individuare l'indirizzo del processo di due processi correlati e registrare l'indirizzo del processo qui.

    Cmd.exe: ____________________________________________________________

    EchoApp.exe: _______________________________________________________

    0: kd> !process 0 0 
    
    …
    
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
    …
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
    …
    

    In alternativa, è possibile usare !process 0 17 per visualizzare informazioni dettagliate su ogni processo. L'output di questo comando può essere lungo. L'output può essere cercato usando CTRL+F.

  7. Usare il !process comando per elencare le informazioni sul processo per entrambi i processi che eseguono il computer. Specificare l'indirizzo del processo dall'output !process 0 0 , non l'indirizzo illustrato in questo esempio.

    Questo output di esempio è relativo all'ID del processo cmd.exe registrato in precedenza. Il nome dell'immagine per questo ID processo è cmd.exe.

    0: kd>  !process ffffe0007bbde900
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
        VadRoot ffffe0007bb8e7b0 Vads 25 Clone 0 Private 117. Modified 20. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001d8c48050
        ElapsedTime                       21:33:05.840
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         24656
        QuotaPoolUsage[NonPagedPool]      3184
        Working Set Sizes (now,min,max)  (261, 50, 345) (1044KB, 200KB, 1380KB)
        PeakWorkingSetSize                616
        VirtualSize                       2097164 Mb
        PeakVirtualSize                   2097165 Mb
        PageFaultCount                    823
        MemoryPriority                    FOREGROUND
        BasePriority                      8
        CommitCharge                      381
    
            THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
                ffffe0008096c900  ProcessObject
            Not impersonating
    ...
    

    Questo output di esempio è relativo all'ID processo echoapp.exe registrato in precedenza.

    0: kd>  !process ffffe0008096c900
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
            IRP List:
                ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
            Not impersonating
    ...
    
  8. Registrare il primo indirizzo del thread associato ai due processi qui.

    Cmd.exe: ____________________________________________________

    EchoApp.exe: _________________________________________________

  9. Usare il !Thread comando per visualizzare informazioni sul thread corrente.

    0: kd>  !Thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    Attached Process          N/A            Image:         N/A
    ...
    

    Come previsto, il thread corrente è il thread associato a echoapp.exe ed è in esecuzione.

  10. Usare il !Thread comando per visualizzare informazioni sul thread associato a cmd.exe processo. Specificare l'indirizzo del thread registrato in precedenza.

    0: kd> !Thread ffffe0007cf34880
    THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
        ffffe0008096c900  ProcessObject
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0007bbde900       Image:         cmd.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      4134621        Ticks: 0
    Context Switch Count      4056           IdealProcessor: 0             
    UserTime                  00:00:00.000
    KernelTime                00:00:01.421
    Win32 Start Address 0x00007ff72e9d6e20
    Stack Init ffffd0015551dc90 Current ffffd0015551d760
    Base ffffd0015551e000 Limit ffffd00155518000 Call 0
    Priority 14 BasePriority 8 UnusualBoost 3 ForegroundBoost 2 IoPriority 2 PagePriority 5
    Child-SP          RetAddr           : Args to Child                                                           : Call Site
    ffffd001`5551d7a0 fffff801`eed184fe : fffff801`eef81180 ffffe000`7cf34880 00000000`fffffffe 00000000`fffffffe : nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    ffffd001`5551d8e0 fffff801`eed17f79 : ffff03a5`ca56a3c8 000000de`b6a6e990 000000de`b6a6e990 00007ff7`d00df000 : nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    ffffd001`5551d980 fffff801`eecea340 : ffffd001`5551da18 00000000`00000000 00000000`00000000 00000000`00000388 : nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    ...
    

    Questo thread è associato a cmd.exe ed è in uno stato di attesa.

  11. Specificare l'indirizzo del thread in attesa CMD.exe thread per modificare il contesto in tale thread in attesa.

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. Usare il k comando per visualizzare lo stack di chiamate associato al thread in attesa.

    0: kd> k
      *** Stack trace for last set context - .thread/.cxr resets it
    # Child-SP          RetAddr           Call Site
    00 ffffd001`5551d7a0 fffff801`eed184fe nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    01 ffffd001`5551d8e0 fffff801`eed17f79 nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    02 ffffd001`5551d980 fffff801`eecea340 nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    03 ffffd001`5551da00 fffff801`ef02e642 nt!KeWaitForSingleObject+0x2c0 [d:\9142\minkernel\ntos\ke\wait.c @ 683]
    ...
    

    Gli elementi dello stack di chiamate, KiCommitThreadWait ad esempio indicano che questo thread non è in esecuzione come previsto.

Per altre informazioni su thread e processi, vedere i riferimenti seguenti:

IRQL, registra e termina la sessione winDbg

In questa sezione visualizzare il livello di richiesta di interrupt (IRQL) e il contenuto dei registri.

Visualizzare il runtime di integrazione salvato

Il runtime di integrazione viene usato per gestire la priorità di manutenzione degli interrupt. Ogni processore ha un'impostazione IRQL che i thread possono aumentare o ridurre. Gli interrupt che si verificano in corrispondenza o al di sotto dell'impostazione IRQL del processore vengono mascherati e non interferiscono con l'operazione corrente. Gli interrupt che si verificano sopra l'impostazione IRQL del processore hanno la precedenza sull'operazione corrente.

Nel sistema host, l'estensione !irql visualizza il runtime di integrazione nel processore corrente del computer di destinazione prima dell'interruzione del debugger. Quando il computer di destinazione si interrompe nel debugger, il runtime di integrazione viene modificato, ma l'IRQL effettivo immediatamente prima del salvataggio dell'interruzione del debugger viene visualizzato da !irql.

0: kd> !irql
Debugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)

Visualizzare i registri

Nel sistema host visualizzare il contenuto dei registri per il thread corrente nel processore corrente usando il comando r (Registri).

0: kd> r
rax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001
rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0
rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620
 r8=000000000000003e  r9=ffffe00167a4a000 r10=000000000000001e
r11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0
r14=0000000000000001 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
nt!DbgBreakPointWithStatus:
fffff803`bb757020 cc              int     3

In alternativa, è possibile visualizzare il contenuto dei registri selezionando Visualizza>registri. Per altre informazioni, vedere r (registri).

La visualizzazione del contenuto dei registri può essere utile durante l'esecuzione del codice del linguaggio assembly e in altri scenari. Per altre informazioni sul disassembly del linguaggio di assembly, vedere Disassembly x86 con annotazioni e disassembly x64 con annotazioni.

Per informazioni sul contenuto del registro, vedere Architettura x86 e architettura x64.

Terminare la sessione WinDbg

Se si vuole lasciare il debugger collegato, ma si vuole lavorare sulla destinazione, cancellare eventuali punti di interruzione usando bc *, in modo che il computer di destinazione non tenti di connettersi al debugger del computer host. Usare quindi il g comando per consentire l'esecuzione del computer di destinazione.

Per terminare la sessione di debug, nel sistema host, eseguire l'interruzione nel debugger e immettere il qd comando (Esci e scollega) oppure selezionare Arresta debug dal menu.

0: kd> qd

Per altre informazioni, vedere Terminare una sessione di debug in WinDbg.

Risorse di debug di Windows

Altre informazioni sono disponibili nel debug di Windows. Alcuni di questi libri usano versioni precedenti di Windows come Windows Vista nei relativi esempi, ma i concetti illustrati sono applicabili alla maggior parte delle versioni di Windows.

Vedi anche