Lesen und Filtern von Debugnachrichten

Die Routinen DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix und KdPrintEx senden unter von Ihnen angegebenen Bedingungen eine Nachricht an den Kerneldebugger. Mit diesem Verfahren können Sie Nachrichten mit niedriger Priorität herausfiltern.

Hinweis

In Microsoft Windows Server 2003 und früheren Versionen von Windows senden die Routinen DbgPrint und KdPrint nachrichten bedingungslos an den Kerneldebugger. In Windows Vista und höheren Versionen von Windows senden diese Routinen bedingt Nachrichten, z. B . DbgPrintEx und KdPrintEx. Unabhängig davon, welche Windows-Version Sie verwenden, sollten Sie DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix und KdPrintEx verwenden, da Sie mit diesen Routinen die Bedingungen steuern können, unter denen die Nachricht gesendet wird.

So filtern Sie Debugnachrichten

  1. Verwenden Sie für jede Nachricht, die Sie an den Debugger senden möchten, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix oder KdPrintEx im Code Ihres Treibers. Übergeben Sie den entsprechenden Komponentennamen an den ComponentId-Parameter , und übergeben Sie einen Wert an den Level-Parameter , der den Schweregrad oder die Art dieser Nachricht widerspiegelt. Die Nachricht selbst wird mit der gleichen Syntax wie printf an die Parameter Format und arguments übergeben.

  2. Legen Sie den Wert der entsprechenden Komponentenfiltermaske fest. Jede Komponente verfügt über eine andere Maske. Der Maskenwert gibt an, welche der Meldungen dieser Komponente angezeigt werden. Sie können die Komponentenfiltermaske in der Registrierung mithilfe eines Registrierungs-Editors oder mithilfe eines Kerneldebuggers im Arbeitsspeicher festlegen.

  3. Fügen Sie einen Kerneldebugger an den Computer an. Jedes Mal, wenn ihr Treiber eine Nachricht an DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix oder KdPrintEx übergibt, werden die Werte, die an ComponentId und Level übergeben werden, mit dem Wert der entsprechenden Komponentenfiltermaske verglichen. Wenn diese Werte bestimmte Kriterien erfüllen, wird die Nachricht an den Kerneldebugger gesendet und angezeigt. Andernfalls wird keine Nachricht gesendet.

Hinweis

Alle Verweise auf dieser Seite auf DbgPrintEx gelten gleichermaßen für KdPrintEx, vDbgPrintEx und vDbgPrintExWithPrefix.

Identifizieren des Komponentennamens

Jede Komponente verfügt über eine separate Filtermaske. Dadurch kann der Debugger den Filter für jede Komponente separat konfigurieren.

Auf jede Komponente wird je nach Kontext auf unterschiedliche Weise verwiesen. Im ComponentId-Parameter von DbgPrintEx hat der Komponentenname das Präfix "DPFLTR_" und das Suffix "_ID". In der Registrierung hat die Komponentenfiltermaske denselben Namen wie die Komponente selbst. Im Debugger wird der Komponentenfiltermaske "Kd_" vorangestellt und mit "_Mask" versehen.

Es gibt eine vollständige Liste aller Komponentennamen (im format DPFLTR_XXXX_ID) im WDK-Header dpfilter.h (Microsoft Windows Driver Kit). Die meisten dieser Komponentennamen sind für Windows und für von Microsoft geschriebene Treiber reserviert.

Es sind sechs Komponentennamen für unabhängige Hardwareanbieter reserviert. Um das Mischen der Treiberausgabe mit der Ausgabe von Windows-Komponenten zu vermeiden, sollten Sie einen der folgenden Komponentennamen verwenden:

Komponentenname Treibertyp
IHVVIDEO Videotreiber
IHVAUDIO Audiotreiber
IHVNETWORK Netzwerktreiber
IHVSTREAMING Kernelstreamingtreiber
IHVBUS Bustreiber
IHVDRIVER Jeder andere Treibertyp

Wenn Sie beispielsweise einen Videotreiber schreiben, verwenden Sie DPFLTR_IHVVIDEO_ID als ComponentId-Parameter von DbgPrintEx, verwenden den Wertnamen IHVVIDEO in der Registrierung und verweisen auf Kd_IHVVIDEO_Mask im Debugger.

