Partager via


Utilisation de LINQ avec les objets débogueur

La syntaxe LINQ peut être utilisée avec les objets débogueur pour rechercher et manipuler des données. L’utilisation de la syntaxe LINQ avec la commande dx permet une expérience plus cohérente que l’utilisation de commandes de débogueur. La sortie et les options sont cohérentes, quel que soit l’objet de débogueur que vous examinez. Les requêtes LINQ vous permettent de poser des questions telles que « Quels sont les 5 principaux processus qui exécutent le plus de threads ? ».

Les objets débogueur sont projetés dans un espace de noms rooté à l’emplacement « Débogueur ». Les processus, modules, threads, piles, trames de pile et variables locales sont tous disponibles pour être utilisés dans une requête LINQ.

LINQ est conceptuellement similaire au langage SQL (SQL) utilisé pour interroger les bases de données. Vous pouvez utiliser un certain nombre de méthodes LINQ pour rechercher, filtrer et analyser des données de débogage. La syntaxe de la méthode LINQ C# est utilisée. Pour plus d’informations sur LINQ et la syntaxe LINQ C#, consultez Prise en main avec LINQ en C#

LINQ utilisé dans la prise en charge du débogueur utilise la « syntaxe de méthode » de LINQ et non la « syntaxe de requête ». Vous trouverez plus d’informations sur les différences dans LINQ (Language-Integrated Query).

Les commandes LINQ telles que les suivantes peuvent être utilisées avec les objets débogueur. Tous. Tout. Compter. Première. Aplatir. Groupby. Dernière. Orderby. OrderByDescending, . Sélectionnez et . Où. Ces méthodes suivent (aussi étroitement que possible) la forme de la méthode LINQ C#.

Objets débogueur natifs

Les objets débogueur natifs représentent différents constructions et comportements de l’environnement du débogueur. Les exemples d’objets débogueur sont les suivants :

  • session
  • Threads / Thread
  • Processus / Processus
  • Stack Frames / Stack Frame
  • Variables locales
  • Modules / Module
  • Utilitaire
  • State
  • Paramètres

Vous pouvez également utiliser les objets débogueur avec NatVis. Pour plus d’informations, consultez Objets débogueur natifs dans NatVis. Pour plus d’informations sur l’utilisation d’objets débogueur avec JavaScript, consultez Objets débogueur natifs dans les extensions JavaScript. Pour plus d’informations sur l’utilisation de C++ et des objets de pilote, consultez Vue d’ensemble du modèle de données C++ du débogueur.

Commande Dx

Les exemples présentés ici utilisent la commande dx. Pour plus d’informations sur l’utilisation de la commande dx, consultez dx (Display Debugger Object Model Expression).

Développement d’une requête LINQ

Une façon de développer une requête d’objet débogueur LINQ consiste à utiliser les liens DML affichés pour explorer le modèle de données afin de localiser d’abord l’objet de débogueur qui sera utilisé dans la requête.

Pour cet exemple, nous aimerions afficher une liste de processus dans une session de débogage du noyau et le nombre de threads pour chacun de ces processus.

Pour commencer notre exploration, nous pouvons utiliser la commande dx pour afficher l’objet débogueur de niveau supérieur.

0: kd> dx Debugger
Debugger
    Sessions
    Settings
    State
    Utility

Après avoir sélectionné les rubriques de niveau supérieur, nous déterminons que les sessions semblent les plus intéressantes. Nous sélectionnons donc le lien DML pour révéler qu’il contient des processus.

0: kd> dx -r1 Debugger.Sessions[0]
Debugger.Sessions[0]                 : Remote KD: KdSrv:Server=@{<Local>},Trans=@{NET:Port=50005,Key=MyKey}
    Processes
    Id               : 0
    Attributes

Ensuite, nous sélectionnons plus bas pour examiner un processus spécifique et nous voyons que les threads associés à ce processus sont disponibles. Lorsque nous sélectionnons Threads pour l’un des processus, nous voyons que tous les threads associés à ce processus sont disponibles.

0: kd> dx -r1 Debugger.Sessions[0].Processes[1428].Threads
Debugger.Sessions[0].Processes[1428].Threads
    [0x598]          : <Unable to get stack trace> [Switch To]
    [0x1220]         : <Unable to get stack trace> [Switch To]
    [0x6f8]          : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To]
    [0x128c]         : <Unable to get stack trace> [Switch To]
    [0x27e4]         : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To] 

