Lecture et filtrage des messages de débogage

Les routines DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix et KdPrintEx envoient un message au débogueur du noyau dans les conditions que vous spécifiez. Cette procédure vous permet de filtrer les messages de faible priorité.

Notes

Dans Microsoft Windows Server 2003 et les versions antérieures de Windows, les routines DbgPrint et KdPrint envoient des messages au débogueur du noyau de manière inconditionnelle. Dans Windows Vista et les versions ultérieures de Windows, ces routines envoient des messages de manière conditionnelle, comme DbgPrintEx et KdPrintEx. Quelle que soit la version de Windows que vous utilisez, vous devez utiliser DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix et KdPrintEx, car ces routines vous permettent de contrôler les conditions dans lesquelles le message est envoyé.

Pour filtrer les messages de débogage

  1. Pour chaque message que vous souhaitez envoyer au débogueur, utilisez DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix ou KdPrintEx dans le code de votre pilote. Transmettez le nom de composant approprié au paramètre ComponentId et transmettez une valeur au paramètre Level qui reflète la gravité ou la nature de ce message. Le message lui-même est passé aux paramètres Format et arguments en utilisant la même syntaxe que printf.

  2. Définissez la valeur du masque de filtre de composant approprié. Chaque composant a un masque différent. La valeur du masque indique les messages de ce composant qui sont affichés. Vous pouvez définir le masque de filtre de composant dans le Registre à l’aide d’un éditeur du Registre ou en mémoire à l’aide d’un débogueur de noyau.

  3. Attachez un débogueur de noyau à l’ordinateur. Chaque fois que votre pilote transmet un message à DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix ou KdPrintEx, les valeurs passées à ComponentId et Level sont comparées à la valeur du masque de filtre de composant correspondant. Si ces valeurs répondent à certains critères, le message est envoyé au débogueur du noyau et affiché. Sinon, aucun message n’est envoyé.

Notes

Toutes les références à DbgPrintEx sur cette page s’appliquent également à KdPrintEx, vDbgPrintEx et vDbgPrintExWithPrefix.

Identification du nom du composant

Chaque composant a un masque de filtre distinct. Cela permet au débogueur de configurer le filtre pour chaque composant séparément.

Chaque composant est référencé de différentes façons, selon le contexte. Dans le paramètre ComponentId de DbgPrintEx, le nom du composant est précédé de « DPFLTR_ » et de « _ID ». Dans le Registre, le masque de filtre de composant porte le même nom que le composant lui-même. Dans le débogueur, le masque de filtre de composant est précédé de « Kd_ » et de « _Mask ».

Il existe une liste complète de tous les noms de composants (au format DPFLTR_XXXX_ID) dans l’en-tête dpfilter.h du Kit de pilotes Microsoft Windows (WDK). La plupart de ces noms de composants sont réservés à Windows et aux pilotes écrits par Microsoft.

Six noms de composants sont réservés aux fournisseurs de matériel indépendants. Pour éviter de mélanger la sortie de votre pilote avec la sortie des composants Windows, vous devez utiliser l’un des noms de composants suivants :

Nom du composant Type de pilote
IHVVIDEO Pilote vidéo
IHVAUDIO Pilote audio
IHVNETWORK Pilote réseau
IHVSTREAMING Pilote de diffusion en continu du noyau
IHVBUS Pilote de bus
IHVDRIVER Tout autre type de pilote

Par exemple, si vous écrivez un pilote vidéo, vous devez utiliser DPFLTR_IHVVIDEO_ID comme paramètre ComponentId de DbgPrintEx, utiliser le nom de valeur IHVVIDEO dans le Registre et faire référence à Kd_IHVVIDEO_Mask dans le débogueur.

Tous les messages envoyés par DbgPrint et KdPrint sont associés au composant DEFAULT .

Choix du niveau correct

Le paramètre Level de la routine DbgPrintEx est de type DWORD. Il est utilisé pour déterminer le champ de bits d’importance. La connexion entre le paramètre Level et ce champ de bits dépend de la taille de Level :

  • Si Level est égal à un nombre compris entre 0 et 31, inclus, il est interprété comme un décalage de bits. Le champ de bits d’importance est défini sur la valeur 1 <<Niveau. Ainsi, le choix d’une valeur comprise entre 0 et 31 pour Niveau entraîne un champ de bits avec exactement un bit défini. Si Level a la valeur 0, le champ de bits équivaut à 0x00000001 ; si Level a la valeur 31, le champ de bits équivaut à 0x80000000.

  • Si Level est un nombre compris entre 32 et 0xFFFFFFFF inclus, le champ de bits d’importance est défini sur la valeur de Level lui-même.