Alle von DbgPrint und KdPrint gesendeten Nachrichten sind der DEFAULT-Komponente zugeordnet.

Auswählen der richtigen Ebene

Der Level-Parameter der DbgPrintEx-Routine ist vom Typ DWORD. Es wird verwendet, um das Wichtigkeitsbitfeld zu bestimmen. Die Verbindung zwischen dem Parameter Level und diesem Bitfeld hängt von der Größe von Level ab:

  • Wenn die Ebene gleich einer Zahl zwischen 0 und 31 ist, wird sie als Bitverschiebung interpretiert. Das Feld "Wichtigkeitsbit" ist auf den Wert 1 <<Ebene festgelegt. Die Auswahl eines Werts zwischen 0 und 31 für Level führt daher zu einem Bitfeld mit genau einem Bitsatz. Wenn Level 0 ist, entspricht das Bitfeld 0x00000001; wenn Level 31 ist, entspricht das Bitfeld 0x80000000.

  • Wenn Level eine Zahl zwischen 32 und 0xFFFFFFFF inklusiv ist, wird das Wichtigkeitsbitfeld auf den Wert von Level selbst festgelegt.

Wenn Sie also das Bitfeld auf 0x00004000 festlegen möchten, können Sie Ebene als 0x00004000 oder einfach als 14 angeben. Beachten Sie, dass bestimmte Bitfeldwerte von diesem System nicht möglich sind , einschließlich eines Bitfelds, das vollständig 0 ist.

Die folgenden Konstanten können nützlich sein, um den Wert von Level festzulegen. Sie sind im WdK-Header dpfilter.h (Microsoft Windows Driver Kit) und im Windows SDK-Header ntrtl.h definiert:

#define   DPFLTR_ERROR_LEVEL     0
#define   DPFLTR_WARNING_LEVEL   1
#define   DPFLTR_TRACE_LEVEL     2
#define   DPFLTR_INFO_LEVEL      3
#define   DPFLTR_MASK   0x80000000

Eine einfache Möglichkeit, den Level-Parameter zu verwenden, besteht darin, immer Werte zwischen 0 und 31 zu verwenden– die Bits 0, 1, 2, 3 mit der Bedeutung, die von DPFLTR_XXXXXX_LEVEL angegeben wird, und die anderen Bits zu verwenden, um das zu bedeuten, was Sie wählen.

Eine weitere einfache Möglichkeit, den Parameter Level zu verwenden, besteht darin, immer explizite Bitfelder zu verwenden. Wenn Sie diese Methode auswählen, können Sie den Wert oder den Wert DPFLTR_MASK mit Ihrem Bitfeld verwenden. Dadurch wird sichergestellt, dass Sie nicht versehentlich einen Wert kleiner als 32 verwenden.

Damit Ihr Treiber mit der Verwendung von Nachrichtenebenen von Windows kompatibel ist, sollten Sie nur das niedrigste Bit (0x1) des Felds "Wichtigkeitsbit" festlegen, wenn ein schwerwiegender Fehler auftritt. Wenn Sie Level-Werte kleiner als 32 verwenden, entspricht dies DPFLTR_ERROR_LEVEL. Wenn dieses Bit festgelegt ist, wird Ihre Nachricht jedes Mal angezeigt, wenn jemand einen Kerneldebugger an einen Computer anfügt, auf dem Ihr Treiber ausgeführt wird.

Die Warnungs-, Ablaufverfolgungs- und Informationsebenen sollten in den entsprechenden Situationen verwendet werden. Andere Bits können frei für alle Zwecke verwendet werden, die Sie nützlich finden. Dadurch können Sie über eine Vielzahl von Nachrichtentypen verfügen, die selektiv sichtbar oder ausgeblendet werden können.

Alle von DbgPrint und KdPrint gesendeten Nachrichten verhalten sich wie DbgPrintEx - und KdPrintEx-Nachrichten mit Level gleich DPFLTR_INFO_LEVEL. Mit anderen Worten, für diese Nachrichten ist das dritte Bit ihres Wichtigkeitsbitfelds festgelegt.