Nous savons maintenant que les données dont nous avons besoin pour afficher le nombre de threads associés à un processus sont disponibles dans le modèle objet du débogueur.

Pour raccourcir un peu la requête LINQ, nous pouvons utiliser les variables définies par le système décrites plus loin dans cette rubrique pour afficher les processus associés à la session active.

0: kd> dx @$cursession.Processes
@$cursession.Processes                
    [0x0]            : Idle [Switch To]
    [0x4]            : System [Switch To]
    [0x90]           : Registry [Switch To]
...

Ajoutez ensuite une instruction select. Pour commencer, nous pouvons spécifier le champ Nom.

0: kd> dx @$cursession.Processes.Select(p => p.Name)
@$cursession.Processes.Select(p => p.Name)                
    [0x0]            : Idle
    [0x4]            : System
    [0x90]           : Registry
...

Pour notre scénario, nous avons également besoin du nombre de threads. Étant donné qu’il existe deux champs, créez un type anonyme à l’aide de new, similaire à la syntaxe de type anonyme de C# décrite ci-dessous dans Variables définies par l’utilisateur.

dx @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})

Avec cette commande, 'dx' n’imprime plus le nom, donc ajoutez -r2 (récursez deux niveaux) pour afficher nom et threads.

dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})
@$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})                
    [0x0]           
        Name             : Idle
        Threads         
    [0x4]           
        Name             : System
        Threads         
    [0x90]          
        Name             : Registry
        Threads       

À ce stade, nous affichons le nom du processus et une liste de threads. Pour afficher le ThreadCount, utilisez le . Méthode Count().

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})                
    [0x0]           
        Name             : Idle
        ThreadCount      : 0x4
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0x90]          
        Name             : Registry
        ThreadCount      : 0x4
...

Pour voir quels processus ont un grand nombre de threads, triez la liste par nombre de threads à l’aide de OrderByDescending.

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)                
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0xa38]         
        Name             : svchost.exe
        ThreadCount      : 0x45
    [0x884]         
        Name             : MemCompression
        ThreadCount      : 0x3e

Pour afficher dans une grille mise en forme, remplacez « -r2 » par « -g ». Le niveau de récursivité n’a pas besoin d’être spécifié, car l’option de grille affiche les colonnes de manière appropriée. Enfin, ajoutez le spécificateur de format « ,d » aux valeurs décimales de sortie.

0: kd> dx -g @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount),d
===========================================================================================
=            = Name                                                         = ThreadCount =
===========================================================================================
= [4]        - System                                                       - 231         =
= [2616]     - svchost.exe                                                  - 69          =
= [2180]     - MemCompression                                               - 62          =
= [968]      - explorer.exe                                                 - 61          =

Exemples d’objets débogueur

Cet exemple montre les 5 principaux processus exécutant le plus de threads :

0: kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5
Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5 

: 
    [0x4]            : 
        Name             : <Unknown Image>
        ThreadCount      : 0x73
    [0x708]          : 
        Name             : explorer.exe
        ThreadCount      : 0x2d
    [0x37c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x2c
    [0x6b0]          : 
        Name             : MsMpEng.exe
        ThreadCount      : 0x22
    [0x57c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x15
    [...]       

Cet exemple montre les appareils de l’arborescence d’appareils plug-and-play regroupés par nom du pilote de l’objet de périphérique physique. Toute la sortie n’est pas affichée.

kd> dx -r2 Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString())
Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString()) 

: 
    ["\"\\Driver\\PnpManager\""] : 
        [0x0]            : HTREE\ROOT\0
        [0x1]            : ROOT\volmgr\0000 (volmgr)
        [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
        [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
        [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
         ...  

Saisie semi-automatique de l’onglet Commande Dx

La saisie semi-automatique de la touche TAB contextuelle prend en compte les méthodes de requête LINQ et fonctionne pour les paramètres des lambdas.

Par exemple, tapez (ou copiez-collez) le texte suivant dans le débogueur. Appuyez ensuite plusieurs fois sur la touche TAB pour parcourir les achèvements potentiels.

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.

Appuyez sur la touche TAB jusqu’à . Nom » s’affiche. Ajoutez une parenthèse fermante « ) » et appuyez sur Entrée pour exécuter la commande.

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name) : 
    [0x274]          : 
        Name             : winlogon.exe
        ThreadCount      : 0x4
    [0x204]          : 
        Name             : wininit.exe
        ThreadCount      : 0x2
    [0x6c4]          : 
        Name             : taskhostex.exe
        ThreadCount      : 0x8
         ...  

Cet exemple montre l’achèvement avec une méthode de comparateur de clé. La substitution affiche les méthodes de chaîne, car la clé est une chaîne.

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.

Appuyez sur la touche TAB jusqu’à . Longueur » s’affiche. Ajoutez une parenthèse fermante « ) » et appuyez sur Entrée pour exécuter la commande.

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length) : 
    [0x544]          : 
        Name             : spoolsv.exe
        ThreadCount      : 0xc
    [0x4d4]          : 
        Name             : svchost.exe
        ThreadCount      : 0xa
    [0x438]          : 
        Name             : svchost.exe

