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 |
|
UniqueID |
|
SilentInstall |
|
RawDeviceOk |
|
SurpriseRemovalOK |
|
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