Festlegen der Komponentenfiltermaske

Es gibt zwei Möglichkeiten, eine Komponentenfiltermaske festzulegen:

  • Auf die Komponentenfiltermaske kann im Registrierungsschlüssel HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filterzugegriffen werden. Erstellen oder öffnen Sie diesen Schlüssel mithilfe eines Registrierungs-Editors. Erstellen Sie unter diesem Schlüssel einen Wert mit dem Namen der gewünschten Komponente in Großbuchstaben. Legen Sie ihn gleich dem DWORD-Wert fest, den Sie als Komponentenfiltermaske verwenden möchten.

  • Wenn ein Kerneldebugger aktiv ist, kann er auf den Wert der Komponentenfiltermaske zugreifen, indem er die im Symbol Kd_XXXX_Mask gespeicherte Adresse deferenciert, wobei XXXX der gewünschte Komponentenname ist. Sie können den Wert dieser Maske in WinDbg oder KD mit dem Befehl dd (DWORD anzeigen) anzeigen oder mit dem Befehl ed (DWORD eingeben) eine neue Komponentenfiltermaske eingeben. Wenn die Gefahr einer Mehrdeutigkeit von Symbolen besteht, können Sie dieses Symbol als nt! Kd_XXXX_MASK.

Filtermasken, die in der Registrierung gespeichert sind, werden während des Startvorgangs wirksam. Filtermasken, die vom Debugger erstellt wurden, werden sofort wirksam und bleiben so lange bestehen, bis Windows neu gestartet wird. Ein in der Registrierung festgelegter Wert kann vom Debugger überschrieben werden, aber die Komponentenfiltermaske kehrt zu dem in der Registrierung angegebenen Wert zurück, wenn das System neu gestartet wird.

Es gibt auch eine systemweite Maske namens WIN2000. Dies entspricht standardmäßig 0x1, kann jedoch wie alle anderen Komponenten über die Registrierung oder den Debugger geändert werden. Wenn die Filterung ausgeführt wird, wird jede Komponentenfiltermaske zuerst mit der WIN2000-Maske OReded. Dies bedeutet insbesondere, dass Komponenten, deren Masken nie angegeben wurden, standardmäßig 0x1.

Kriterien für die Anzeige der Nachricht

Wenn DbgPrintEx im Kernelmoduscode aufgerufen wird, vergleicht Windows das von Level angegebene Nachrichtenrelevanzbitfeld mit der Filtermaske der komponente, die von ComponentId angegeben wird.

Hinweis

Denken Sie daran, dass das Wichtigkeitsbitfeld gleich 1 <<Ebene ist, wenn der Level-Parameter zwischen 0 und 31 liegt. Wenn der Level-Parameter jedoch 32 oder höher ist, ist das Wichtigkeitsbitfeld einfach gleich Level.

Windows führt einen AND-Vorgang für das Wichtigkeitsbitfeld und die Komponentenfiltermaske aus. Wenn das Ergebnis nonzero ist, wird die Nachricht an den Debugger gesendet.

Debugfilterbeispiel

Angenommen, Sie haben vor dem letzten Start die folgenden Werte in der Debugdruckfiltertaste erstellt:

  • IHVVIDEO, mit einem Wert gleich DWORD 0x2

  • IHVBUS, gleich DWORD 0x7FF

Nun geben Sie die folgenden Befehle im Kerneldebugger aus:

kd> ed Kd_IHVVIDEO_Mask 0x8 
kd> ed Kd_IHVAUDIO_Mask 0x7 

An diesem Punkt verfügt die IHVVIDEO-Komponente über eine Filtermaske mit 0x8, die IHVAUDIO-Komponente über eine Filtermaske mit 0x7 und die IHVBUS-Komponente über eine Filtermaske mit 0x7FF.

Da diese Masken jedoch automatisch mit der WIN2000 systemweiten Maske (die in der Regel gleich 0x1 ist), ist die IHVVIDEO-Maske effektiv gleich 0x9. In der Tat verfügen Komponenten, deren Filtermasken überhaupt nicht festgelegt wurden (für instance, IHVSTREAMING oder DEFAULT), eine Filtermaske mit 0x1.