Par conséquent, si vous souhaitez définir le champ bit sur 0x00004000, vous pouvez spécifier Level comme 0x00004000 ou simplement comme 14. Notez que certaines valeurs de champ de bits ne sont pas possibles par ce système, y compris un champ de bits qui est entièrement égal à zéro.

Les constantes suivantes peuvent être utiles pour définir la valeur de Level. Ils sont définis dans l’en-tête du Kit de pilotes Microsoft Windows (WDK) dpfilter.h et dans l’en-tête du Kit de développement logiciel (SDK) Windows 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

Une façon simple d’utiliser le paramètre Level consiste à toujours utiliser des valeurs comprises entre 0 et 31 , en utilisant les bits 0, 1, 2, 3 avec la signification donnée par DPFLTR_XXXX_LEVEL et en utilisant les autres bits pour désigner ce que vous choisissez.

Une autre façon simple d’utiliser le paramètre Level consiste à toujours utiliser des champs de bits explicites. Si vous choisissez cette méthode, vous pouvez choisir OU la valeur DPFLTR_MASK avec votre champ de bits ; Cela garantit que vous n’utiliserez pas accidentellement une valeur inférieure à 32.

Pour rendre votre pilote compatible avec la façon dont Windows utilise les niveaux de message, vous ne devez définir le bit le plus bas (0x1) du champ de bits d’importance qu’en cas d’erreur grave. Si vous utilisez des valeurs de niveau inférieures à 32, cela correspond à DPFLTR_ERROR_LEVEL. Si ce bit est défini, votre message sera affiché chaque fois qu’une personne attache un débogueur de noyau à un ordinateur sur lequel votre pilote est en cours d’exécution.

Les niveaux d’avertissement, de trace et d’information doivent être utilisés dans les situations appropriées. D’autres bits peuvent être utilisés librement à des fins que vous trouvez utiles. Cela vous permet d’avoir un large éventail de types de messages qui peuvent être vus ou masqués de manière sélective.

Tous les messages envoyés par DbgPrint et KdPrint se comportent comme des messages DbgPrintEx et KdPrintEx avec niveau égal à DPFLTR_INFO_LEVEL. En d’autres termes, ces messages ont le troisième bit de leur champ de bits d’importance défini.

Définition du masque de filtre de composant

Il existe deux façons de définir un masque de filtre de composant :

  • Le masque de filtre de composant est accessible dans la clé de RegistreHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. À l’aide d’un éditeur du Registre, créez ou ouvrez cette clé. Sous cette clé, créez une valeur avec le nom du composant souhaité, en majuscules. Définissez-la sur la valeur DWORD que vous souhaitez utiliser comme masque de filtre de composant.

  • Si un débogueur de noyau est actif, il peut accéder à la valeur du masque de filtre de composant en déréférençant l’adresse stockée dans le symbole Kd_XXXX_Mask, où XXXX est le nom du composant souhaité. Vous pouvez afficher la valeur de ce masque dans WinDbg ou KD avec la commande dd (Display DWORD) ou entrer un nouveau masque de filtre de composant avec la commande ed (Enter DWORD). S’il existe un risque d’ambiguïté de symbole, vous pouvez spécifier ce symbole comme nt ! Kd_XXXX_Mask.

Les masques de filtre stockés dans le Registre prennent effet pendant le démarrage. Les masques de filtre créés par le débogueur prennent effet immédiatement et persistent jusqu’à ce que Windows soit redémarré. Une valeur définie dans le Registre peut être remplacée par le débogueur, mais le masque de filtre de composant retourne à la valeur spécifiée dans le Registre si le système est redémarré.

Il existe également un masque à l’échelle du système appelé WIN2000. Cela est égal à 0x1 par défaut, bien qu’il puisse être modifié via le Registre ou le débogueur comme tous les autres composants. Lorsque le filtrage est effectué, chaque masque de filtre de composant est d’abord ORed avec le masque WIN2000 . En particulier, cela signifie que les composants dont les masques n’ont jamais été spécifiés par défaut 0x1.

Critères d’affichage du message

Lorsque DbgPrintEx est appelé dans le code en mode noyau, Windows compare le champ de bits d’importance du message spécifié par Level avec le masque de filtre du composant spécifié par ComponentId.

Notes

Rappelez-vous que lorsque le paramètre Level est compris entre 0 et 31, le champ de bits d’importance est égal à 1 <<Niveau. Mais lorsque le paramètre Level est égal ou supérieur à 32, le champ de bits d’importance est simplement égal à Level.

Windows effectue une opération AND sur le champ de bits d’importance et le masque de filtre de composant. Si le résultat est différent de zéro, le message est envoyé au débogueur.