Variables définies par l’utilisateur

Une variable définie par l’utilisateur peut être définie en préfixant le nom de la variable avec @$. Une variable définie par l’utilisateur peut être affectée à tout ce que dx peut utiliser, par exemple, les lambdas, les résultats des requêtes LINQ, etc.

Vous pouvez créer et définir la valeur d’une variable utilisateur comme ceci.

kd> dx @$String1="Test String"

Vous pouvez afficher les variables utilisateur définies à l’aide de Debugger.State.UserVariables ou @$vars.

kd> dx Debugger.State.UserVariables
Debugger.State.UserVariables : 
    mySessionVar     : 
    String1          : Test String

Vous pouvez supprimer une variable à l’aide de . Retirer.

kd> dx @$vars.Remove("String1")

Cet exemple montre comment définir une variable utilisateur pour référencer Debugger.Sesssions.

kd> dx @$mySessionVar = Debugger.Sessions

La variable définie par l’utilisateur peut ensuite être utilisée comme indiqué ci-dessous.

kd> dx -r2 @$mySessionVar 
@$mySessionVar   : 
    [0x0]            : Remote KD: KdSrv:Server=@{<Local>},Trans=@{COM:Port=\\.\com3,Baud=115200,Timeout=4000}
        Processes        : 
        Devices     

Variables définies par le système

Les variables définies par le système suivantes peuvent être utilisées dans n’importe quelle requête LINQ dx.

  • @$cursession - Session en cours

  • @$curprocess : processus en cours

  • @$curthread - Le thread actuel

Cet exemple montre l’utilisation des variables définies par le système.

kd> dx @$curprocess.Threads.Count()
@$curprocess.Threads.Count() : 0x4
kd> dx -r1 @$curprocess.Threads
@$curprocess.Threads : 
    [0x4adc]         : 
    [0x1ee8]         : 
    [0x51c8]         : 
    [0x62d8]         : 
     ...

Variables définies par l’utilisateur - Types anonymes

Cette création d’objets dynamiques est effectuée à l’aide de la syntaxe de type anonyme C# (new { ... }). Pour plus d’informations, consultez Types anonymes (Guide de programmation C#). Cet exemple crée un type anonyme avec un entier et une valeur de chaîne.

kd> dx -r1 new { MyInt = 42, MyString = "Hello World" }
new { MyInt = 42, MyString = "Hello World" } : 
    MyInt            : 42
    MyString         : Hello World

Objets de fonction (expressions lambda)

La plupart des méthodes utilisées pour interroger des données sont basées sur le concept d’exécution répétée d’une fonction fournie par l’utilisateur sur des objets d’une collection. Pour prendre en charge la possibilité d’interroger et de manipuler des données dans le débogueur, la commande dx prend en charge les expressions lambda à l’aide de la syntaxe C# équivalente. Une expression lambda est définie par l’utilisation de l’opérateur => comme suit :

(arguments) => (résultat)

Pour voir comment LINQ est utilisé avec dx, essayez cet exemple simple pour ajouter 5 et 7.

kd> dx ((x, y) => (x + y))(5, 7) 

La commande dx renvoie l’expression lambda et affiche le résultat de 12.

((x, y) => (x + y))(5, 7)  : 12

Cet exemple d’expression lambda combine les chaînes « Hello » et « World ».

kd> dx ((x, y) => (x + y))("Hello", "World")
((x, y) => (x + y))("Hello", "World") : HelloWorld

Syntaxe LINQ prise en charge - Méthodes de requête