Angenommen, die folgenden Funktionsaufrufe treten in verschiedenen Treibern auf:

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");

Die erste Nachricht hat den Level-Parameter gleich DPFLTR_INFO_LEVEL, d. h. 3. Da dies weniger als 32 ist, wird es als eine kleine Verschiebung behandelt, was zu einem Wichtigkeitsbitfeld von 0x8 führt. Dieser Wert wird dann mit der effektiven IHVVIDEO-Komponentenfiltermaske von 0x9 anDed, sodass ein nonzero-Ergebnis angezeigt wird. Die erste Nachricht wird also an den Debugger übertragen.

Die zweite Nachricht hat den Level-Parameter 7. Auch dies wird als eine kleine Verschiebung behandelt, was zu einem Wichtigkeitsbitfeld von 0x80 führt. Dies wird dann mit der IHVAUDIO-Komponentenfiltermaske von 0x7 anDeded, was ein Ergebnis von 0 ergibt. Die zweite Nachricht wird also nicht übertragen.

Die dritte Nachricht hat den Level-Parameter DPFLTR_MASK | 0x10. Dies ist größer als 31, und daher wird das Wichtigkeitsbitfeld gleich dem Wert von Level festgelegt, d. h. 0x80000010. Dies wird dann mit der IHVBUS-Komponentenfiltermaske von 0x7FF anded, was ein nonzero-Ergebnis ergibt. Die dritte Nachricht wird also an den Debugger übertragen.

Die vierte Nachricht wurde an DbgPrint anstelle von DbgPrintEx übergeben. In Windows Server 2003 und früheren Versionen von Windows werden nachrichten, die an diese Routine übergeben werden, immer übertragen. In Windows Vista und höheren Versionen von Windows erhalten nachrichten, die an diese Routine übergeben werden, immer einen Standardfilter. Das Feld "Wichtigkeitsbit" ist gleich 1 << DPFLTR_INFO_LEVEL, was 0x00000008 ist. Die Komponente für diese Routine ist DEFAULT. Da Sie die STANDARD-Komponentenfiltermaske nicht festgelegt haben, weist sie den Wert 0x1 auf. Wenn dies mit dem Feld "Wichtigkeitsbit" anded wird, ist das Ergebnis 0. Die vierte Nachricht wird also nicht übertragen.

DbgPrint-Puffer und Debugger

Wenn die Routine DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint oder KdPrintEx eine Nachricht an den Debugger überträgt, wird die formatierte Zeichenfolge an den DbgPrint-Puffer gesendet. Der Inhalt dieses Puffers wird sofort im Debuggerbefehlsfenster angezeigt, es sei denn, Sie haben diese Anzeige mithilfe der Option Puffer-DbgPrint-Ausgabe von GFlags deaktiviert.

Während des lokalen Kerneldebuggens und jedes andere Mal, wenn diese Anzeige deaktiviert wurde, kann der Inhalt des DbgPrint-Puffers nur mit dem Erweiterungsbefehl !dbgprint angezeigt werden.

Jeder einzelne Aufruf von DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint oder KdPrintEx überträgt nur 512 Bytes an Informationen. Jede Ausgabe, die länger als die 512 Bytes ist, geht verloren. Der DbgPrint-Puffer selbst kann bis zu 4 KB Daten auf einem kostenlosen Build von Windows und bis zu 32 KB Daten in einem überprüften Build von Windows aufnehmen. Unter Windows Server 2003 und höheren Versionen von Windows können Sie das KDbgCtrl-Tool verwenden, um die Größe des DbgPrint-Puffers zu ändern. Dieses Tool ist Teil der Debugtools für Windows.

Hinweis

Überprüfte Builds waren unter älteren Versionen von Windows verfügbar, bevor Windows 10 Version 1803. Verwenden Sie Tools wie Driver Verifier und GFlags, um Treibercode in späteren Versionen von Windows zu überprüfen.

Wenn eine Nachricht aufgrund ihrer ComponentId- und Level-Werte herausgefiltert wird, wird sie nicht über die Debugverbindung übertragen. Daher gibt es keine Möglichkeit, diese Meldung im Debugger anzuzeigen.