Lettura e filtro dei messaggi di debug
Le routine DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix e KdPrintEx inviano un messaggio al debugger del kernel in condizioni specificate. Questa procedura consente di filtrare i messaggi con priorità bassa.
Nota
In Microsoft Windows Server 2003 e versioni precedenti di Windows, le routine DbgPrint e KdPrint inviano messaggi al debugger kernel in modo incondizionato. In Windows Vista e versioni successive di Windows, queste routine inviano messaggi in modo condizionale, ad esempio DbgPrintEx e KdPrintEx. Indipendentemente dalla versione di Windows in uso, è necessario usare DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix e KdPrintEx, perché queste routine consentono di controllare le condizioni in cui viene inviato il messaggio.
Per filtrare i messaggi di debug
Per ogni messaggio che si vuole inviare al debugger, usare DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix o KdPrintEx nel codice del driver. Passare il nome del componente appropriato al parametro ComponentId e passare un valore al parametro Level che riflette la gravità o la natura del messaggio. Il messaggio stesso viene passato ai parametri Format e arguments usando la stessa sintassi di printf.
Impostare il valore della maschera di filtro del componente appropriata. Ogni componente ha una maschera diversa. Il valore della maschera indica quale dei messaggi del componente vengono visualizzati. È possibile impostare la maschera di filtro dei componenti nel Registro di sistema usando un editor del Registro di sistema o in memoria usando un debugger del kernel.
Collegare un debugger del kernel al computer. Ogni volta che il driver passa un messaggio a DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix o KdPrintEx, i valori passati a ComponentId e Level vengono confrontati con il valore della maschera di filtro del componente corrispondente. Se questi valori soddisfano determinati criteri, il messaggio viene inviato al debugger del kernel e visualizzato. In caso contrario, non viene inviato alcun messaggio.
Nota
Tutti i riferimenti in questa pagina a DbgPrintEx si applicano ugualmente a KdPrintEx, vDbgPrintEx e vDbgPrintExWithPrefix.
Identificazione del nome del componente
Ogni componente ha una maschera di filtro separata. Ciò consente al debugger di configurare il filtro per ogni componente separatamente.
Ogni componente viene definito in modi diversi, a seconda del contesto. Nel parametro ComponentId di DbgPrintEx il nome del componente è preceduto da "DPFLTR_" e suffisso con "_ID". Nel Registro di sistema, la maschera filtro componente ha lo stesso nome del componente stesso. Nel debugger, la maschera filtro componente è preceduta da "Kd_" e suffisso con "_Mask".
È disponibile un elenco completo di tutti i nomi dei componenti (nel formato DPFLTR_XXXX_ID) nell'intestazione dpfilter.h (Microsoft Windows Driver Kit). La maggior parte di questi nomi dei componenti è riservata per Windows e per i driver scritti da Microsoft.
Esistono sei nomi dei componenti riservati ai fornitori hardware indipendenti. Per evitare di combinare l'output del driver con l'output dei componenti di Windows, è consigliabile usare uno dei nomi dei componenti seguenti:
Nome componente | Tipo di driver |
---|---|
IHVVIDEO | Driver video |
IHVAUDIO | Driver audio |
IHVNETWORK | Driver di rete |
IHVSTREAMING | Driver di streaming del kernel |
IHVBUS | Driver del bus |
IHVDRIVER | Qualsiasi altro tipo di driver |
Ad esempio, se si scrive un driver video, si userà DPFLTR_IHVVIDEO_ID come parametro ComponentId di DbgPrintEx, usare il nome di valore IHVVIDEO nel Registro di sistema e fare riferimento a Kd_IHVVIDEO_Mask nel debugger.
Tutti i messaggi inviati da DbgPrint e KdPrint sono associati al componente DEFAULT .
Scelta del livello corretto
Il parametro Level della routine DbgPrintEx è di tipo DWORD. Viene usato per determinare il campo bit di importanza. La connessione tra il parametro Level e il campo bit dipende dalle dimensioni di Level:
Se Level è uguale a un numero compreso tra 0 e 31, inclusivo, viene interpretato come uno spostamento di bit. Il campo bit di importanza è impostato sul valore 1 <<Livello. Pertanto, scegliendo un valore compreso tra 0 e 31 per Livello , viene restituito un campo bit con esattamente un set di bit. Se Il livello è 0, il campo bit equivale a 0x00000001; se Level è 31, il campo bit equivale a 0x80000000.
Se Level è un numero compreso tra 32 e 0xFFFFFFFF inclusivo, il campo bit di importanza viene impostato sul valore di Level stesso.
Pertanto, se si desidera impostare il campo bit su 0x00004000, è possibile specificare Level come 0x00004000 o semplicemente come 14. Si noti che alcuni valori dei campi bit non sono possibili da questo sistema, incluso un campo bit che è interamente zero.
Le costanti seguenti possono essere utili per impostare il valore di Level. Sono definiti nell'intestazione dpfilter.h di Microsoft Windows Driver Kit (WDK) e nell'intestazione di Windows SDK ntrtl.h:
#define DPFLTR_ERROR_LEVEL 0
#define DPFLTR_WARNING_LEVEL 1
#define DPFLTR_TRACE_LEVEL 2
#define DPFLTR_INFO_LEVEL 3
#define DPFLTR_MASK 0x80000000
Un modo semplice per usare il parametro Level consiste nell'usare sempre i valori compresi tra 0 e 31 , usando i bit 0, 1, 2, 3 con il significato dato da DPFLTR_XXXX_LEVEL e usando gli altri bit per significare qualsiasi cosa si sceglie.
Un altro modo semplice per usare il parametro Level consiste nell'usare sempre campi bit espliciti. Se si sceglie questo metodo, è possibile che si voglia orare il valore DPFLTR_MASK con il campo bit; in questo modo si assicura che non si userà accidentalmente un valore minore di 32.
Per rendere compatibile il driver con il modo in cui Windows usa i livelli di messaggio, è consigliabile impostare solo il bit più basso (0x1) del campo bit di importanza se si verifica un errore grave. Se si usano valori di livello inferiori a 32, corrisponde a DPFLTR_ERROR_LEVEL. Se questo bit è impostato, il messaggio verrà visualizzato ogni volta che qualcuno collega un debugger del kernel a un computer in cui è in esecuzione il driver.
I livelli di avviso, traccia e informazioni devono essere usati nelle situazioni appropriate. Altri bit possono essere usati liberamente per qualsiasi scopo che si trova utile. Ciò consente di avere un'ampia gamma di tipi di messaggi che possono essere visualizzati o nascosti in modo selettivo.
Tutti i messaggi inviati da DbgPrint e KdPrint si comportano come i messaggi DbgPrintEx e KdPrintEx con livello uguale a DPFLTR_INFO_LEVEL. In altre parole, questi messaggi hanno il terzo bit del relativo set di campi di bit di importanza.
Impostazione della maschera filtro componente
Esistono due modi per impostare una maschera di filtro dei componenti:
La maschera filtro componente può essere accessibile nella chiave del Registro di sistema HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. Usando un editor del Registro di sistema, creare o aprire questa chiave. In questa chiave creare un valore con il nome del componente desiderato, in maiuscolo. Impostarlo uguale al valore DWORD che si desidera usare come maschera di filtro del componente.
Se un debugger del kernel è attivo, può accedere al valore maschera filtro componente dereferendo l'indirizzo archiviato nel simbolo Kd_XXXX_Mask, dove XXXX è il nome del componente desiderato. È possibile visualizzare il valore di questa maschera in WinDbg o KD con il comando dd (Display DWORD) oppure immettere una nuova maschera di filtro dei componenti con il comando ed (Invio DWORD). Se esiste un pericolo di ambiguità dei simboli, è possibile specificare questo simbolo come nt! Kd_XXXX_Mask.
Le maschere di filtro archiviate nel Registro di sistema hanno effetto durante l'avvio. Le maschere di filtro create dal debugger hanno effetto immediatamente e vengono mantenute finché Windows non viene riavviato. Un valore impostato nel Registro di sistema può essere sottoposto a override dal debugger, ma la maschera di filtro del componente restituirà il valore specificato nel Registro di sistema se il sistema viene riavviato.
Esiste anche una maschera a livello di sistema denominata WIN2000. Questa operazione è uguale a 0x1 per impostazione predefinita, anche se può essere modificata tramite il Registro di sistema o il debugger come tutti gli altri componenti. Quando viene eseguito il filtro, ogni maschera di filtro dei componenti viene prima ORed con la maschera di WIN2000 . In particolare, ciò significa che i componenti i cui maschere non sono mai state specificate per impostazione predefinita per 0x1.
Criteri per la visualizzazione del messaggio
Quando DbgPrintEx viene chiamato nel codice in modalità kernel, Windows confronta il campo bit di importanza del messaggio specificato da Level con la maschera di filtro del componente specificata da ComponentId.
Nota
Si ricordi che quando il parametro Level è compreso tra 0 e 31, il bitfield di importanza è uguale a 1 <<Livello. Ma quando il parametro Level è 32 o superiore, il campo di bit di importanza è semplicemente uguale a Level.
Windows esegue un'operazione AND sul campo bit di importanza e sulla maschera di filtro del componente. Se il risultato è diverso da zero, il messaggio viene inviato al debugger.
Esempio di filtro di debug
Si supponga che prima dell'ultimo avvio siano stati creati i valori seguenti nella chiave debug del filtro di stampa :
IHVVIDEO, con un valore uguale a DWORD 0x2
IHVBUS, uguale a DWORD 0x7FF
A questo punto si emettono i comandi seguenti nel debugger del kernel:
kd> ed Kd_IHVVIDEO_Mask 0x8
kd> ed Kd_IHVAUDIO_Mask 0x7
A questo punto, il componente IHVVIDEO ha una maschera di filtro di 0x8, il componente IHVAUDIO ha una maschera di filtro di 0x7 e il componente IHVBUS ha una maschera di filtro di 0x7FF.
Tuttavia, poiché queste maschere sono automaticamente ORed con la maschera WIN2000 a livello di sistema (che in genere è uguale a 0x1), la maschera IHVVIDEO è effettivamente uguale a 0x9. Infatti, i componenti le cui maschere di filtro non sono state impostate affatto (ad esempio , IHVSTREAMING o DEFAULT) avranno una maschera di filtro di 0x1.
Si supponga ora che le chiamate di funzione seguenti si verifichino in vari driver:
DbgPrintEx( DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID, 7, "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID, DPFLTR_MASK | 0x10, "Third message.\n");
DbgPrint( "Fourth message.\n");
Il primo messaggio ha il parametro Level uguale a DPFLTR_INFO_LEVEL, ovvero 3. Poiché questo è minore di 32, viene considerato come uno spostamento di bit, con conseguente un campo di bit di importanza di 0x8. Questo valore viene quindi ANDed con la maschera di filtro del componente IHVVIDEO effettiva di 0x9, dando un risultato diverso da zero. Il primo messaggio viene quindi trasmesso al debugger.
Il secondo messaggio ha il parametro Level uguale a 7. Anche in questo caso, questo viene considerato come uno spostamento di bit, con conseguente campo di bit di importanza di 0x80. Si tratta quindi di ANDed con la maschera di filtro del componente IHVAUDIO di 0x7, dando un risultato pari a zero. Quindi il secondo messaggio non viene trasmesso.
Il terzo messaggio ha il parametro Level uguale a DPFLTR_MASK | 0x10. Questo valore è maggiore di 31 e pertanto il campo di bit di importanza viene impostato su uguale al valore di Level , ovvero su 0x80000010. Si tratta quindi di ANDed con la maschera filtro componente IHVBUS di 0x7FF, dando un risultato diverso da zero. Il terzo messaggio viene quindi trasmesso al debugger.
Il quarto messaggio è stato passato a DbgPrint anziché a DbgPrintEx. In Windows Server 2003 e versioni precedenti di Windows i messaggi passati a questa routine vengono sempre trasmessi. In Windows Vista e versioni successive di Windows, ai messaggi passati a questa routine viene sempre assegnato un filtro predefinito. Il campo di bit di importanza è uguale a 1 << DPFLTR_INFO_LEVEL, ovvero 0x00000008. Il componente per questa routine è DEFAULT. Poiché non è stata impostata la maschera filtro componente DEFAULT, ha un valore di 0x1. Quando si tratta di ANDed con il campo di bit di importanza, il risultato è zero. Quindi il quarto messaggio non viene trasmesso.
Buffer DbgPrint e debugger
Quando la routine DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint o KdPrintEx trasmette un messaggio al debugger, la stringa formattata viene inviata al buffer DbgPrint. Il contenuto di questo buffer viene visualizzato immediatamente nella finestra Comando debugger, a meno che questa visualizzazione non sia stata disabilitata usando l'opzione Buffer DbgPrint Output di GFlags.
Durante il debug del kernel locale e ogni altra volta che questa visualizzazione è stata disabilitata, il contenuto del buffer DbgPrint può essere visualizzato solo usando il comando di estensione !dbgprint .
Qualsiasi singola chiamata a DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint o KdPrintEx trasmette solo 512 byte di informazioni. Qualsiasi output più lungo dei 512 byte viene perso. Il buffer DbgPrint può contenere fino a 4 KB di dati in una build gratuita di Windows e fino a 32 KB di dati in una build controllata di Windows. In Windows Server 2003 e versioni successive di Windows è possibile usare lo strumento KDbgCtrl per modificare le dimensioni del buffer DbgPrint. Questo strumento fa parte di Strumenti di debug per Windows.
Nota
Le build controllate erano disponibili nelle versioni precedenti di Windows, prima di Windows 10 versione 1803. Usare strumenti come Driver Verifier e GFlags per controllare il codice del driver nelle versioni successive di Windows.
Se un messaggio viene filtrato a causa dei relativi valori ComponentId e Level , non viene trasmesso attraverso la connessione di debug. Non è pertanto possibile visualizzare questo messaggio nel debugger.