Tout objet que dx définit comme itérable (qu’il s’agit d’un tableau natif, d’un type dont NatVis a écrit le décrivant comme un conteneur ou d’un objet d’extension de débogueur) a une série de méthodes LINQ (ou linQ équivalentes) projetées dessus. Ces méthodes de requête sont décrites ci-dessous. Les signatures des arguments des méthodes de requête sont répertoriées après toutes les méthodes de requête.

Méthodes de filtrage

. Where ( PredicateMethod ) : renvoie une nouvelle collection d’objets contenant chaque objet de la collection d’entrée pour lequel la méthode de prédicat a retourné true.

Méthodes de projection

. Aplatissement ( [KeyProjectorMethod] ) : prend un conteneur d’entrée de conteneurs (une arborescence) et l’aplatit en un seul conteneur qui contient chaque élément dans l’arborescence. Si la méthode de projecteur de clés facultative est fournie, l’arborescence est considérée comme un conteneur de clés qui sont elles-mêmes des conteneurs et ces clés sont déterminées par un appel à la méthode de projection.

. Sélectionner ( KeyProjectorMethod ) : renvoie une nouvelle collection d’objets contenant le résultat de l’appel de la méthode projecteur sur chaque objet de la collection d’entrée.

Méthodes de regroupement

. GroupBy ( KeyProjectorMethod, [KeyComparatorMethod] ) : renvoie une nouvelle collection de collections en regroupant tous les objets de la collection d’entrée ayant la même clé que celle déterminée par l’appel de la méthode du projecteur de clés. Une méthode de comparateur facultative peut être fournie.

Join (InnerCollection, méthode de sélecteur de clé externe, méthode de sélecteur de clé interne, méthode de sélecteur de résultats, [ComparatorMethod]) : joint deux séquences basées sur des fonctions de sélecteur de clés et extrait des paires de valeurs. Une méthode de comparateur facultative peut également être spécifiée.

Intersect (InnerCollection, [ComparatorMethod]) : renvoie l’intersection définie, ce qui signifie les éléments qui apparaissent dans chacune des deux collections. Une méthode de comparateur facultative peut également être spécifiée.

Union (InnerCollection, [ComparatorMethod]) : renvoie l’union définie, qui signifie les éléments uniques qui apparaissent dans l’une des deux collections. Une méthode de comparateur facultative peut également être spécifiée.

Méthodes de jeu de données

Contains (Object, [ComparatorMethod]) : détermine si une séquence contient un élément spécifié. Vous pouvez fournir une méthode de comparateur facultative qui sera appelée chaque fois que l’élément est comparé à une entrée dans la séquence.

Distinct ([ComparatorMethod]) : supprime les valeurs dupliquées d’une collection. Une méthode de comparateur facultative peut être fournie pour être appelée chaque fois que des objets de la collection doivent être comparés.

Sauf (InnerCollection, [ComparatorMethod]) : renvoie la différence définie, ce qui signifie les éléments d’une collection qui n’apparaissent pas dans une deuxième collection. Une méthode de comparateur facultative peut être spécifiée.

Concat (InnerCollection) : concatène deux séquences pour former une seule séquence.

Méthodes de classement

. OrderBy ( KeyProjectorMethod, [KeyComparatorMethod] ) : trie la collection dans l’ordre croissant en fonction d’une clé comme fourni en appelant la méthode de projection de clé sur chaque objet de la collection d’entrée. Une méthode de comparateur facultative peut être fournie.

. OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod] ) : trie la collection dans l’ordre décroissant en fonction d’une clé comme fourni en appelant la méthode de projection de clé sur chaque objet de la collection d’entrée. Une méthode de comparateur facultative peut être fournie.

Agrégation des méthodes

Count () : méthode qui retourne le nombre d’éléments dans la collection.

Somme ([ProjectionMethod]) : calcule la somme des valeurs d’une collection. Peut éventuellement spécifier une méthode de projecteur pour transformer les éléments avant que la somme ne se produise.

Ignorer les méthodes

Skip (Count) : ignore les éléments jusqu’à une position spécifiée dans une séquence.

SkipWhile (PredicateMethod) : ignore les éléments basés sur une fonction de prédicat jusqu’à ce qu’un élément ne remplit pas la condition.

Méthodes Take

Take (Count) : prend les éléments jusqu’à une position spécifiée dans une séquence.

TakeWhile (PredicateMethod) : prend des éléments basés sur une fonction de prédicat jusqu’à ce qu’un élément ne remplisse pas la condition.

