Uso di LINQ Con gli oggetti debugger
La sintassi LINQ può essere usata con gli oggetti debugger per cercare e modificare i dati. L'uso della sintassi LINQ con il comando dx consente un'esperienza più coerente rispetto all'uso dei comandi del debugger. L'output e le opzioni sono coerenti indipendentemente dall'oggetto debugger che si sta esaminando. Le query LINQ consentono di porre domande come "Quali sono i primi 5 processi che eseguono la maggior parte dei thread?".
Gli oggetti debugger vengono proiettati in uno spazio dei nomi rooted in "Debugger". Processi, moduli, thread, stack, stack frame e variabili locali sono tutti disponibili per l'uso in una query LINQ.
LINQ è concettualmente simile al Structured Query Language (SQL) usato per eseguire query sui database. È possibile usare diversi metodi LINQ per cercare, filtrare e analizzare i dati di debug. Viene usata la sintassi del metodo LINQ C#. Per altre informazioni sulla sintassi LINQ e LINQ C#, vedere Introduzione con LINQ in C#
LINQ usato nel supporto del debugger usa la "sintassi del metodo" di LINQ e non la "sintassi di query". Per altre informazioni sulle differenze, vedere LINQ (Language-Integrated Query).
I comandi LINQ, ad esempio i seguenti, possono essere usati con gli oggetti debugger. Tutti. Qualsiasi. Conteggio. Prima. Appiattire. Groupby. Ultima. Orderby. Orderbydescending. Selezionare e . Dove. Questi metodi seguono (il più possibile) il modulo del metodo LINQ C#.
Oggetti debugger nativi
Gli oggetti debugger nativi rappresentano vari costrutti e comportamenti dell'ambiente del debugger. Gli oggetti debugger di esempio includono quanto segue.
- sessione
- Thread/Thread
- Processi/Processo
- Stack Frame/Stack Frame
- Variabili locali
- Moduli/Modulo
- Utilità
- State
- Impostazioni
È anche possibile usare gli oggetti debugger con NatVis. Per altre informazioni, vedere Oggetti debugger nativi in NatVis. Per informazioni sull'uso di oggetti debugger con JavaScript, vedere Oggetti debugger nativi nelle estensioni JavaScript. Per informazioni sull'uso di C++ e degli oggetti driver, vedere Cenni preliminari sul modello di dati del debugger C++.
Comando Dx
Gli esempi illustrati qui usano il comando dx, per altre informazioni sull'uso del comando dx, vedere dx (Display Debugger Object Model Expression).
Sviluppo di una query LINQ
Un modo per sviluppare una query dell'oggetto debugger LINQ consiste nell'usare i collegamenti DML visualizzati per esplorare il modello di dati per individuare prima l'oggetto debugger che verrà usato nella query.
Per questo esempio, si vuole visualizzare un elenco di processi in una sessione di debug del kernel e il numero di thread per ognuno di questi processi.
Per avviare l'esplorazione, è possibile usare il comando dx per visualizzare l'oggetto debugger di primo livello.
0: kd> dx Debugger
Debugger
Sessions
Settings
State
Utility
Dopo aver selezionato gli argomenti di primo livello, si determina che Sessioni ha un aspetto più interessante, quindi si seleziona il collegamento DML per visualizzare che contiene Processi.
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
Selezionare quindi più avanti per esaminare il processo specifico e si noterà che i thread associati a tale processo sono disponibili. Quando si seleziona Thread per uno dei processi, vengono visualizzati tutti i thread associati a tale processo.
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]
Ora sappiamo che i dati che è necessario visualizzare il numero di thread associati a un processo sono disponibili nel modello a oggetti del debugger.
Per rendere più breve la query LINQ, è possibile usare le variabili definite dal sistema descritte più avanti in questo argomento per visualizzare i processi associati alla sessione corrente.
0: kd> dx @$cursession.Processes
@$cursession.Processes
[0x0] : Idle [Switch To]
[0x4] : System [Switch To]
[0x90] : Registry [Switch To]
...
Aggiungere quindi un'istruzione select. Per iniziare, è possibile specificare il campo Nome.
0: kd> dx @$cursession.Processes.Select(p => p.Name)
@$cursession.Processes.Select(p => p.Name)
[0x0] : Idle
[0x4] : System
[0x90] : Registry
...
Per lo scenario è necessario anche il numero di thread. Poiché sono presenti due campi, creare un tipo anonimo usando una nuova sintassi di tipo anonimo, simile alla sintassi di tipo anonimo di C#descritta di seguito in Variabili definite dall'utente.
dx @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})
Con questo comando 'dx' non stampa più il nome, quindi aggiungere -r2 (due livelli) per visualizzare Nome e Thread.
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
A questo punto viene visualizzato il nome del processo e un elenco di thread. Per visualizzare ThreadCount, usare . Metodo 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
...
Per vedere quali processi hanno un numero elevato di thread, ordinare l'elenco in base al numero di thread usando 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
Per eseguire il rendering in una griglia formattata, modificare '-r2' in '-g'. Non è necessario specificare il livello di ricorsione, perché l'opzione griglia visualizza le colonne in modo appropriato. Infine, aggiungere l'identificatore di formato ",d" ai valori decimali di output.
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 =
Esempi di oggetti debugger
Questo esempio mostra i primi 5 processi che eseguono la maggior parte dei thread:
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
[...]
Questo esempio mostra i dispositivi nell'albero dei dispositivi plug and play raggruppati in base al nome del driver dell'oggetto dispositivo fisico. Non viene visualizzato tutto l'output.
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)
...
Completamento automatico della scheda Comando Dx
Il completamento automatico della chiave TAB contestuale riconosce i metodi di query LINQ e funziona per i parametri delle espressioni lambda.
Ad esempio, digitare (o copiare e incollare) il testo seguente nel debugger. Premere quindi tabulazione più volte per scorrere i potenziali completamenti.
dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.
Premere TAB fino a ". Viene visualizzato il nome". Aggiungere una parentesi di chiusura ")" e premere INVIO per eseguire il comando.
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
...
In questo esempio viene illustrato il completamento con un metodo di confronto della chiave. La sostituzione mostrerà i metodi stringa, poiché la chiave è una stringa.
dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.
Premere TAB fino a ". Viene visualizzata la lunghezza. Aggiungere una parentesi di chiusura ")" e premere INVIO per eseguire il comando.
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
Variabili definite dall'utente
Una variabile definita dall'utente può essere definita anteponendo al nome della variabile @$. Una variabile definita dall'utente può essere assegnata a qualsiasi elemento dx può usare, ad esempio espressioni lambda, risultati delle query LINQ e così via.
È possibile creare e impostare il valore di una variabile utente in questo modo.
kd> dx @$String1="Test String"
È possibile visualizzare le variabili utente definite usando Debugger.State.UserVariables o @$vars.
kd> dx Debugger.State.UserVariables
Debugger.State.UserVariables :
mySessionVar :
String1 : Test String
È possibile rimuovere una variabile usando . Rimuovere.
kd> dx @$vars.Remove("String1")
In questo esempio viene illustrato come definire una variabile utente per fare riferimento a Debugger.Sesssions.
kd> dx @$mySessionVar = Debugger.Sessions
La variabile definita dall'utente può quindi essere usata come illustrato di seguito.
kd> dx -r2 @$mySessionVar
@$mySessionVar :
[0x0] : Remote KD: KdSrv:Server=@{<Local>},Trans=@{COM:Port=\\.\com3,Baud=115200,Timeout=4000}
Processes :
Devices
Variabili definite dal sistema
Le variabili definite dal sistema seguenti possono essere usate in qualsiasi query LINQ dx.
@$cursession - Sessione corrente
@$curprocess - Processo corrente
@$curthread - Thread corrente
In questo esempio viene illustrato l'uso delle variabili definite dal sistema.
kd> dx @$curprocess.Threads.Count()
@$curprocess.Threads.Count() : 0x4
kd> dx -r1 @$curprocess.Threads
@$curprocess.Threads :
[0x4adc] :
[0x1ee8] :
[0x51c8] :
[0x62d8] :
...
Variabili definite dall'utente - Tipi anonimi
Questa creazione di oggetti dinamici viene eseguita usando la sintassi del tipo anonimo C# (new { ... }). Per altre informazioni sui tipi anonimi, vedere Tipi anonimi (Guida per programmatori C#). In questo esempio viene creato un tipo anonimo con un valore integer e stringa.
kd> dx -r1 new { MyInt = 42, MyString = "Hello World" }
new { MyInt = 42, MyString = "Hello World" } :
MyInt : 42
MyString : Hello World
Oggetti Funzione (espressioni lambda)
Molti dei metodi usati per eseguire query sui dati si basano sul concetto di esecuzione ripetuta di una funzione fornita dall'utente tra gli oggetti di una raccolta. Per supportare la possibilità di eseguire query e modificare i dati nel debugger, il comando dx supporta espressioni lambda usando la sintassi C# equivalente. Un'espressione lambda viene definita dall'utilizzo dell'operatore => come indicato di seguito:
(arguments) => (risultato)
Per vedere come viene usato LINQ con dx, provare questo semplice esempio per aggiungere insieme 5 e 7.
kd> dx ((x, y) => (x + y))(5, 7)
Il comando dx restituisce l'espressione lambda e visualizza il risultato di 12.
((x, y) => (x + y))(5, 7) : 12
Questa espressione lambda di esempio combina le stringhe "Hello" e "World".
kd> dx ((x, y) => (x + y))("Hello", "World")
((x, y) => (x + y))("Hello", "World") : HelloWorld
Sintassi LINQ supportata - Metodi di query
Qualsiasi oggetto che dx definisce come iterabile (sia che una matrice nativa, un tipo con NatVis scritto come contenitore o un oggetto di estensione del debugger) abbia una serie di metodi LINQ (o LINQ equivalenti) proiettati su di esso. Questi metodi di query sono descritti di seguito. Le firme degli argomenti ai metodi di query sono elencate dopo tutti i metodi di query.
Metodi di filtro
. Where ( PredicateMethod ): restituisce una nuova raccolta di oggetti contenenti ogni oggetto nell'insieme di input per cui il metodo predicato ha restituito true.
Metodi di proiezione
. Flatten ( [KeyProjectorMethod] ): accetta un contenitore di input di contenitori (un albero) e lo appiattisce in un singolo contenitore con ogni elemento nell'albero. Se viene fornito il metodo di proiettore chiave facoltativo, l'albero viene considerato un contenitore di chiavi che sono contenitori e tali chiavi vengono determinate da una chiamata al metodo di proiezione.
. Select ( KeyProjectorMethod ): restituisce una nuova raccolta di oggetti contenente il risultato della chiamata al metodo proiettore su ogni oggetto nell'insieme di input.
Metodi di raggruppamento
. GroupBy ( KeyProjectorMethod, [KeyComparatorMethod]: restituisce una nuova raccolta di raccolte raggruppando tutti gli oggetti nell'insieme di input con la stessa chiave determinata chiamando il metodo del proiettore chiave. È possibile specificare un metodo di confronto facoltativo.
Join (InnerCollection, metodo selettore di chiavi esterne, metodo selettore chiave interna, metodo selettore risultato, [ComparatorMethod]: aggiunge due sequenze in base alle funzioni del selettore chiave ed estrae coppie di valori. È anche possibile specificare un metodo di confronto facoltativo.
Intersect (InnerCollection, [ComparatorMethod]): restituisce l'intersezione del set, ovvero gli elementi visualizzati in ognuna di due raccolte. È anche possibile specificare un metodo di confronto facoltativo.
Union (InnerCollection, [ComparatorMethod]: restituisce l'unione set, ovvero elementi univoci visualizzati in una delle due raccolte. È anche possibile specificare un metodo di confronto facoltativo.
Metodi del set di dati
Contiene (Oggetto, [ComparatorMethod]: determina se una sequenza contiene un elemento specificato. È possibile specificare un metodo di confronto facoltativo che verrà chiamato ogni volta che l'elemento viene confrontato con una voce nella sequenza.
Distinct ([ComparatorMethod]): rimuove i valori duplicati da una raccolta. È possibile specificare un metodo di confronto facoltativo da chiamare ogni volta che gli oggetti della raccolta devono essere confrontati.
Tranne (InnerCollection, [ComparatorMethod]: restituisce la differenza impostata, ovvero gli elementi di una raccolta che non vengono visualizzati in una seconda raccolta. È possibile specificare un metodo di confronto facoltativo.
Concat (InnerCollection): concatena due sequenze per formare una sequenza.
Metodi di ordinamento
. OrderBy ( KeyProjectorMethod, [KeyComparatorMethod] ): ordina l'insieme in ordine crescente in base a una chiave fornita chiamando il metodo di proiezione chiave su ogni oggetto nell'insieme di input. È possibile specificare un metodo di confronto facoltativo.
. OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod]: ordina l'insieme in ordine decrescente in base a una chiave, come indicato chiamando il metodo di proiezione chiave su ogni oggetto dell'insieme di input. È possibile specificare un metodo di confronto facoltativo.
Metodi di aggregazione
Count (): metodo che restituisce il numero di elementi nell'insieme.
Sum ([ProjectionMethod]): calcola la somma dei valori in una raccolta. Facoltativamente, è possibile specificare un metodo proiettore per trasformare gli elementi prima che si verifichi la somma.
Ignora metodi
Skip (Count): ignora gli elementi fino a una posizione specificata in una sequenza.
SkipWhile (PredicateMethod): ignora gli elementi in base a una funzione predicato fino a quando un elemento non soddisfa la condizione.
Accetta metodi
Accetta (Conteggio): accetta elementi fino a una posizione specificata in una sequenza.
TakeWhile (PredicateMethod): accetta elementi in base a una funzione predicato fino a quando un elemento non soddisfa la condizione.
Metodi di confronto
SequenceEqual (InnerCollection, [ComparatorMethod]: determina se due sequenze sono uguali confrontando gli elementi in modo saggio. È possibile specificare un comparatore facoltativo.
Metodi di gestione degli errori
AllNonError (PredicateMethod): restituisce se tutti gli elementi non di errore di una raccolta soddisfano una determinata condizione.
FirstNonError ([PredicateMethod]: restituisce il primo elemento di una raccolta che non è un errore.
LastNonError ([PredicateMethod]: restituisce l'ultimo elemento di una raccolta che non è un errore.
Altri metodi
. All ( PredicateMethod ): restituisce se il risultato della chiamata al metodo predicato specificato su ogni elemento della raccolta di input è true.
. Any ( PredicateMethod ): restituisce se il risultato della chiamata al metodo predicato specificato su qualsiasi elemento della raccolta di input è true.
. First ( [PredicateMethod] ): Restituisce il primo elemento dell'insieme. Se il predicato facoltativo viene passato, restituisce il primo elemento della raccolta per cui una chiamata al predicato restituisce true.
. Last ( [PredicateMethod] ): Restituisce l'ultimo elemento della raccolta. Se il predicato facoltativo viene passato, restituisce l'ultimo elemento della raccolta per cui una chiamata al predicato restituisce true.
Min([KeyProjectorMethod]: Restituisce l'elemento minimo della raccolta. È possibile specificare un metodo di proiettore facoltativo per proiettare ogni metodo prima che venga confrontato con altri.
Max([KeyProjectorMethod]): Restituisce l'elemento massimo della raccolta. È possibile specificare un metodo di proiettore facoltativo per proiettare ogni metodo prima che venga confrontato con altri.
Single([PredicateMethod]: restituisce l'unico elemento dell'elenco (o un errore se la raccolta contiene più di un elemento). Se viene specificato un predicato, restituisce l'singolo elemento che soddisfa tale predicato (se più di un elemento lo soddisfa, la funzione restituisce invece un errore).
Firme degli argomenti
KeyProjectorMethod : ( obj => chiave arbitraria ) | Accetta un oggetto dell'insieme e restituisce una chiave da tale oggetto. |
KeyComparatorMethod: ( (a, b) => valore intero ) | Accetta due chiavi e ne confronta la restituzione: -1 se ( a < b ) 0 se ( a == b) 1 se ( a > b ) |
PredicateMethod: ( obj => valore booleano ) | Accetta un oggetto dell'insieme e restituisce true o false in base al fatto che l'oggetto soddisfi determinati criteri. |
Sintassi LINQ supportata - Manipolazione delle stringhe
Tutti gli oggetti stringa hanno i metodi seguenti proiettati in essi, in modo che siano disponibili per l'uso:
Eseguire query sui metodi pertinenti & proprietà
. Contiene ( OtherString ): restituisce un valore booleano che indica se la stringa di input contiene OtherString.
. EndWith (OtherString): restituisce un valore booleano che indica se la stringa di input termina con OtherString.
Lunghezza: proprietà che restituisce la lunghezza della stringa.
. StartsWith ( OtherString ): restituisce un valore booleano che indica se la stringa di input inizia con OtherString.
. Sottostringa ( StartPos, [Length] ): restituisce una sottostringa all'interno della stringa di input a partire dalla posizione iniziale specificata. Se viene specificata la lunghezza facoltativa, la sottostringa restituita sarà della lunghezza specificata; in caso contrario, verrà visualizzata alla fine della stringa.
Metodi vari
. IndexOf ( OtherString ): restituisce l'indice della prima occorrenza di OtherString all'interno della stringa di input.
. LastIndexOf ( OtherString): restituisce l'indice dell'ultima occorrenza di OtherString all'interno della stringa di input.
Metodi di formattazione
. PadLeft ( TotalWidth ): aggiunge spazi in base alle esigenze del lato sinistro della stringa per portare la lunghezza totale della stringa alla larghezza specificata.
. PadRight ( TotalWidth ): aggiunge spazi in base alle esigenze del lato destro della stringa per portare la lunghezza totale della stringa alla larghezza specificata.
. Remove ( StartPos, [Length] ): rimuove i caratteri dalla stringa di input a partire dalla posizione iniziale specificata. Se viene specificato il parametro di lunghezza facoltativo, tale numero di caratteri verrà rimosso; altrimenti: tutti i caratteri alla fine della stringa verranno rimossi.
. Sostituisci ( SearchString, ReplaceString ): sostituisce ogni occorrenza di SearchString all'interno della stringa di input con l'oggetto ReplaceString specificato.
Proiezioni di oggetti stringa
Oltre ai metodi proiettati direttamente sugli oggetti stringa, qualsiasi oggetto che ha una conversione stringa ha il metodo seguente proiettato su di esso, rendendolo disponibile per l'uso:
. ToDisplayString ( ): restituisce una conversione stringa dell'oggetto. Si tratta della conversione stringa che verrà visualizzata in una chiamata dx per l'oggetto. È possibile fornire un identificatore di formattazione per formattare l'output di ToDisplayString. Per altre informazioni, vedere Identificatori di formato per C++ nel debugger di Visual Studio
Gli esempi seguenti illustrano l'uso degli identificatori di formato.
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
Esempio di debug Plug and Play
Questa sezione illustra il modo in cui gli oggetti debugger predefiniti usati con query LINQ possono essere usati per eseguire il debug di oggetti plug and play.
Visualizzare tutti i dispositivi
Usare Flatten nell'albero dei dispositivi per visualizzare tutti i dispositivi.
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
...
Visualizzazione della griglia
Come per altri comandi dx, è possibile selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) un comando dopo l'esecuzione e selezionare "Visualizza come griglia" o aggiungere "-g" al comando per ottenere una visualizzazione griglia dei risultati.
# 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] =
...
Visualizzare i dispositivi in base allo stato
Usare Dove specificare uno stato specifico del dispositivo.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State <operator> <state number>)
Ad esempio, per visualizzare i dispositivi nello stato DeviceNodeStarted usare questo comando.
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)
...
Visualizzare i dispositivi non avviati
Usare questo comando per visualizzare i dispositivi non nello stato 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
Visualizzare i dispositivi in base al codice del problema
Usare l'oggetto DeviceNodeObject.Problem per visualizzare i dispositivi con codici di problema specifici.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem <operator> <problemCode>)
Ad esempio, per visualizzare i dispositivi con codice non zero problema, usare questo comando. In questo modo vengono fornite informazioni simili a "!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)
Visualizzare tutti i dispositivi senza problemi
Usare questo comando per visualizzare tutti i dispositivi senza problemi
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)
...
Visualizzare tutti i dispositivi con un problema specifico
Usare questo comando per visualizzare i dispositivi con uno stato di problema di 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)
Visualizzare i dispositivi in base al driver di funzione
Usare questo comando per visualizzare i dispositivi in base al driver di funzione.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName <operator> <service name>)
Per visualizzare i dispositivi che usano un determinato driver di funzione, ad esempio atapi, usare questo comando.
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)
Visualizzazione di un elenco di driver di avvio
Per visualizzare l'elenco dei driver di avvio caricati come winload, è necessario trovarsi in un contesto in cui si ha accesso a LoaderBlock e abbastanza presto loaderBlock è ancora in giro. Ad esempio, durante nt! IopInitializeBootDrivers. Un punto di interruzione può essere impostato per arrestarsi in questo contesto.
1: kd> g
Breakpoint 0 hit
nt!IopInitializeBootDrivers:
8225c634 8bff mov edi,edi
Usare ?? comando per visualizzare la struttura del driver di avvio.
1: kd> ?? LoaderBlock->BootDriverListHead
struct _LIST_ENTRY
[ 0x808c9960 - 0x808c8728 ]
+0x000 Flink : 0x808c9960 _LIST_ENTRY [ 0x808c93e8 - 0x808a2e18 ]
+0x004 Blink : 0x808c8728 _LIST_ENTRY [ 0x808a2e18 - 0x808c8de0 ]
Usare l'oggetto debugger Debugger.Utility.Collections.FromListEntry per visualizzare i dati usando l'indirizzo iniziale della struttura 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]
...
Usare l'opzione -g per creare una visualizzazione griglia dei dati.
dx -r1 -g Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")
Visualizzare i dispositivi in base alla funzionalità
Visualizzare i dispositivi usando l'oggetto DeviceNodeObject.CapabilityFlags.
dx -r1 @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & <flag>) != 0)
Questa tabella riepiloga l'uso del comando dx con flag comuni di funzionalità del dispositivo.
Removibile |
|
UniqueID |
|
SilentInstall |
|
RawDeviceOk |
|
SorpresaRemovalOK |
|
Per altre informazioni sulle funzionalitàFlags, vedere DEVICE_CAPABILITIES.
Vedere anche
dx (Visualizzazione espressione del modello a oggetti debugger)
Oggetti debugger nativi in NatVis
Oggetti debugger nativi nelle estensioni JavaScript