Exemple de filtre de débogage

Supposons qu’avant le dernier démarrage, vous avez créé les valeurs suivantes dans la clé Filtre d’impression de débogage :

  • IHVVIDEO, avec une valeur égale à DWORD 0x2

  • IHVBUS, égal à DWORD 0x7FF

Vous émettez maintenant les commandes suivantes dans le débogueur du noyau :

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

À ce stade, le composant IHVVIDEO a un masque de filtre de 0x8, le composant IHVAUDIO a un masque de filtre de 0x7 et le composant IHVBUS a un masque de filtre de 0x7FF.

Toutefois, étant donné que ces masques sont automatiquement ORed avec le masque WIN2000 à l’échelle du système (qui est généralement égal à 0x1), le masque IHVVIDEO est effectivement égal à 0x9. En effet, les composants dont les masques de filtre n’ont pas été définis du tout (pour instance, IHVSTREAMING ou DEFAULT) auront un masque de filtre de 0x1.

Supposons maintenant que les appels de fonction suivants se produisent dans différents pilotes :

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

Le premier message a son paramètre Level égal à DPFLTR_INFO_LEVEL, soit 3. Étant donné que cette valeur est inférieure à 32, elle est traitée comme un décalage de bits, ce qui entraîne un champ de bits d’importance de 0x8. Cette valeur est ensuite associée au masque de filtre du composant IHVVIDEO effectif de 0x9, ce qui donne un résultat différent de zéro. Le premier message est donc transmis au débogueur.

Le deuxième message a son paramètre Level égal à 7. Là encore, cela est traité comme un décalage de bits, ce qui entraîne un champ de bits d’importance de 0x80. Cela est ensuite and avec le masque de filtre de composant IHVAUDIO de 0x7, ce qui donne un résultat de zéro. Le deuxième message n’est donc pas transmis.

Le troisième message a son paramètre Level égal à DPFLTR_MASK | 0x10. Cette valeur est supérieure à 31 et, par conséquent, le champ de bits d’importance est défini sur la valeur de Level , en d’autres termes, sur 0x80000010. Ce paramètre est ensuite associé au masque de filtre du composant IHVBUS de 0x7FF, ce qui donne un résultat différent de zéro. Le troisième message est donc transmis au débogueur.

Le quatrième message a été passé à DbgPrint au lieu de DbgPrintEx. Dans Windows Server 2003 et les versions antérieures de Windows, les messages transmis à cette routine sont toujours transmis. Dans Windows Vista et les versions ultérieures de Windows, les messages passés à cette routine reçoivent toujours un filtre par défaut. Le champ de bits d’importance est égal à 1 << DPFLTR_INFO_LEVEL, ce qui est 0x00000008. Le composant de cette routine est DEFAULT. Étant donné que vous n’avez pas défini le masque de filtre de composant DEFAULT , il a la valeur 0x1. Lorsqu’il s’agit d’UND avec le champ de bits d’importance, le résultat est égal à zéro. Le quatrième message n’est donc pas transmis.

Mémoire tampon DbgPrint et débogueur

Lorsque la routine DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint ou KdPrintEx transmet un message au débogueur, la chaîne mise en forme est envoyée à la mémoire tampon DbgPrint . Le contenu de cette mémoire tampon s’affiche immédiatement dans la fenêtre Commande du débogueur, sauf si vous avez désactivé cet affichage à l’aide de l’option Sortie DbgPrint tampon de GFlags.

Pendant le débogage du noyau local et à toute autre fois que cet affichage a été désactivé, le contenu de la mémoire tampon DbgPrint ne peut être consulté qu’à l’aide de la commande d’extension !dbgprint .

Tout appel unique à DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint ou KdPrintEx transmet uniquement 512 octets d’informations. Toute sortie supérieure à 512 octets est perdue. La mémoire tampon DbgPrint elle-même peut contenir jusqu’à 4 Ko de données sur une version gratuite de Windows et jusqu’à 32 Ko de données sur une build vérifiée de Windows. Sur Windows Server 2003 et versions ultérieures de Windows, vous pouvez utiliser l’outil KDbgCtrl pour modifier la taille de la mémoire tampon DbgPrint. Cet outil fait partie des outils de débogage pour Windows.

Notes

Les builds vérifiées étaient disponibles sur les versions antérieures de Windows, avant Windows 10 version 1803. Utilisez des outils tels que Driver Verifier et GFlags pour case activée code de pilote dans les versions ultérieures de Windows.

Si un message est filtré en raison de ses valeurs ComponentId et Level , il n’est pas transmis via la connexion de débogage. Par conséquent, il n’existe aucun moyen d’afficher ce message dans le débogueur.