Méthodes de comparaison

SequenceEqual (InnerCollection, [ComparatorMethod]) : détermine si deux séquences sont égales en comparant les éléments d’une manière par paire. Un comparateur facultatif peut être spécifié.

Méthodes de gestion des erreurs

AllNonError (PredicateMethod) : retourne si tous les éléments non-erreur d’une collection satisfont à une condition donnée.

FirstNonError ([PredicateMethod]) : renvoie le premier élément d’une collection qui n’est pas une erreur.

LastNonError ([PredicateMethod]) : renvoie le dernier élément d’une collection qui n’est pas une erreur.

Autres méthodes

. All ( PredicateMethod ) : retourne si le résultat de l’appel de la méthode de prédicat spécifiée sur chaque élément de la collection d’entrée est vrai.

. Any ( PredicateMethod ) : indique si le résultat de l’appel de la méthode de prédicat spécifiée sur un élément de la collection d’entrée est vrai.

. First ( [PredicateMethod] ) : renvoie le premier élément de la collection. Si le prédicat facultatif est passé, retourne le premier élément de la collection pour lequel un appel au prédicat retourne true.

. Last ( [PredicateMethod] ) : renvoie le dernier élément de la collection. Si le prédicat facultatif est passé, retourne le dernier élément de la collection pour lequel un appel au prédicat retourne true.

Min([KeyProjectorMethod]) : renvoie l’élément minimal de la collection. Une méthode de projecteur facultative peut être spécifiée pour projeter chaque méthode avant d’être comparée à d’autres.

Max([KeyProjectorMethod]) : renvoie l’élément maximal de la collection. Une méthode de projecteur facultative peut être spécifiée pour projeter chaque méthode avant d’être comparée à d’autres.

Single([PredicateMethod]) : renvoie le seul élément de la liste (ou une erreur si la collection contient plusieurs éléments). Si un prédicat est spécifié, retourne l’élément unique qui satisfait ce prédicat (si plusieurs éléments le satisfont, la fonction retourne une erreur à la place).

Signatures des arguments

KeyProjectorMethod : ( obj => clé arbitraire ) Prend un objet de la collection et retourne une clé de cet objet.
KeyComparatorMethod : ( (a, b) => valeur entière ) Prend deux clés et les compare en retournant :

-1 si ( a < b )

0 si ( a == b)

1 si ( a > b )

PrédicateMethod : ( obj => valeur booléenne ) Prend un objet de la collection et retourne true ou false selon que cet objet répond à certains critères.

Syntaxe LINQ prise en charge - Manipulation de chaîne

Les méthodes suivantes sont projetées dans tous les objets de chaîne, afin qu’elles soient disponibles pour utilisation :

Interroger les méthodes pertinentes & propriétés

. Contains ( OtherString ) : renvoie une valeur booléenne indiquant si la chaîne d’entrée contient OtherString.

. EndsWith ( OtherString ) : renvoie une valeur booléenne indiquant si la chaîne d’entrée se termine par OtherString.

Length : propriété qui retourne la longueur de la chaîne.

. StartsWith ( OtherString ) : retourne une valeur booléenne indiquant si la chaîne d’entrée commence par OtherString.

. Sous-chaîne ( StartPos, [Length] ) : retourne une sous-chaîne dans la chaîne d’entrée commençant à la position de départ donnée. Si la longueur facultative est fournie, la sous-chaîne retournée sera de la longueur spécifiée ; dans le cas contraire , elle ira à la fin de la chaîne.

Méthodes diverses

. IndexOf ( OtherString) : renvoie l’index de la première occurrence d’OtherString dans la chaîne d’entrée.

. LastIndexOf ( OtherString) : renvoie l’index de la dernière occurrence d’OtherString dans la chaîne d’entrée.

Méthodes de mise en forme

. PadLeft ( TotalWidth) : ajoute des espaces si nécessaire sur le côté gauche de la chaîne afin d’amener la longueur totale de la chaîne à la largeur spécifiée.

. PadRight ( TotalWidth) : ajoute des espaces si nécessaire sur le côté droit de la chaîne afin d’apporter la longueur totale de la chaîne à la largeur spécifiée.

. Remove ( StartPos, [Length] ) : supprime les caractères de la chaîne d’entrée en commençant par la position de départ spécifiée. Si le paramètre de longueur facultatif est fourni, ce nombre de caractères est supprimé ; sinon , tous les caractères à la fin de la chaîne seront supprimés.

