Uso de LINQ Con los objetos del depurador
La sintaxis LINQ se puede usar con los objetos del depurador para buscar y manipular datos. El uso de la sintaxis LINQ con el comando dx permite una experiencia más coherente en comparación con el uso de comandos del depurador. La salida y las opciones son coherentes independientemente del objeto del depurador que examine. Las consultas LINQ permiten formular preguntas como "¿Cuáles son los cinco procesos principales que ejecutan la mayoría de los subprocesos?".
Los objetos del depurador se proyectan en un espacio de nombres rooteado en "Debugger". Los procesos, los módulos, los subprocesos, las pilas, los marcos de pila y las variables locales están disponibles para usarse en una consulta LINQ.
LINQ es conceptualmente similar al Lenguaje de consulta estructurado (SQL) que se usa para consultar las bases de datos. Puede usar varios métodos LINQ para buscar, filtrar y analizar datos de depuración. Se usa la sintaxis del método LINQ C#. Para obtener más información sobre LINQ y la sintaxis de LINQ C#, vea Introducción con LINQ en C#
LINQ que se usa en la compatibilidad con el depurador usa la "sintaxis de método" de LINQ y no la "sintaxis de consulta". Puede encontrar más detalles sobre las diferencias en LINQ (Language-Integrated Query).
Los comandos LINQ, como los siguientes, se pueden usar con los objetos del depurador. Todo. Cualquier. Contar. Primero. Aplanar. Groupby. Última. Orderby. OrderByDescending, . Seleccione y . Dónde. Estos métodos siguen (lo más cerca posible) el formulario del método LINQ de C#.
Objetos de depurador nativos
Los objetos del depurador nativo representan diversas construcciones y comportamientos del entorno del depurador. Los objetos de depurador de ejemplo incluyen lo siguiente.
- Sesión
- Subprocesos o subprocesos
- Procesos y procesos
- Marcos de pila/Marco de pila
- Variables locales
- Módulos o módulos
- Utilidad
- State
- Configuración
También puede trabajar con los objetos del depurador con NatVis. Para obtener más información, vea Objetos de depurador nativo en NatVis. Para obtener información sobre el uso de objetos de depurador con JavaScript, vea Objetos de depurador nativos en extensiones de JavaScript. Para obtener información sobre cómo trabajar con C++ y los objetos de controlador, vea Información general sobre el modelo de datos del depurador de C++.
Comando Dx
En los ejemplos que se muestran aquí se usa el comando dx para obtener más información sobre cómo trabajar con el comando dx, vea dx (Display Debugger Object Model Expression)).
Desarrollo de una consulta LINQ
Una manera de desarrollar una consulta de objetos del depurador LINQ es usar los vínculos DML que se muestran para explorar el modelo de datos para localizar primero el objeto del depurador que se usará en la consulta.
En este ejemplo, nos gustaría mostrar una lista de procesos en una sesión de depuración del kernel y el número de subprocesos para cada uno de esos procesos.
Para iniciar la exploración, podemos usar el comando dx para mostrar el objeto del depurador de nivel superior.
0: kd> dx Debugger
Debugger
Sessions
Settings
State
Utility
Después de seleccionar los temas de nivel superior, determinamos que Las sesiones son más interesantes, por lo que seleccionamos el vínculo DML para mostrar que contiene Procesos.
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
A continuación, seleccionamos más abajo para examinar el proceso específico y vemos que los subprocesos asociados a ese proceso están disponibles. Al seleccionar Subprocesos para uno de los procesos, vemos que todos los subprocesos asociados a ese proceso están 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]
Ahora sabemos que los datos que necesitamos para mostrar el número de subprocesos asociados a un proceso están disponibles en el modelo de objetos del depurador.
Para que la consulta LINQ sea un poco más corta, podemos usar las variables definidas por el sistema descritas más adelante en este tema para mostrar los procesos asociados a la sesión actual.
0: kd> dx @$cursession.Processes
@$cursession.Processes
[0x0] : Idle [Switch To]
[0x4] : System [Switch To]
[0x90] : Registry [Switch To]
...
A continuación, agregue una instrucción select. Para empezar, podemos especificar el campo Nombre.
0: kd> dx @$cursession.Processes.Select(p => p.Name)
@$cursession.Processes.Select(p => p.Name)
[0x0] : Idle
[0x4] : System
[0x90] : Registry
...
Para nuestro escenario, también necesitamos el número de subprocesos. Dado que hay dos campos, cree un tipo anónimo mediante la sintaxis de tipo anónimo de C#, similar a la sintaxis de tipo anónimo de C#que se describe a continuación en Variables definidas por el usuario.
dx @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})
Con ese comando, 'dx' ya no imprime el nombre, por lo que agrega -r2 (recurse dos niveles) para mostrar Nombre y subprocesos.
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
En este momento se muestra el nombre del proceso y una lista de subprocesos. Para mostrar ThreadCount, use . Método 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
...
Para ver qué procesos tienen un gran número de subprocesos, ordene la lista por recuento de subprocesos mediante 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
Para representar en una cuadrícula con formato, cambie "-r2" a "-g". No es necesario especificar el nivel de recursividad, ya que la opción de cuadrícula muestra las columnas correctamente. Por último, agregue el especificador de formato ",d" a los valores decimales de salida.
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 =
Ejemplos de objetos del depurador
En este ejemplo se muestran los cinco procesos principales que ejecutan la mayoría de los subprocesos:
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
[...]
En este ejemplo se muestran los dispositivos del árbol de dispositivos plug and play agrupados por el nombre del controlador del objeto de dispositivo físico. No se muestra toda la salida.
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)
...
Finalización automática de la pestaña Comando Dx
La finalización automática de la clave TAB contextual es consciente de los métodos de consulta LINQ y funcionará para parámetros de lambdas.
Por ejemplo, escriba (o copie y pegue) el texto siguiente en el depurador. A continuación, presione la tecla TAB varias veces para recorrer posibles finalizaciones.
dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.
Presione la tecla TAB hasta ". Aparece name" (Nombre). Agregue un paréntesis de cierre ")" y presione Entrar para ejecutar el 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
...
En este ejemplo se muestra la finalización con un método comparador de claves. La sustitución mostrará métodos de cadena, ya que la clave es una cadena.
dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.
Presione la tecla TAB hasta ". Aparece length" (Longitud). Agregue un paréntesis de cierre ")" y presione Entrar para ejecutar el 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
Variables definidas por el usuario
Una variable definida por el usuario se puede definir mediante el prefijo del nombre de la variable con @$. Una variable definida por el usuario se puede asignar a cualquier dx que pueda utilizar, por ejemplo, lambdas, los resultados de las consultas LINQ, etc.
Puede crear y establecer el valor de una variable de usuario como esta.
kd> dx @$String1="Test String"
Puede mostrar las variables de usuario definidas mediante Debugger.State.UserVariables o @$vars.
kd> dx Debugger.State.UserVariables
Debugger.State.UserVariables :
mySessionVar :
String1 : Test String
Puede quitar una variable mediante . Eliminar.
kd> dx @$vars.Remove("String1")
En este ejemplo se muestra cómo definir una variable de usuario para hacer referencia a Debugger.Sesssions.
kd> dx @$mySessionVar = Debugger.Sessions
La variable definida por el usuario se puede usar como se muestra a continuación.
kd> dx -r2 @$mySessionVar
@$mySessionVar :
[0x0] : Remote KD: KdSrv:Server=@{<Local>},Trans=@{COM:Port=\\.\com3,Baud=115200,Timeout=4000}
Processes :
Devices
Variables definidas por el sistema
Las siguientes variables definidas por el sistema se pueden usar en cualquier consulta LINQ dx.
@$cursession: la sesión actual
@$curprocess: el proceso actual
@$curthread: subproceso actual
En este ejemplo se muestra el uso de las variables definidas por el sistema.
kd> dx @$curprocess.Threads.Count()
@$curprocess.Threads.Count() : 0x4
kd> dx -r1 @$curprocess.Threads
@$curprocess.Threads :
[0x4adc] :
[0x1ee8] :
[0x51c8] :
[0x62d8] :
...
Variables definidas por el usuario: tipos anónimos
Esta creación de objetos dinámicos se realiza mediante la sintaxis de tipo anónimo de C# (nuevo { ... }). Para obtener más información, consulte Tipos anónimos (Guía de programación de C#). En este ejemplo se crea un tipo anónimo con un valor entero y de cadena.
kd> dx -r1 new { MyInt = 42, MyString = "Hello World" }
new { MyInt = 42, MyString = "Hello World" } :
MyInt : 42
MyString : Hello World
Objetos function (expresiones lambda)
Muchos de los métodos que se usan para consultar datos se basan en el concepto de ejecutar repetidamente una función proporcionada por el usuario entre objetos de una colección. Para admitir la capacidad de consultar y manipular datos en el depurador, el comando dx admite expresiones lambda mediante la sintaxis equivalente de C#. Una expresión lambda se define mediante el uso del operador => de la siguiente manera:
(argumentos) => (resultado)
Para ver cómo se usa LINQ con dx, pruebe este ejemplo sencillo para agregar juntos 5 y 7.
kd> dx ((x, y) => (x + y))(5, 7)
El comando dx devuelve la expresión lambda y muestra el resultado de 12.
((x, y) => (x + y))(5, 7) : 12
Esta expresión lambda de ejemplo combina las cadenas "Hello" y "World".
kd> dx ((x, y) => (x + y))("Hello", "World")
((x, y) => (x + y))("Hello", "World") : HelloWorld
Sintaxis LINQ admitida: métodos de consulta
Cualquier objeto que dx define como iterable (ser que una matriz nativa, un tipo que tiene NatVis escrito que lo describe como un contenedor o un objeto de extensión del depurador) tiene una serie de métodos LINQ (o equivalentes de LINQ) proyectados en él. Estos métodos de consulta se describen a continuación. Las firmas de los argumentos de los métodos de consulta se enumeran después de todos los métodos de consulta.
Métodos de filtrado
. Where ( PredicateMethod ): devuelve una nueva colección de objetos que contienen todos los objetos de la colección de entrada para la que el método de predicado devolvió true.
Métodos de proyección
. Flatten ( [KeyProjectorMethod]): toma un contenedor de entrada de contenedores (un árbol) y lo aplana en un único contenedor que tiene todos los elementos del árbol. Si se proporciona el método opcional del proyector de claves, el árbol se considera un contenedor de claves que son propios contenedores y esas claves se determinan mediante una llamada al método de proyección.
. Select ( KeyProjectorMethod ): devuelve una nueva colección de objetos que contienen el resultado de llamar al método del proyector en cada objeto de la colección de entrada.
Métodos de agrupamiento
. GroupBy ( KeyProjectorMethod, [KeyComparatorMethod]): devuelve una nueva colección de colecciones mediante la agrupación de todos los objetos de la colección de entrada que tienen la misma clave que se determina mediante una llamada al método del proyector de claves. Se puede proporcionar un método comparador opcional.
Join (InnerCollection, método del selector de claves externo, método selector de claves interno, método selector de resultados, [ComparatorMethod]): combina dos secuencias basadas en funciones del selector de claves y extrae pares de valores. También se puede especificar un método comparador opcional.
Intersect (InnerCollection, [ComparatorMethod]): devuelve la intersección del conjunto, lo que significa que los elementos que aparecen en cada una de las dos colecciones. También se puede especificar un método comparador opcional.
Union (InnerCollection, [ComparatorMethod]): devuelve la unión set, lo que significa elementos únicos que aparecen en cualquiera de las dos colecciones. También se puede especificar un método comparador opcional.
Métodos de conjunto de datos
Contains (Object, [ComparatorMethod]): determina si una secuencia contiene un elemento especificado. Se puede proporcionar un método comparador opcional que se llamará cada vez que el elemento se compara con una entrada de la secuencia.
Distinct ([ComparatorMethod]): quita valores duplicados de una colección. Se puede proporcionar un método comparador opcional para llamarse cada vez que se deben comparar objetos de la colección.
Excepto (InnerCollection, [ComparatorMethod]): devuelve la diferencia establecida, lo que significa que los elementos de una colección que no aparecen en una segunda colección. Se puede especificar un método comparador opcional.
Concat (InnerCollection): concatena dos secuencias para formar una secuencia.
Métodos de ordenación
. OrderBy ( KeyProjectorMethod, [KeyComparatorMethod]): ordena la colección en orden ascendente según una clave según lo proporcionado llamando al método de proyección de clave en cada objeto de la colección de entrada. Se puede proporcionar un método comparador opcional.
. OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod]): ordena la colección en orden descendente según una clave tal y como se proporciona llamando al método de proyección de clave en cada objeto de la colección de entrada. Se puede proporcionar un método comparador opcional.
Agregar métodos
Count (): método que devuelve el número de elementos de la colección.
Sum ([ProjectionMethod]): calcula la suma de los valores de una colección. Opcionalmente, puede especificar un método de proyector para transformar los elementos antes de que se produzca la suma.
Skip (métodos)
Skip (Count): omite los elementos hasta una posición especificada en una secuencia.
SkipWhile (PredicateMethod):omite los elementos basados en una función de predicado hasta que un elemento no cumple la condición.
Métodos Take
Take (Count): toma elementos hasta una posición especificada en una secuencia.
TakeWhile (PredicateMethod): toma elementos basados en una función de predicado hasta que un elemento no cumple la condición.
Métodos de comparación
SequenceEqual (InnerCollection, [ComparatorMethod]): determina si dos secuencias son iguales mediante la comparación de elementos de manera emparejada. Se puede especificar un comparador opcional.
Métodos de control de errores
AllNonError (PredicateMethod): devuelve si todos los elementos que no son de error de una colección cumplen una condición determinada.
FirstNonError ([PredicateMethod]): devuelve el primer elemento de una colección que no es un error.
LastNonError ([PredicateMethod]): devuelve el último elemento de una colección que no es un error.
Otros métodos
. All ( PredicateMethod ): devuelve si el resultado de llamar al método de predicado especificado en cada elemento de la colección de entrada es true.
. Any ( PredicateMethod ): devuelve si el resultado de llamar al método de predicado especificado en cualquier elemento de la colección de entrada es true.
. First ( [PredicateMethod] ): devuelve el primer elemento de la colección. Si se pasa el predicado opcional, devuelve el primer elemento de la colección para el que una llamada al predicado devuelve true.
. Last ( [PredicateMethod] ): devuelve el último elemento de la colección. Si se pasa el predicado opcional, devuelve el último elemento de la colección para el que una llamada al predicado devuelve true.
Min([KeyProjectorMethod]):: devuelve el elemento mínimo de la colección. Se puede especificar un método de proyector opcional para proyectar cada método antes de compararlo con otros.
Max([KeyProjectorMethod]): devuelve el elemento máximo de la colección. Se puede especificar un método de proyector opcional para proyectar cada método antes de compararlo con otros.
Single([PredicateMethod]): devuelve el único elemento de la lista (o un error si la colección contiene más de un elemento). Si se especifica un predicado, devuelve el único elemento que satisface ese predicado (si más de un elemento lo satisface, la función devuelve un error en su lugar).
Firmas de los argumentos
KeyProjectorMethod : ( obj => clave arbitraria ) | Toma un objeto de la colección y devuelve una clave de ese objeto. |
KeyComparatorMethod: ( (a, b) => valor entero ) | Toma dos claves y las compara devolviendo: -1 si ( a < b ) 0 si ( a == b) 1 si ( a > b ) |
PredicateMethod: ( obj => valor booleano ) | Toma un objeto de la colección y devuelve true o false en función de si ese objeto cumple determinados criterios. |
Sintaxis linq admitida: manipulación de cadenas
Todos los objetos de cadena tienen los métodos siguientes proyectados en ellos, de modo que estén disponibles para su uso:
Consulta de métodos pertinentes & propiedades
. Contains ( OtherString ): devuelve un valor booleano que indica si la cadena de entrada contiene OtherString.
. EndsWith ( OtherString ):: devuelve un valor booleano que indica si la cadena de entrada termina con OtherString.
Length: propiedad que devuelve la longitud de la cadena.
. StartsWith ( OtherString ):: devuelve un valor booleano que indica si la cadena de entrada comienza con OtherString.
. Subcadena ( StartPos, [Length] ): devuelve una subcadena dentro de la cadena de entrada a partir de la posición inicial especificada. Si se proporciona la longitud opcional, la subcadena devuelta será de la longitud especificada; de lo contrario, irá al final de la cadena.
Métodos varios
. IndexOf ( OtherString ):: devuelve el índice de la primera aparición de OtherString dentro de la cadena de entrada.
. LastIndexOf ( OtherString ): devuelve el índice de la última aparición de OtherString dentro de la cadena de entrada.
Métodos de formato
. PadLeft ( TotalWidth ): agrega espacios según sea necesario al lado izquierdo de la cadena para llevar la longitud total de la cadena al ancho especificado.
. PadRight ( TotalWidth ): agrega espacios según sea necesario al lado derecho de la cadena para llevar la longitud total de la cadena al ancho especificado.
. Remove ( StartPos, [Length] ): quita los caracteres de la cadena de entrada a partir de la posición inicial especificada. Si se proporciona el parámetro de longitud opcional, se quitará ese número de caracteres; de lo contrario, se quitarán todos los caracteres al final de la cadena.
. Replace ( SearchString, ReplaceString ): reemplaza todas las apariciones de SearchString dentro de la cadena de entrada por el replaceString especificado.
Proyecciones de objeto de cadena
Además de los métodos que se proyectan directamente en objetos de cadena, cualquier objeto que tenga una conversión de cadena tiene el siguiente método proyectado en él, lo que hace que el método esté disponible para su uso:
. ToDisplayString ( ): devuelve una conversión de cadena del objeto . Esta es la conversión de cadena que se mostraría en una invocación dx para el objeto . Puede proporcionar un especificador de formato para dar formato a la salida de ToDisplayString. Para obtener más información, vea Especificadores de formato para C++ en el depurador de Visual Studio.
En los ejemplos siguientes se muestra el uso de especificadores de 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
Ejemplo de depuración Plug and Play
En esta sección se muestra cómo se pueden usar los objetos del depurador integrados con consultas LINQ para depurar objetos plug and play.
Ver todos los dispositivos
Use Flatten en el árbol de dispositivos para ver todos los dispositivos.
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
...
Visualización de la cuadrícula
Al igual que con otros comandos dx, puede seleccionar y mantener presionado (o hacer clic con el botón derecho) un comando después de ejecutarse y seleccionar "Mostrar como cuadrícula" o agregar "-g" al comando para obtener una vista de cuadrícula de los resultados.
# 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] =
...
Ver dispositivos por estado
Use Where para especificar un estado de dispositivo específico.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State <operator> <state number>)
Por ejemplo, para ver los dispositivos en el estado DeviceNodeStarted, use este 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)
...
Ver dispositivos no iniciados
Use este comando para ver los dispositivos que no están en el estado 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
Ver dispositivos por código de problema
Use el objeto DeviceNodeObject.Problem para ver los dispositivos que tienen códigos de problema específicos.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem <operator> <problemCode>)
Por ejemplo, para ver los dispositivos que tienen un código de problema distinto de cero, use este comando. Esto proporciona información similar 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)
Ver todos los dispositivos sin un problema
Use este comando para ver todos los dispositivos sin ningún problema.
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)
...
Ver todos los dispositivos con un problema específico
Use este comando para ver los dispositivos con un estado problemático de 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)
Ver dispositivos por controlador de función
Use este comando para ver los dispositivos por controlador de función.
dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName <operator> <service name>)
Para ver los dispositivos mediante un controlador de función determinado, como atapi, use este 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)
Ver una lista de controladores de arranque
Para ver la lista de lo que winload cargó como controladores de inicio de arranque, debe estar en un contexto en el que tenga acceso a LoaderBlock y lo suficientemente temprano como loaderBlock todavía está alrededor. Por ejemplo, durante nt! IopInitializeBootDrivers. Se puede establecer un punto de interrupción para que se detenga en este contexto.
1: kd> g
Breakpoint 0 hit
nt!IopInitializeBootDrivers:
8225c634 8bff mov edi,edi
Use el operador ?? comando para mostrar la estructura del controlador de arranque.
1: kd> ?? LoaderBlock->BootDriverListHead
struct _LIST_ENTRY
[ 0x808c9960 - 0x808c8728 ]
+0x000 Flink : 0x808c9960 _LIST_ENTRY [ 0x808c93e8 - 0x808a2e18 ]
+0x004 Blink : 0x808c8728 _LIST_ENTRY [ 0x808a2e18 - 0x808c8de0 ]
Use el objeto debugger.Utility.Collections.FromListEntry para ver los datos mediante la dirección inicial de la estructura 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]
...
Use la opción -g para crear una vista de cuadrícula de los datos.
dx -r1 -g Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")
Visualización de dispositivos por funcionalidad
Vea los dispositivos mediante la funcionalidad mediante el objeto DeviceNodeObject.CapabilityFlags.
dx -r1 @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & <flag>) != 0)
En esta tabla se resume el uso del comando dx con marcas de funcionalidad de dispositivo comunes.
Extraíble |
|
UniqueID |
|
SilentInstall |
|
RawDeviceOk |
|
SurpriseRemovalOK |
|
Para obtener más información sobre CapabilityFlags, consulte DEVICE_CAPABILITIES.
Vea también
dx (Mostrar expresión del modelo de objetos del depurador)
Objetos de depurador nativos en NatVis
Objetos de depurador nativos en extensiones de JavaScript