. Replace ( SearchString, ReplaceString ) : remplace chaque occurrence de SearchString dans la chaîne d’entrée par la valeur ReplaceString spécifiée.

Projections d’objets string

En plus des méthodes qui sont projetées directement sur des objets string, tout objet qui a lui-même une conversion de chaîne est projeté sur la méthode suivante, ce qui le rend disponible pour utilisation :

. ToDisplayString ( ) : renvoie une conversion de chaîne de l’objet. Il s’agit de la conversion de chaîne qui serait affichée dans un appel dx pour l’objet. Vous pouvez fournir un spécificateur de mise en forme pour mettre en forme la sortie de ToDisplayString. Pour plus d’informations, consultez Mettre en forme des spécificateurs pour C++ dans le débogueur Visual Studio.

Les exemples suivants illustrent l’utilisation de spécificateurs de format.

kd> dx (10).ToDisplayString("d")
(10).ToDisplayString("d") : 10

kd> dx (10).ToDisplayString("x")
(10).ToDisplayString("x") : 0xa

kd> dx (10).ToDisplayString("o")
(10).ToDisplayString("o") : 012

kd> dx (10).ToDisplayString("b") 
(10).ToDisplayString("b")  : 0y1010

kd> dx ("some wchar string here").ToDisplayString("su") 
("some wchar string here").ToDisplayString("su")  : "some wchar string here"

kd> dx ("some wchar string here").ToDisplayString("sub") 
("some wchar string here").ToDisplayString("sub")  : some wchar string here

Exemple de débogage Plug-and-Play

Cette section montre comment les objets de débogueur intégrés utilisés avec les requêtes LINQ peuvent être utilisés pour déboguer des objets plug-and-play.

Voir tous les appareils

Utilisez Aplatir sur l’arborescence de l’appareil pour afficher tous les appareils.

 1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
    [0x5]            : ROOT\spaceport\0000 (spaceport)
    [0x6]            : ROOT\KDNIC\0000 (kdnic)
    [0x7]            : ROOT\UMBUS\0000 (umbus)
    [0x8]            : ROOT\ACPI_HAL\0000
...

Affichage de la grille

Comme avec d’autres commandes dx, vous pouvez sélectionner et maintenir (ou cliquer avec le bouton droit) une commande après son exécution et sélectionner « Afficher sous forme de grille » ou ajouter « -g » à la commande pour obtenir une vue grille des résultats.

# 0: kd> dx -g @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
=====================================================================================================================================================================================================================================================================================================================
# =                                                              = (+) DeviceNodeObject = InstancePath                                                 = ServiceName               = (+) PhysicalDeviceObject                                    = State                          = (+) Resources = (+) Children       =
=====================================================================================================================================================================================================================================================================================================================
= [0x0] : HTREE\ROOT\0                                         - {...}                - HTREE\ROOT\0                                                 -                           - 0xffffb6075614be40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x1] : ROOT\volmgr\0000 (volmgr)                            - {...}                - ROOT\volmgr\0000                                             - volmgr                    - 0xffffb607561fbe40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x2] : ROOT\BasicDisplay\0000 (BasicDisplay)                - {...}                - ROOT\BasicDisplay\0000                                       - BasicDisplay              - 0xffffb607560739b0 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x3] : ROOT\CompositeBus\0000 (CompositeBus)                - {...}                - ROOT\CompositeBus\0000                                       - CompositeBus              - 0xffffb607561f9060 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
...

Afficher les appareils par état

Utilisez Where pour spécifier un état d’appareil spécifique.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State <operator> <state number>)

Par exemple, pour afficher les appareils dans l’état DeviceNodeStarted, utilisez cette commande.

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
...

Afficher les appareils non démarrés

Utilisez cette commande pour afficher les appareils qui ne sont pas dans l’état DeviceNodeStarted.

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)                
    [0x0]            : ACPI\PNP0C01\1
    [0x1]            : ACPI\PNP0000\4&215d0f95&0
    [0x2]            : ACPI\PNP0200\4&215d0f95&0
    [0x3]            : ACPI\PNP0100\4&215d0f95&0
    [0x4]            : ACPI\PNP0800\4&215d0f95&0
    [0x5]            : ACPI\PNP0C04\4&215d0f95&0
    [0x6]            : ACPI\PNP0700\4&215d0f95&0 (fdc)
    [0x7]            : ACPI\PNP0C02\1
    [0x8]            : ACPI\PNP0C02\2

Afficher les appareils par code de problème

Utilisez l’objet DeviceNodeObject.Problem pour afficher les appareils qui ont des codes de problème spécifiques.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem <operator> <problemCode>)

Par exemple, pour afficher les appareils qui ont un code de problème non nul, utilisez cette commande. Cela fournit des informations similaires à « !devnode 0 21 ».

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

Afficher tous les appareils sans problème

Utilisez cette commande pour afficher tous les appareils sans problème

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)                
    [0x0]            : ROOT\volmgr\0000 (volmgr)
    [0x1]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x2]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x3]            : ROOT\vdrvroot\0000 (vdrvroot)
...

Afficher tous les appareils présentant un problème spécifique

Utilisez cette commande pour afficher les appareils dont l’état de problème est 0x16.

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

Afficher les appareils par pilote de fonction

Utilisez cette commande pour afficher les appareils par pilote de fonction.

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName <operator> <service name>)

Pour afficher les appareils utilisant un certain pilote de fonction, tel qu’atapi, utilisez cette commande.

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")                
    [0x0]            : PCIIDE\IDEChannel\4&10bf2f88&0&0 (atapi)
    [0x1]            : PCIIDE\IDEChannel\4&10bf2f88&0&1 (atapi)

Affichage d’une liste de pilotes de démarrage

Pour afficher la liste des pilotes winload chargés en tant que pilotes de démarrage, vous devez être dans un contexte où vous avez accès au LoaderBlock et suffisamment tôt où le LoaderBlock est toujours là. Par exemple, pendant nt ! IopInitializeBootDrivers. Un point d’arrêt peut être défini pour s’arrêter dans ce contexte.

1: kd> g
Breakpoint 0 hit
nt!IopInitializeBootDrivers:
8225c634 8bff            mov     edi,edi

Utilisez l’opérateur ?? commande permettant d’afficher la structure du pilote de démarrage.

1: kd> ?? LoaderBlock->BootDriverListHead
struct _LIST_ENTRY
 [ 0x808c9960 - 0x808c8728 ]
   +0x000 Flink            : 0x808c9960 _LIST_ENTRY [ 0x808c93e8 - 0x808a2e18 ]
   +0x004 Blink            : 0x808c8728 _LIST_ENTRY [ 0x808a2e18 - 0x808c8de0 ]

Utilisez l’objet débogueur Debugger.Utility.Collections.FromListEntry pour afficher les données, à l’aide de l’adresse de départ de la structure nt !_LIST_ENTRY.

1: kd> dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")
Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")                
    [0x0]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x1]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x2]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x3]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x4]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x5]            [Type: _BOOT_DRIVER_LIST_ENTRY]
...

Utilisez l’option -g pour créer une vue grille des données.

dx -r1 -g Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")

Afficher les appareils par fonctionnalité

Affichez les appareils par fonctionnalité à l’aide de l’objet DeviceNodeObject.CapabilityFlags.

dx -r1 @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & <flag>) != 0)

Ce tableau récapitule l’utilisation de la commande dx avec les indicateurs de capacité d’appareil courants.

Amovible

dbgcmd 0 : kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0)
[0x0] : SWD\PRINTENUM{2F8DBBB6-F246-4D84-BB1D-AA8761353885} [0x1] : SWD\PRINTENUM{F210BC77-55A1-4FCA-AA80-013E2B408378} [0x2 : SWD\PRINTENUM{07940A8E-11F4-46C3-B714-7FF9B87738F8} [0x3] : DISPLAY\Default_Monitor\6&1a097cd8&0&UID5527112 (moniteur)

UniqueID

dbgcmd 0 : kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

SilentInstall

dbgcmd 0 : kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

RawDeviceOk

dbgcmd 0 : kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x2] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT ...

SurpriseRemovalOK

dbgcmd 0 : kd> dx -r1 @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0) @$cursession. Devices.DeviceTree.Flatten(n => n.Children). Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0)
[0x0] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x1] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT [0x2] : SWD\PRINTENUM\PrintQueues ...

Pour plus d’informations sur les fonctionnalités CapabilityFlags, consultez DEVICE_CAPABILITIES.

Voir aussi

dx (Display Debugger Object Model Expression)

Objets débogueur natifs dans NatVis

Objets débogueur natifs dans les extensions JavaScript