Laboratorio paso a paso de controladores de Windows de depuración (modo kernel eco)

En este laboratorio se presenta el depurador de kernel de WinDbg. Use WinDbg para depurar el código del controlador de ejemplo del modo kernel de eco.

Objetivos del laboratorio

Este laboratorio incluye ejercicios que presentan las herramientas de depuración, enseñan comandos de depuración comunes, ilustran el uso de puntos de interrupción y muestran cómo usar las extensiones de depuración.

En este laboratorio, usará una conexión de depuración de kernel activa para explorar las siguientes acciones:

  • Uso de los comandos del depurador de Windows
  • Uso de comandos estándar (pilas de llamadas, variables, subprocesos, IRQL)
  • Uso de comandos de depuración de controladores avanzados (!commands)
  • Uso de símbolos
  • Establecimiento de puntos de interrupción en la depuración en tiempo real
  • Visualización de las pilas de llamadas
  • Visualización del árbol de dispositivos Plug and Play
  • Trabajo con el contexto de subprocesos y procesos

Depuración en modo de usuario y kernel

Al trabajar con el depurador de Windows, puede realizar dos tipos de depuración:

Modo de usuario: las aplicaciones y subsistemas se ejecutan en el equipo en modo de usuario. Los procesos que se ejecutan en modo de usuario lo hacen dentro de sus propios espacios de direcciones virtuales. Están restringidos a obtener acceso directo a muchas partes del sistema, incluido el hardware del sistema, la memoria que no está asignada para su uso y otras partes del sistema que podrían poner en peligro la integridad del sistema. Dado que los procesos que se ejecutan en modo de usuario están aislados eficazmente del sistema y de otros procesos en modo de usuario, no pueden interferir con estos recursos.

Modo kernel: el sistema operativo y los programas con privilegios se ejecutan en modo kernel. El código en modo kernel tiene permiso para acceder a cualquier parte del sistema. No está restringido como el código en modo de usuario. Puede obtener acceso a cualquier parte de cualquier otro proceso que se ejecute en modo de usuario o en modo kernel. Gran parte de la funcionalidad principal del sistema operativo y muchos controladores de dispositivos de hardware se ejecutan en modo kernel.

En este ejercicio se tratan los comandos de depuración que se usan con frecuencia durante la depuración en modo de usuario y en modo kernel. En el ejercicio también se tratan las extensiones de depuración, a veces denominadas !commands, que se usan para la depuración en modo kernel.

Configuración del laboratorio

Necesita el siguiente hardware para completar el laboratorio:

  • Un equipo portátil o de escritorio (host) que ejecute Windows 10
  • Un segundo equipo portátil o de escritorio (destino) que ejecute Windows 10
  • Un concentrador de red o enrutador y cables de red para conectar los dos equipos
  • Acceso a Internet para descargar archivos de símbolos

Necesita el siguiente software para completar el laboratorio:

  • Visual Studio
  • Kit de desarrollo de software de Windows (SDK) para Windows 10
  • Kit de controladores de Windows (WDK) para Windows 10
  • Controlador de eco de ejemplo para Windows 10

El laboratorio incluye las secciones siguientes:

Conexión a una sesión WinDbg en modo kernel

En esta sección, configurará la depuración de red en el sistema host y de destino.

Los equipos de este laboratorio deben configurarse para usar una conexión de red Ethernet para la depuración del kernel.

Este laboratorio usa dos equipos. El depurador de Windows se ejecuta en el sistema host y el controlador de eco del marco de controladores del modo kernel (KMDF) se ejecuta en el sistema de destino.

Use un concentrador de red o enrutador y cables de red para conectar los dos equipos.

Diagrama que ilustra dos equipos conectados a través de un concentrador de red o enrutador.

Para trabajar con aplicaciones en modo kernel y usar WinDbg, se recomienda usar KDNET a través del transporte Ethernet. Para obtener información sobre cómo usar el protocolo de transporte Ethernet, consulte Introducción a WinDbg (modo kernel). Para obtener más información sobre cómo configurar el equipo de destino, consulte Preparación de un equipo para la implementación manual del controlador y Configuración de la depuración automática del kernel de red KDNET.

Configuración de la depuración en modo kernel mediante Ethernet

Para habilitar la depuración en modo kernel en el sistema de destino:

  1. En el sistema host, abra una ventana de símbolo del sistema y escriba ipconfig para determinar su dirección IP.

    Windows IP Configuration
    Ethernet adapter Ethernet:
       Connection-specific DNS Suffix  . :
       Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b%3
       Autoconfiguration IPv4 Address. . : 169.182.1.1
       Subnet Mask . . . . . . . . . . . : 255.255.0.0
       Default Gateway . . . . . . . . . :
    
  2. Registre la dirección IP del sistema host: ______________________________________

  3. En el sistema de destino, abra una ventana de símbolo del sistema y use el comando ping para confirmar la conectividad de red entre los dos sistemas.

    ping 169.182.1.1
    

    Use la dirección IP real del sistema host que registró en lugar de 169.182.1.1 que se muestra en la salida de ejemplo.

    Pinging 169.182.1.1 with 32 bytes of data:
    Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    
    Ping statistics for 169.182.1.1:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 0ms, Maximum = 1ms, Average = 0ms
    

Para habilitar la depuración en modo kernel en el sistema de destino, siga los pasos siguientes.

Importante

Antes de usar BCDEdit para cambiar la información de arranque, es posible que deba suspender temporalmente las características de seguridad de Windows, como BitLocker y Arranque seguro, en el equipo de prueba. Vuelva a habilitar estas características de seguridad cuando se completen las pruebas. Administre correctamente el equipo de prueba cuando las características de seguridad estén deshabilitadas. El arranque seguro normalmente está deshabilitado en UEFI. Para acceder a la configuración de UEFI, vaya a Sistema, Recuperación, Inicio avanzado. Después, seleccione Solucionar problemas, Opciones avanzadas, Configuración de firmware de UEFI. Tenga cuidado, ya que establecer incorrectamente las opciones de UEFI o deshabilitar BitLocker, puede hacer que el sistema sea inoperable.

  1. En el equipo de destino, abra una ventana de símbolo del sistema como administrador. Escriba este comando para habilitar la depuración:

    bcdedit /set {default} DEBUG YES
    
  2. Escriba este comando para habilitar la firma de pruebas:

    bcdedit /set TESTSIGNING ON 
    
  3. Escriba este comando para establecer la dirección IP del sistema host. Utilice la dirección IP del sistema host que registró anteriormente, no la que se muestra.

    bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    

    Advertencia

    Para aumentar la seguridad de la conexión y reducir el riesgo de las solicitudes de conexión aleatorias del depurador de cliente, use una clave aleatoria generada automáticamente. Para obtener más información, consulte Configuración de la depuración automática del kernel de red KDNET.

  4. Escriba este comando para confirmar que los valores de dbgsettings se han establecido correctamente:

    bcdedit /dbgsettings
    
    key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    debugtype               NET
    hostip                  169.168.1.1
    port                    50000
    dhcp                    Yes
    The operation completed successfully.
    

    Nota:

    Si recibe un mensaje del firewall y desea usar el depurador, marque las tres casillas.

    Captura de pantalla de cuadro de diálogo de alerta de seguridad de Windows que indica que el firewall de Windows ha bloqueado algunas características de una aplicación.

  5. En el equipo host, abra una ventana de símbolo del sistema como administrador. En este laboratorio usaremos la versión x64 de WinDbg.exe del Kit para controladores de Windows (WDK) que se instaló como parte de la instalación del kit de Windows. Cambie al directorio de WinDbg predeterminado; la ubicación predeterminada se muestra a continuación.

    cd C:\Program Files(x86)\Windows Kits\10\Debuggers\x64 
    

    En estos laboratorios se supone que ambos equipos ejecutan una versión de 64 bits de Windows tanto en el destino como en el host. Si no es así, el mejor enfoque es ejecutar el mismo bit de herramientas en el host en el que se ejecuta el destino. Por ejemplo, si el destino ejecuta Windows de 32 bits, ejecute una versión de 32 bits del depurador en el host. Para obtener más información, consulte Elección de herramientas de depuración de 32 o 64 bits.

  6. Abra WinDbg con depuración de usuario remoto mediante el siguiente comando. Los valores de la clave y el puerto coinciden con los valores establecidos anteriormente mediante BCDEdit en el equipo de destino.

    WinDbg –k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  7. Reinicie el sistema de destino.

  8. En un minuto o dos, la salida de depuración debe mostrarse en el sistema host.

    Microsoft (R) Windows Debugger Version 10.0.17074.1002 AMD64
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    Using NET for debugging
    Opened WinSock 2.0
    Waiting to reconnect...
    Connected to target 169.182.1.1 on port 50005 on local IP 169.182.1.2
    You can get the target MAC address by running .kdtargetmac command.
    Connected to Windows 10 16299 x64 target at (Wed Feb 28 17:16:23.051 2018 (UTC - 8:00)), ptr64 TRUE
    Kernel Debugger connection established.  (Initial Breakpoint requested)
    Symbol search path is: srv*
    Executable search path is: 
    Windows 10 Kernel Version 16299 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 16299.15.amd64fre.rs3_release.170928-1534
    Machine Name:
    Kernel base = 0xfffff800`9540d000 PsLoadedModuleList = 0xfffff800`95774110
    Debug session time: Wed Feb 28 17:16:23.816 2018 (UTC - 8:00)
    System Uptime: 0 days 0:00:20.534
    

La ventana Comando del depurador es la ventana de información de depuración principal en WinDbg. Puede escribir comandos del depurador y ver la salida del comando en esta ventana.

La ventana Comando del depurador se divide en dos paneles. Los comandos se escriben en el panel más pequeño, que es el panel de entrada de comandos, en la parte inferior de la ventana y la salida del comando se ve en el panel más grande de la parte superior de la ventana.

En el panel de entrada de comandos, use las teclas de flecha arriba y flecha abajo para desplazarse por el historial de comandos. Cuando aparezca un comando, puede editarlo o pulsar Entrar para ejecutar el comando.

Comandos y técnicas de depuración en modo kernel

En esta sección, usará comandos de depuración para mostrar información sobre el sistema de destino.

Algunos comandos de depuración muestran texto mediante el lenguaje de marcado del depurador (DML) que puede seleccionar para recopilar rápidamente más información.

  1. En el sistema host, use Ctrl+Bloq Despl en WinDBg para irrumpir en el código que se ejecuta en el sistema de destino. El sistema de destino puede tardar algún tiempo en responder.

    Pantalla principal del depurador en la que se muestra la salida de la ventana de comandos desde una conexión de kernel activa.

  2. Escriba el siguiente comando para habilitar DML en la ventana Comando del depurador:

    0: kd> .prefer_dml 1
    DML versions of commands on by default
    
  3. Puede acceder a la ayuda del comando de referencia mediante el comando .hh. Escriba el siguiente comando para ver la ayuda de referencia de comandos para .prefer_dml:

    0: kd> .hh .prefer_dml
    

    El archivo de ayuda del depurador muestra ayuda para el comando .prefer_dml.

    Captura de pantalla de la aplicación de ayuda del depurador que muestra ayuda para el comando .prefer-dml.

  4. Para visualizar información detallada de la versión en el sistema de destino, escriba el comando vertarget (Mostrar versión del equipo de destino) en la ventana WinDbg:

    0: kd> vertarget
    Windows 10 Kernel Version 9926 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 9926.0.amd64fre.fbl_awesome1501.150119-1648
    Machine Name: ""
    Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0
    Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)
    System Uptime: 0 days 01:31:58.931
    
  5. Para comprobar que está trabajando con el proceso correcto en modo kernel, escriba el comando lm (Enumerar módulos cargados) en la ventana WinDbg para mostrar los módulos cargados:

    0: Kd> lm
    start             end                 module name
    fffff801`09200000 fffff801`0925f000   volmgrx    (no symbols)
    fffff801`09261000 fffff801`092de000   mcupdate_GenuineIntel   (no symbols)
    fffff801`092de000 fffff801`092ec000   werkernel   (export symbols)       werkernel.sys
    fffff801`092ec000 fffff801`0934d000   CLFS       (export symbols)       CLFS.SYS
    fffff801`0934d000 fffff801`0936f000   tm         (export symbols)       tm.sys
    fffff801`0936f000 fffff801`09384000   PSHED      (export symbols)       PSHED.dll
    fffff801`09384000 fffff801`0938e000   BOOTVID    (export symbols)       BOOTVID.dll
    fffff801`0938e000 fffff801`093f7000   spaceport   (no symbols)
    fffff801`09400000 fffff801`094cf000   Wdf01000   (no symbols)
    fffff801`094d9000 fffff801`09561000   CI         (export symbols)       CI.dll
    ...
    

    La salida que se ha omitido se indica con "..." en este laboratorio.

  6. Para solicitar información detallada sobre un módulo específico, use la opción v (detallada):

    0: Kd> lm v m tcpip
    Browse full module list
    start             end                 module name
    fffff801`09eeb000 fffff801`0a157000   tcpip      (no symbols)           
        Loaded symbol image file: tcpip.sys
        Image path: \SystemRoot\System32\drivers\tcpip.sys
        Image name: tcpip.sys
        Browse all global symbols  functions  data
        Timestamp:        Sun Nov 09 18:59:03 2014 (546029F7)
        CheckSum:         00263DB1
        ImageSize:        0026C000
        Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    
    Unable to enumerate user-mode unloaded modules, Win32 error 0n30
    

    No hay ninguna ruta de acceso de símbolo establecida ni símbolos cargados, por lo que la información que está disponible en el depurador es limitada.

Descarga y compilación del controlador de eco KMDF

En esta sección, descargará y compilará el controlador de eco KMDF.

Normalmente, trabajaría con su propio código de controlador al usar WinDbg. Para familiarizarse con la operación WinDbg, este laboratorio usa el controlador de ejemplo de plantilla "Eco" de KMDF. El código fuente está disponible para ayudar a comprender la información que se muestra en WinDbg. Este ejemplo también se utiliza para ilustrar cómo se puede recorrer paso a paso el código nativo en modo kernel. Esta técnica puede ser valiosa para depurar problemas complejos de código en modo kernel.

Para descargar y compilar el controlador de audio de ejemplo eco:

  1. Descargue y extraiga el ejemplo de eco de KMDF de GitHub.

    El ejemplo de eco de KMDF se encuentra en la carpeta general.

    Captura de pantalla de la página windows-driver-samples de GitHub en la que se resalta la carpeta general y el botón de descargar zip.

    1. Descargue los ejemplos de controladores en un archivo zip: Ejemplos de controladores

    2. Descargue el archivo zip en la unidad de disco duro local.

    3. Seleccione y mantenga pulsado (o haga clic con el botón derecho) el archivo zip y seleccione Extraer todo. Especifique una nueva carpeta o vaya a una existente para almacenar los archivos extraídos. Por ejemplo, podría especificar C:\DriverSamples\ como la nueva carpeta en la que extraer los archivos.

    4. Una vez extraídos los archivos, vaya a la subcarpeta siguiente: C:\DriverSamples\general\echo\kmdf

  2. En Microsoft Visual Studio, seleccione Archivo>Abrir>Proyecto/Solución... y vaya a la carpeta que contiene los archivos extraídos, por ejemplo, C:\DriverSamples\general\echo\kmdf. Haga doble clic en el archivo de solución kmdfecho para abrirlo.

    En Visual Studio, localice el Explorador de soluciones. Si esta ventana aún no está abierta, seleccione Explorador de soluciones en el menú Ver. En el Explorador de soluciones, puede ver una solución que tiene tres proyectos.

    Captura de pantalla de Visual Studio que muestra el archivo device.c cargado desde el proyecto kmdfecho.

  3. Establezca la configuración y la plataforma del ejemplo. En el Explorador de soluciones, seleccione y mantenga pulsada (o haga clic con el botón derecho) la Solución "kmdfecho" (3 proyectos) y seleccione Administrador de configuración. Asegúrese de que la configuración y las opciones de plataforma sean las mismas para los tres proyectos. De forma predeterminada, la configuración se establece en Win10 Debug y la plataforma se establece en Win64 para todos los proyectos. Si realiza algún cambio de configuración o plataforma para un proyecto, debe realizar los mismos cambios para los tres proyectos restantes.

  4. Los ejemplos de controladores deben modificarse para usar valores que no se superpongan con los controladores existentes. Consulte De código de ejemplo a controlador de producción: qué cambiar en los ejemplos para obtener información sobre cómo crear un ejemplo de controlador único que coexista con los controladores reales existentes instalados en Windows.

  5. Establezca la biblioteca en tiempo de ejecución. Abra la página de propiedades del controlador de eco y busque C/C++>Generación de código. Cambie la biblioteca en tiempo de ejecución a Depuración multiproceso (/MTd). Para obtener más información sobre las opciones de compilación, consulte /MD, /MT, /LD (Uso de la biblioteca en tiempo de ejecución).

    Captura de pantalla de la página de propiedades de eco en Visual Studio en la que se resalta la configuración de la biblioteca en tiempo de ejecución.

  6. En las propiedades del controlador, asegúrese de que Firma de controladores>Modo de firma esté establecido en Firma de prueba.

    Captura de pantalla de la página de propiedades de eco en Visual Studio en la que se resalta la configuración del modo de firma.

  7. En Visual Studio, seleccione Compilar>Compilar solución.

    Las ventanas de compilación deberían mostrar un mensaje indicando que la compilación se ha realizado correctamente para los tres proyectos.

Sugerencia

Si encuentra un mensaje de error de compilación, use el número de error de compilación para determinar una corrección. Por ejemplo, el error MSBuild MSB8040 describe cómo trabajar con bibliotecas con mitigación de Spectre.

  1. En el Explorador de archivos, vaya a la carpeta que contiene los archivos extraídos para el ejemplo. Por ejemplo, vaya a C:\DriverSamples\general\echo\kmdf, si es la carpeta que especificó anteriormente. Dentro de esa carpeta, la ubicación de los archivos de controlador compilados varía en función de la configuración y de los ajustes de la plataforma que seleccionó en Administrador de configuración. Si dejó la configuración predeterminada sin cambios, los archivos de controlador compilados se habrán guardado en una carpeta denominada \x64\Debug para una compilación de depuración de 64 bits.

    Vaya a la carpeta que contiene los archivos compilados para el controlador Autosync: C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug.

    La carpeta debe contener estos archivos:

    Archivo Descripción
    Echo.sys El archivo del controlador.
    Echo.inf Archivo de información (INF) que contiene información necesaria para instalar el controlador.

    Además, el archivo echoapp.exe se ha compilado y debería encontrarse aquí: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug.

    Archivo Descripción
    EchoApp.exe Un archivo de prueba ejecutable del símbolo del sistema que se comunica con el controlador echo.sys.
  2. Busque una unidad USB o configure un recurso compartido de red para copiar los archivos de controlador creados y la EchoApp de prueba desde el sistema host al sistema de destino.

En la sección siguiente, copiará el código en el sistema de destino e instalará y probará el controlador.

Instalación del ejemplo de controlador de eco en el sistema de destino

En esta sección, usará la herramienta DevCon para instalar el controlador de ejemplo de eco.

El equipo en el que se instala el controlador se denomina equipo de destino o equipo de prueba. Normalmente, este equipo es independiente del equipo en el que desarrolla y compila el paquete de controladores. El equipo donde desarrolla y compila el controlador se denomina equipo host.

El proceso de mover el paquete de controladores al equipo de destino e instalar el controlador se denomina implementación del controlador.

Antes de implementar un controlador firmado de prueba, prepare el equipo de destino habilitando la firma de pruebas. También debe buscar la herramienta DevCon en la instalación de WDK y copiarla en el sistema de destino.

Para instalar el controlador en el sistema de destino, siga los pasos siguientes.

En el sistema de destino, habilite controladores firmados de prueba:

  1. Abra Configuración de Windows.

  2. En Actualización y seguridad, seleccione Recuperación.

  3. En Inicio avanzado, seleccione Reiniciar ahora.

  4. Cuando se reinicie el equipo, seleccione Opciones de inicio. En Windows 10, seleccione Solución de problemas>Opciones avanzadas>Configuración de inicio y, a continuación, seleccione Reiniciar.

  5. Seleccione Deshabilitar aplicación de firmas del controlador pulsando la tecla F7.

  6. Reinicie el equipo de destino.

En el sistema host, vaya a la carpeta Herramientas de la instalación de WDK y busque la herramienta DevCon. Por ejemplo, busque en la carpeta siguiente: C:\Archivos de programa (x86)\Windows Kits\10\Tools\x64\devcon.exe.

Cree una carpeta en el destino para el paquete de controladores compilado, por ejemplo, C:\EchoDriver. Copie devcon.exe en el sistema de destino. Busque el certificado .cer en el sistema host. Está en la misma carpeta del equipo host de la carpeta que contiene los archivos de controlador compilado. Copie todos los archivos del controlador compilado descrito anteriormente en el equipo host y guárdelos en la misma carpeta que creó en el equipo de destino.

En el equipo de destino, seleccione y mantenga pulsado (o haga clic con el botón derecho) el archivo de certificado, seleccione Instalar y, a continuación, siga las indicaciones para instalar el certificado de prueba.

Si necesita instrucciones más detalladas para configurar el equipo de destino, consulte Preparación de un equipo para la implementación manual de controladores.

En las instrucciones siguientes se muestra cómo instalar y probar el controlador de ejemplo. Esta es la sintaxis general de la herramienta devcon que se usa para instalar el controlador:

devcon install <INF file> <hardware ID>

El archivo INF necesario para instalar este controlador es echo.inf. El archivo INF contiene el identificador de hardware para instalar echo.sys. Para el ejemplo de eco, el identificador de hardware es root\ECHO.

En el equipo de destino, abra una ventana de símbolo del sistema como administrador. Vaya a la carpeta del paquete de controladores y escriba el siguiente comando:

devcon install echo.inf root\ECHO

Si recibe un mensaje de error sobre devcon que no se reconoce, intente agregar la ruta de acceso a la herramienta devcon. Por ejemplo, si lo copió en una carpeta denominada C:\Tools, pruebe a usar el siguiente comando:

c:\tools\devcon install echo.inf root\ECHO

Aparecerá un cuadro de diálogo que indica que el controlador de prueba es un controlador sin firmar. Seleccione Instalar este controlador de todos modos para continuar.

Captura de pantalla de advertencia de seguridad de Windows que indica que Windows no puede comprobar el publicador del software del controlador.

Sugerencia

 Si tiene algún problema con la instalación, consulte el archivo siguiente para obtener más información. %windir%\inf\setupapi.dev.log

Después de instalar correctamente el controlador de ejemplo, ya está listo para probarlo.

En el equipo de destino, en una ventana del símbolo del sistema, escriba devmgmt para abrir Administrador de dispositivos. En Administrador de dispositivos, en el menú Ver, elija Dispositivos por tipo. En el árbol de dispositivos, busque Controlador de eco de WDF de ejemplo en el nodo Dispositivo de ejemplo.

Captura de pantalla del árbol de Administrador de dispositivos que resalta el controlador de eco WDF de ejemplo.

Escriba echoapp para iniciar la aplicación de eco de prueba para confirmar que el controlador es funcional.

C:\Samples\KMDF_Echo_Sample> echoapp
DevicePath: \\?\root#sample#0005#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a}
Opened device successfully
512 Pattern Bytes Written successfully
512 Pattern Bytes Read successfully
Pattern Verified successfully
30720 Pattern Bytes Written successfully
30720 Pattern Bytes Read successfully
Pattern Verified successfully

Uso de WinDbg para mostrar información sobre el controlador

En esta sección, establecerá la ruta de acceso del símbolo y usará comandos del depurador de kernel para mostrar información sobre el controlador de ejemplo de eco de KMDF.

Para ver información sobre el controlador:

  1. En el sistema host, si cerró el depurador, ábralo de nuevo mediante el siguiente comando en la ventana del símbolo del sistema del administrador.

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Use Ctrl+Interrumpir (Bloq Despl) para irrumpir en el código que se ejecuta en el sistema de destino.

  3. Para establecer la ruta de acceso de símbolos al servidor de símbolos de Microsoft en el entorno de WinDbg, use el comando .symfix.

    0: kd> .symfix
    
  4. Para agregar la ubicación del símbolo local para usar los símbolos locales, agregue la ruta de acceso mediante .sympath+ y, a continuación, .reload /f.

    0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf
    0: kd> .reload /f
    

    El comando .reload con la opción de aplicación /f elimina toda la información de símbolos del módulo especificado y vuelve a cargar los símbolos. En algunos casos, este comando también recarga o descarga el propio módulo.

Para usar todas las funciones avanzadas que proporciona WinDbg, debe cargar los símbolos adecuados. Si no tiene símbolos configurados correctamente, recibirá mensajes que indican que los símbolos no están disponibles al intentar usar la funcionalidad que depende de los símbolos.

0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type “.hh dbgerr005” for details.

Hay muchos enfoques que se pueden usar para trabajar con símbolos. En muchas situaciones, puede configurar el equipo para acceder a símbolos desde un servidor de símbolos que Microsoft proporciona cuando son necesarios. En este laboratorio se usa ese enfoque. Si los símbolos del entorno están en una ubicación diferente, modifique los pasos para usar esa ubicación. Para obtener más información, consulte Ruta de símbolos para la depuración de Windows.

Para realizar la depuración de origen, debe crear una versión comprobada (depuración) de los archivos binarios. El compilador crea archivos de símbolos (archivos .pdb). Estos archivos de símbolos muestran al depurador cómo las instrucciones binarias corresponden a las líneas de origen. Los propios archivos de origen también deben ser accesibles para el depurador.

Los archivos de símbolos no contienen el texto del código fuente. Para la depuración, es mejor si el enlazador no optimiza el código. La depuración de origen y el acceso a las variables locales son más difíciles y, a veces, casi imposibles, si el código se ha optimizado. Si tiene problemas para ver variables locales o líneas de origen, establezca las siguientes opciones de compilación:

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. Escriba el siguiente comando en el área de comandos del depurador para mostrar información sobre el controlador de eco:

    0: kd> lm m echo* v
    Browse full module list
    start             end                 module name
    fffff801`4ae80000 fffff801`4ae89000   ECHO       (private pdb symbols)  C:\Samples\KMDF_ECHO_SAMPLE\echo.pdb
        Loaded symbol image file: ECHO.sys
        Image path: \SystemRoot\system32\DRIVERS\ECHO.sys
        Image name: ECHO.sys
    ...  
    

    Para obtener más información, consulte lm.

  2. Dado que en este laboratorio se estableció prefer_dml anteriormente, algunos elementos de la salida son vínculos activos que puede seleccionar. Seleccione el vínculo Examinar todos los símbolos globales de la salida de depuración para mostrar información sobre los símbolos de elementos que comienzan con la letra "a".

    0: kd> x /D Echo!a*
    
  3. El ejemplo de eco no contiene ningún símbolo que comience con la letra "a", por lo que escriba x ECHO!Echo* para mostrar información sobre todos los símbolos asociados con el controlador de eco que comienzan por "Echo".

    0: kd> x ECHO!Echo*
    fffff801`0bf95690 ECHO!EchoEvtIoQueueContextDestroy (void *)
    fffff801`0bf95000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    fffff801`0bf95ac0 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    fffff801`0bf9b120 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    ...
    

    Para obtener más información, consulte x (Examinar símbolos).

  4. La extensión !lmi muestra información detallada sobre un módulo. Escriba !lmi echo. La salida debe ser similar al texto que se muestra en este ejemplo:

    0: kd> !lmi echo
    Loaded Module Info: [echo] 
             Module: ECHO
       Base Address: fffff8010bf94000
         Image Name: ECHO.sys
    … 
    
  5. Use la extensión !dh para mostrar información de encabezado como se muestra en este ejemplo:

    0: kd> !dh echo
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
         14C machine (i386)
           6 number of sections
    54AD8A42 time date stamp Wed Jan 07 11:34:26 2015
    ...
    
  6. Escriba lo siguiente para cambiar la máscara de bits de depuración predeterminada para que todos los mensajes de depuración del sistema de destino se muestren en el depurador:

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    

    Algunos controladores muestran información adicional cuando se usa la máscara de 0xFFFFFFFF. Establezca la máscara en 0x00000000 si desea reducir la cantidad de información que se muestra.

    0: kd> ed nt!Kd_DEFAULT_MASK 0x00000000
    

    Use el comando dd para confirmar que la máscara está establecida para mostrar todos los mensajes del depurador.

    0: kd> dd nt!kd_DEFAULT_MASK 
    fffff802`bb4057c0  ffffffff 00000000 00000000 00000000
    fffff802`bb4057d0  00000000 00000000 00000000 00000000
    fffff802`bb4057e0  00000001 00000000 00000000 00000000
    fffff802`bb4057f0  00000000 00000000 00000000 00000000
    fffff802`bb405800  00000000 00000000 00000000 00000000
    fffff802`bb405810  00000000 00000000 00000000 00000000
    fffff802`bb405820  00000000 00000000 00000000 00000000
    fffff802`bb405830  00000000 00000000 00000000 00000000
    

Visualización de la información del árbol de dispositivos Plug and Play

En esta sección, visualizará información sobre el controlador de dispositivo de ejemplo de eco y dónde reside en el árbol de dispositivos Plug and Play.

La información sobre el controlador de dispositivo en el árbol de dispositivos Plug and Play puede resultar útil para solucionar problemas. Por ejemplo, si un controlador de dispositivo no reside en el árbol de dispositivos, puede haber un problema con la instalación del controlador de dispositivo.

Para obtener más información sobre la extensión de depuración del nodo de dispositivo, consulte !devnode.

  1. En el sistema host, para ver todos los nodos de dispositivo en el árbol de dispositivos Plug and Play, escriba el comando !devnode 0 1.

    0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30)
    DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0…
    …
    
  2. Use Ctrl+F para buscar en la salida que se genera el nombre del controlador de dispositivo, echo.

    Captura de pantalla del cuadro de diálogo Buscar en WinDbg con el término de búsqueda

  3. Se debería cargar el controlador del dispositivo de eco. Use el comando !devnode 0 1 echo para mostrar información de Plug and Play asociada al controlador del dispositivo de eco, como se muestra en este ejemplo:

    0: Kd> !devnode 0 1 echo
    Dumping IopRootDeviceNode (= 0xffffe0007b725d30)
    DevNode 0xffffe0007b71a630 for PDO 0xffffe0007b71a960
      InstancePath is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    …
    
  4. La salida mostrada en el comando anterior incluye el PDO asociado a la instancia en ejecución del controlador, en este ejemplo, 0xffffe0007b71a960. Escriba el comando !devobj <PDO address> para mostrar información de Plug and Play asociada al controlador de dispositivo de eco. Use la dirección PDO que !devnode muestra en el equipo, no la que se muestra aquí.

    0: kd> !devobj 0xffffe0007b71a960
    Device object (ffffe0007b71a960) is for:
     0000000e \Driver\PnpManager DriverObject ffffe0007b727e60
    Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
    Dacl ffffc102c9b36031 DevExt 00000000 DevObjExt ffffe0007b71aab0 DevNode ffffe0007b71a630 
    ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe000801fee20 \Driver\ECHO
    Device queue is not busy.
    
  5. La salida mostrada en el comando !devnode 0 1 incluye la dirección PDO asociada a la instancia en ejecución del controlador, en este ejemplo, es 0xffffe0007b71a960. Escriba el comando !devstack <PDO address> para mostrar información de Plug and Play asociada al controlador de dispositivo. Use la dirección PDO que !devnode muestra en el equipo, no la que se muestra en este ejemplo.

    0: kd> !devstack 0xffffe0007b71a960
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe000801fee20  \Driver\ECHO       ffffe0007f72eff0  
    > ffffe0007b71a960  \Driver\PnpManager 00000000  0000000e
    !DevNode ffffe0007b71a630 :
      DeviceInst is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
    

La salida muestra que tiene una pila de controladores de dispositivo muy sencilla. El controlador de eco es un elemento secundario del nodo PnPManager. PnPManager es un nodo raíz.

\Driver\ECHO
\Driver\PnpManager

En este diagrama se muestra un árbol de nodos de dispositivo más complejo.

Diagrama que ilustra un árbol de nodos de dispositivo que consta de aproximadamente 20 nodos.

Para obtener más información sobre las pilas de controladores más complejas, consulte Pilas de controladores y Nodos de dispositivo y pilas de dispositivos.

Trabajo con puntos de interrupción y código fuente

En esta sección, establecerá puntos de interrupción y código fuente en modo kernel de un solo paso.

Para poder recorrer el código y comprobar los valores de las variables en tiempo real, habilite los puntos de interrupción y establezca una ruta de acceso al código fuente.

Los puntos de interrupción detienen la ejecución de código en una línea de código determinada. Avance en el código desde ese punto para depurar esa sección específica del código.

Para establecer un punto de interrupción mediante un comando de depuración, use uno de los siguientes comandos b.

Comando Descripción
bp Establece un punto de interrupción que estará activo hasta que se descargue el módulo en el que se encuentra.
bu Establece un punto de interrupción que no se resuelve cuando el módulo se descarga y se vuelve a habilitar cuando el módulo se vuelve a cargar.
bm Establece un punto de interrupción para un símbolo. Este comando usa bu o bp adecuadamente y permite usar caracteres comodín (*) para establecer puntos de interrupción en todos los símbolos que coincidan, como todos los métodos de una clase.

Para obtener más información, consulte Depuración de código fuente en WinDbg.

  1. En el sistema host, use la interfaz de usuario de WinDbg para confirmar que Depuración>Modo de origen está habilitado en la sesión actual de WinDbg.

  2. Escriba el comando siguiente para añadir la ubicación de su código local a la ruta de origen:

    .srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  3. Escriba el comando siguiente para añadir la ubicación de símbolo local a la ruta de símbolos:

    .sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  4. Use el comando x para examinar los símbolos asociados al controlador de eco para determinar el nombre de la función que se va a usar para el punto de interrupción. Puede usar un carácter comodín o Ctrl+F para buscar el nombre de la función DeviceAdd.

    0: kd> x ECHO!EchoEvt*
    8b4c7490          ECHO!EchoEvtIoQueueContextDestroy (void *)
    8b4c7000          ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    8b4c7820          ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    8b4cb0e0          ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    8b4c75d0          ECHO!EchoEvtIoWrite (struct WDFQUEUE__ *, struct WDFREQUEST__ *, unsigned int)
    8b4cb170          ECHO!EchoEvtDeviceAdd (struct WDFDRIVER__ *, struct 
    …
    

    La salida muestra que el método DeviceAdd para el controlador de eco es ECHO!EchoEvtDeviceAdd.

    También puede revisar el código fuente para buscar el nombre de la función para el punto de interrupción.

  5. Establezca el punto de interrupción con el comando bm utilizando el nombre del controlador, seguido del nombre de la función, por ejemplo, AddDevice, donde desea establecer el punto de interrupción, separados por un signo de exclamación. En este laboratorio se usa AddDevice para ver el controlador que se carga.

    0: kd> bm ECHO!EchoEvtDeviceAdd
      1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
    

    Puede usar una sintaxis diferente junto con la configuración de variables como <module>!<symbol>, <class>::<method>'<file.cpp>:<line number>' u omitir un número de veces <condition> <#>. Para obtener más información, consulte Puntos de interrupción condicionales en WinDbg y otros depuradores de Windows.

  6. Enumere los puntos de interrupción actuales para confirmar que el punto de interrupción se estableció escribiendo el comando bl:

    0: kd> bl
    1 e fffff801`0bf9b1c0     0001 (0001) ECHO!EchoEvtDeviceAdd
    

    La "e" de la salida que se muestra aquí indica que el número de punto de interrupción 1 está habilitado para activarse.

  7. Reinicie la ejecución de código en el sistema de destino escribiendo el comando g (ir).

  8. En el sistema de destino, en Windows, abra Administrador de dispositivos mediante el icono o escribiendo mmc devmgmt.msc. En Administrador de dispositivos, expanda el nodo Ejemplos.

  9. Seleccione y mantenga pulsada (o haga clic con el botón derecho) la entrada del controlador de eco de KMDF y seleccione Deshabilitar en el menú.

  10. Vuelva a seleccionar y mantenga pulsada (o haga clic con el botón derecho) la entrada del controlador de eco de KMDF y seleccione Habilitar en el menú.

  11. En el sistema host, cuando el controlador está habilitado, el punto de interrupción de depuración AddDevice debería activarse. La ejecución del código de controlador en el sistema de destino debería detenerse. Cuando se alcanza el punto de interrupción, la ejecución debería detener al principio de la rutina AddDevice. La salida del comando de depuración muestra Breakpoint 1 hit.

    Captura de pantalla de WinDbg en la que se muestran las ventanas de comandos y variables locales de código de ejemplo.

  12. Para recorrer la línea de código por línea, escriba el comando p o pulse F10 hasta llegar al siguiente final de la rutina AddDevice. El carácter de llave (}) está resaltado como se muestra.

    Captura de pantalla de la ventana de código con el carácter de llave resaltado al principio de la rutina AddDevice.

En la sección siguiente, examine el estado de las variables después de ejecutar el código DeviceAdd.

Puede modificar los puntos de interrupción existentes mediante los siguientes comandos:

Comando Descripción
bl Enumera los puntos de interrupción.
bc Borra un punto de interrupción de la lista. Use bc * para borrar todos los puntos de interrupción.
bd Deshabilita un punto de interrupción. Use bd * para deshabilitar todos los puntos de interrupción.
be Habilita un punto de interrupción. Use be * para habilitar todos los puntos de interrupción.

También puede modificar puntos de interrupción en la interfaz de usuario de WinDbg.

También puede establecer puntos de interrupción que se activan cuando se accede a una ubicación de memoria. Use el comando ba (interrumpir el acceso), con la siguiente sintaxis:

ba <access> <size> <address> {options}
Opción Descripción
e ejecutar: cuando la CPU captura una instrucción de la dirección
r leer/escribir: cuando la CPU lee o escribe en la dirección
w escribir: cuando la CPU escribe en la dirección

Solo puede establecer cuatro puntos de interrupción de datos en un momento dado. Es necesario asegurarse de que está alineando los datos correctamente para desencadenar el punto de interrupción. Las palabras deben terminar en direcciones divisibles en 2, las palabras dwords deben ser divisibles por 4 y las palabras cuádruples por 0 o 8.

Por ejemplo, para establecer un punto de interrupción de lectura/escritura en una dirección de memoria específica, podría usar un comando como el de este ejemplo.

ba r 4 0x0003f7bf0

Pude usar los comandos siguientes para recorrer el código con los métodos abreviados del teclado asociados que se muestran entre paréntesis.

  • Interrumpir (Ctrl+Interrumpir). Este comando interrumpe un sistema mientras el sistema se esté ejecutando y esté en comunicación con WinDbg. La secuencia del depurador de kernel es Ctrl+C.
  • Ejecutar hasta el cursor (F7 o Ctrl+F10). Coloque el cursor en una ventana de origen o desensamblado donde quiera que se interrumpa la ejecución y pulse F7. La ejecución del código se ejecuta hasta ese punto. Si el flujo de ejecución de código no llega al punto indicado por el cursor, WinDbg no se interrumpirá. Esta situación puede ocurrir si no se ejecuta una instrucción IF.
  • Ejecutar (F5). Se ejecuta hasta que se encuentra un punto de interrupción o se produce un evento, como una comprobación de errores.
  • Paso a paso por procedimientos (F10). Este comando hace que la ejecución del código continúe con una instrucción o una instrucción a la vez. Si se encuentra una llamada, la ejecución del código pasa por la llamada sin escribir la rutina llamada. Si el lenguaje de programación es C o C++ y WinDbg está en modo de origen, el modo de origen se puede activar o desactivar mediante Depuración>Modo de origen.
  • Paso a paso por instrucciones (F11). Este comando es similar al paso a paso por procedimientos, excepto que la ejecución de una llamada entra en la rutina llamada.
  • Paso a paso para salir (Mayús+F11). Este comando hace que la ejecución se ejecute y salga de la rutina actual o del lugar actual en la pila de llamadas. Este comando es útil si ha visto suficiente de la rutina.

Para obtener más información, consulte Depuración de código fuente en WinDbg.

Visualización de variables y pilas de llamadas

En esta sección, visualizará información sobre las variables y las pilas de llamadas.

En este laboratorio se supone que se ha detenido en la rutina AddDevice mediante el proceso descrito anteriormente. Para ver la salida que se muestra aquí, repita los pasos descritos anteriormente, si es necesario.

En el sistema host, para mostrar variables, use la opción de menú Ver>Local para mostrar variables locales.

Captura de pantalla de WinDbg que muestra la ventana de variables locales.

Para buscar la ubicación de una dirección de variables global, escriba ? <variable name>.

  • Paso a paso para salir (Mayús+F11): este comando hace que la ejecución se ejecute y salga de la rutina actual (lugar actual en la pila de llamadas). Esto es útil si ha visto suficiente de la rutina.

Para obtener más información, consulte Depuración de código fuente en WinDbg (clásico) en la documentación de referencia de depuración.

Sección 8: Visualización de variables y pilas de llamadas

En la sección 8, visualizará información sobre las variables y las pilas de llamadas.

En este laboratorio se supone que se ha detenido en la rutina AddDevice mediante el proceso descrito anteriormente. Para ver la salida que se muestra aquí, repita los pasos descritos anteriormente, si es necesario.

<- En el sistema host

Visualización de variables

Use la opción de menú Ver>Local para visualizar variables locales.

Captura de pantalla de WinDbg que muestra la ventana de variables locales.

Variables globales

Para encontrar la ubicación de una dirección de variable global, escriba ? <nombre de variable>..

Variables locales

Puede mostrar los nombres y valores de todas las variables locales de un marco determinado escribiendo el comando dv. Para mostrar los nombres y valores de todas las variables locales de un marco específico, escriba el comando dv:

0: kd> dv
         Driver = 0x00001fff`7ff9c838
     DeviceInit = 0xffffd001`51978190
         status = 0n0

La pila de llamadas es la cadena de llamadas a la función que han llevado a la ubicación actual del contador del programa. La función superior de la pila de llamadas es la función actual y la función siguiente es la función que llamó a la función actual, etc.

Para mostrar la pila de llamadas, use los comandos k*.

Comando Descripción
kb Muestra la pila y los tres primeros parámetros.
kp Muestra las pilas y la lista completa de parámetros.
kn Permite ver la pila con la información de marco junto a ella.
  1. En el sistema host, si desea mantener la pila de llamadas disponible, seleccione Ver>Pila de llamadas para verla. Seleccione las columnas de la parte superior de la ventana para alternar la presentación de información adicional.

    Captura de pantalla de WinDbg que muestra la ventana Pilas de llamadas.

  2. Use el comando kn para mostrar la pila de llamadas mientras depura el código del adaptador de ejemplo en un estado de interrupción.

    3: kd> kn
    # Child-SP          RetAddr           Call Site
    00 ffffd001`51978110 fffff801`0942f55b ECHO!EchoEvtDeviceAdd+0x66 [c:\Samples\kmdf echo sample\c++\driver\autosync\driver.c @ 138]
    01 (Inline Function) --------`-------- Wdf01000!FxDriverDeviceAdd::Invoke+0x30 [d:\wbrtm\minkernel\wdf\framework\shared\inc\private\common\fxdrivercallbacks.hpp @ 61]
    02 ffffd001`51978150 fffff801`eed8097d Wdf01000!FxDriver::AddDevice+0xab [d:\wbrtm\minkernel\wdf\framework\shared\core\km\fxdriverkm.cpp @ 72]
    03 ffffd001`51978570 fffff801`ef129423 nt!PpvUtilCallAddDevice+0x35 [d:\9142\minkernel\ntos\io\pnpmgr\verifier.c @ 104]
    04 ffffd001`519785b0 fffff801`ef0c4112 nt!PnpCallAddDevice+0x63 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 7397]
    05 ffffd001`51978630 fffff801`ef0c344f nt!PipCallDriverAddDevice+0x6e2 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 3390]
    ...
    

La pila de llamadas muestra que el kernel (nt) llamó al código Plug and Play (PnP) que llamó al código marco del controlador (WDF) que posteriormente llamó a la función DeviceAdd del controlador de eco.

Visualización de procesos y subprocesos

En esta sección, visualizará información sobre los procesos y subprocesos que se ejecutan en modo kernel.

Procesos

Puede mostrar o establecer información del proceso mediante la extensión del depurador !process. Establezca un punto de interrupción para examinar el proceso que se usa cuando se reproduce un sonido.

  1. En el sistema host, escriba el comando dv para examinar las variables de configuración regional asociadas a la rutina EchoEvtIo:

    0: kd> dv ECHO!EchoEvtIo*
    ECHO!EchoEvtIoQueueContextDestroy
    ECHO!EchoEvtIoWrite
    ECHO!EchoEvtIoRead         
    
  2. Borre los puntos de interrupción anteriores mediante bc *:

    0: kd> bc *  
    
  3. Establezca un punto de interrupción de símbolos en las rutinas EchoEvtIo mediante el comando siguiente:

    0: kd> bm ECHO!EchoEvtIo*
      2: aade5490          @!”ECHO!EchoEvtIoQueueContextDestroy”
      3: aade55d0          @!”ECHO!EchoEvtIoWrite”
      4: aade54c0          @!”ECHO!EchoEvtIoRead”
    
  4. Enumere los puntos de interrupción para confirmar que el punto de interrupción está establecido correctamente:

    0: kd> bl
    1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197]    0001 (0001) ECHO!EchoEvtIoQueueContextDestroy
    ...
    
  5. Escriba g para reiniciar la ejecución del código:

    0: kd> g
    
  6. En el sistema de destino, ejecute el programa de prueba de controladores EchoApp.exe en el sistema de destino.

  7. En el sistema host, cuando se ejecuta la aplicación de prueba, se llama a la rutina de E/S en el controlador. Esta llamada hace que se active el punto de interrupción y se detenga la ejecución del código del controlador en el sistema de destino.

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. Use el comando !process para mostrar el proceso actual implicado en la ejecución de echoapp.exe:

    0: kd> !process
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 03c4    Peb: 7ff7cfec4000  ParentCid: 0f34
        DirBase: 1efd1b000  ObjectTable: ffffc001d77978c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000802c79f0 Vads 30 Clone 0 Private 135. Modified 5. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf270050
        ElapsedTime                       00:00:00.052
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (682, 50, 345) (2728KB, 200KB, 1380KB)
        PeakWorkingSetSize                652
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    688
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe00080e32080  Cid 03c4.0ec0  Teb: 00007ff7cfece000 Win32Thread: 0000000000000000 RUNNING on processor 1
    

    La salida muestra que el proceso está asociado al subproceso de echoapp.exe, que se estaba ejecutando cuando se alcanzó el punto de interrupción en el evento de escritura del controlador. Para obtener más información, consulte !process.

  9. Use !process 0 0 para visualizar información de resumen para todos los procesos. En la salida, use Ctrl+F para buscar la misma dirección de proceso para el proceso asociado a la imagen de echoapp.exe. En el ejemplo, la dirección del proceso es ffffe0007e6a7780.

    ...
    
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
        DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
        Image: echoapp.exe
    
    ...
    
  10. Registre el identificador de proceso asociado a echoapp.exe para usarlo más adelante en este laboratorio. También puede usar Ctrl+C para copiar la dirección en el búfer de copia para su uso posterior.

    _____________________________________________________(dirección de proceso de echoapp.exe)

  11. Escriba g como sea necesario en el depurador para ejecutar el código hasta que echoapp.exe termine de ejecutarse. Alcanza el punto de interrupción en el evento de lectura y escritura muchas veces. Cuando finalice echoapp.exe, interrumpa en el depurador pulsando Ctrl+Bloq Despl (Ctrl+Interrumpir).

  12. Use el comando !process para confirmar que está ejecutando un proceso diferente. En la salida que se muestra aquí, el proceso con el valor de Imagen de System es diferente del valor de Imagen de Echo.

    1: kd> !process
    PROCESS ffffe0007b65d900
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001ab000  ObjectTable: ffffc001c9a03000  HandleCount: 786.
        Image: System
        VadRoot ffffe0007ce45930 Vads 14 Clone 0 Private 22. Modified 131605. Locked 64.
        DeviceMap ffffc001c9a0c220
        Token                             ffffc001c9a05530
        ElapsedTime                       21:31:02.516
    ...
    

    La salida muestra que se estaba ejecutando un proceso del sistema ffffe0007b65d900 cuando se detuvo el sistema operativo.

  13. Use el comando !process para intentar examinar el identificador de proceso asociado a echoapp.exe que registró anteriormente. Proporcione la dirección del proceso de echoapp.exe que registró anteriormente, en lugar de la dirección del proceso de ejemplo que se muestra en este ejemplo.

    0: kd> !process ffffe0007e6a7780
    TYPE mismatch for process object at 82a9acc0
    

    El objeto de proceso ya no está disponible porque el proceso de echoapp.exe ya no se está ejecutando.

Subprocesos

Los comandos para ver y establecer subprocesos son similares a los comandos para los procesos. Use el comando !thread para ver los subprocesos. Use .thread para establecer los subprocesos actuales.

  1. En el sistema host, escriba g en el depurador para reiniciar la ejecución de código en el sistema de destino.

  2. En el sistema de destino, ejecute el programa de prueba de controladores EchoApp.exe.

  3. En el sistema host, se alcanza el punto de interrupción y se detiene la ejecución del código.

    Breakpoint 4 hit
    ECHO!EchoEvtIoRead:
    aade54c0 55              push    ebp
    
  4. Para ver los subprocesos que se están ejecutando, escriba !thread. Debe mostrarse información similar a la del siguiente ejemplo:

    0: kd>  !thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    ...
    

    Anote el nombre de la imagen de echoapp.exe. Esto indica que está viendo el subproceso asociado a la aplicación de prueba.

  5. Use el comando !process para determinar si este subproceso es el único subproceso que se ejecuta en el proceso asociado a echoapp.exe. El número de subproceso del subproceso en ejecución en el proceso es el mismo subproceso en ejecución que mostró el comando !thread.

    0: kd> !process
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    
  6. Use el comando !process 0 0 para buscar la dirección del proceso de dos procesos relacionados y registre esa dirección de proceso aquí.

    Cmd.exe: ____________________________________________________________

    EchoApp.exe: _______________________________________________________

    0: kd> !process 0 0 
    
    …
    
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
    …
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
    …
    

    También puede usar !process 0 17 para mostrar información detallada sobre cada proceso. La salida de este comando puede ser larga. Se pueden realizar búsquedas en la salida con Ctrl+F.

  7. Use el comando !process para enumerar la información del proceso para ambos procesos que ejecutan el equipo. Proporcione la dirección del proceso de la salida !process 0 0, no la dirección que se muestra en este ejemplo.

    Esta salida de ejemplo es para el identificador de proceso de cmd.exe que se registró anteriormente. El nombre de la imagen de este identificador de proceso es cmd.exe.

    0: kd>  !process ffffe0007bbde900
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
        VadRoot ffffe0007bb8e7b0 Vads 25 Clone 0 Private 117. Modified 20. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001d8c48050
        ElapsedTime                       21:33:05.840
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         24656
        QuotaPoolUsage[NonPagedPool]      3184
        Working Set Sizes (now,min,max)  (261, 50, 345) (1044KB, 200KB, 1380KB)
        PeakWorkingSetSize                616
        VirtualSize                       2097164 Mb
        PeakVirtualSize                   2097165 Mb
        PageFaultCount                    823
        MemoryPriority                    FOREGROUND
        BasePriority                      8
        CommitCharge                      381
    
            THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
                ffffe0008096c900  ProcessObject
            Not impersonating
    ...
    

    Esta salida de ejemplo es para el identificador de proceso de echoapp.exe que se registró anteriormente.

    0: kd>  !process ffffe0008096c900
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
            IRP List:
                ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
            Not impersonating
    ...
    
  8. Registre aquí la primera dirección del subproceso asociada a los dos procesos.

    Cmd.exe: ____________________________________________________

    EchoApp.exe: _________________________________________________

  9. Use el comando !Thread para mostrar información sobre el subproceso actual.

    0: kd>  !Thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    Attached Process          N/A            Image:         N/A
    ...
    

    Como se esperaba, el subproceso actual es el subproceso asociado a echoapp.exe y está en estado de ejecución.

  10. Use el comando !Thread para mostrar información sobre el subproceso asociado al proceso cmd.exe. Proporcione la dirección del subproceso que registró anteriormente.

    0: kd> !Thread ffffe0007cf34880
    THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
        ffffe0008096c900  ProcessObject
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0007bbde900       Image:         cmd.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      4134621        Ticks: 0
    Context Switch Count      4056           IdealProcessor: 0             
    UserTime                  00:00:00.000
    KernelTime                00:00:01.421
    Win32 Start Address 0x00007ff72e9d6e20
    Stack Init ffffd0015551dc90 Current ffffd0015551d760
    Base ffffd0015551e000 Limit ffffd00155518000 Call 0
    Priority 14 BasePriority 8 UnusualBoost 3 ForegroundBoost 2 IoPriority 2 PagePriority 5
    Child-SP          RetAddr           : Args to Child                                                           : Call Site
    ffffd001`5551d7a0 fffff801`eed184fe : fffff801`eef81180 ffffe000`7cf34880 00000000`fffffffe 00000000`fffffffe : nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    ffffd001`5551d8e0 fffff801`eed17f79 : ffff03a5`ca56a3c8 000000de`b6a6e990 000000de`b6a6e990 00007ff7`d00df000 : nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    ffffd001`5551d980 fffff801`eecea340 : ffffd001`5551da18 00000000`00000000 00000000`00000000 00000000`00000388 : nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    ...
    

    Este subproceso está asociado a cmd.exe y está en estado de espera.

  11. Proporcione la dirección del subproceso en espera CMD.exe para cambiar el contexto a ese subproceso en espera.

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. Use el comando k para ver la pila de llamadas asociada al subproceso en espera.

    0: kd> k
      *** Stack trace for last set context - .thread/.cxr resets it
    # Child-SP          RetAddr           Call Site
    00 ffffd001`5551d7a0 fffff801`eed184fe nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    01 ffffd001`5551d8e0 fffff801`eed17f79 nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    02 ffffd001`5551d980 fffff801`eecea340 nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    03 ffffd001`5551da00 fffff801`ef02e642 nt!KeWaitForSingleObject+0x2c0 [d:\9142\minkernel\ntos\ke\wait.c @ 683]
    ...
    

    Los elementos de la pila de llamadas como KiCommitThreadWait indican que este subproceso no se está ejecutando como se esperaba.

Para obtener más información sobre los procesos y subprocesos, consulte las referencias siguientes:

IRQL, registros y finalización de la sesión de WinDbg

En esta sección, visualizará el nivel de solicitud de interrupción (IRQL) y el contenido de los registros.

Visualización del IRQL guardado

IRQL se usa para administrar la prioridad del mantenimiento de interrupciones. Cada procesador tiene una configuración de IRQL que los subprocesos pueden aumentar o reducir. Las interrupciones que se producen en la configuración IRQL del procesador o por debajo de esta se enmascaran y no interferirán con la operación actual. Las interrupciones que se producen por encima de la configuración de IRQL del procesador tienen prioridad sobre la operación actual.

En el sistema host, la extensión !irql muestra el IRQL en el procesador actual del equipo de destino antes de la interrupción del depurador. Cuando el equipo de destino irrumpe en el depurador, el IRQL cambia, pero se guarda el IRQL que estaba vigente justo antes de la irrupción del depurador y se muestra mediante !irql.

0: kd> !irql
Debugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)

Visualización de los registros

En el sistema host, visualice el contenido de los registros del subproceso actual en el procesador actual mediante el comando r (Registros).

0: kd> r
rax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001
rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0
rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620
 r8=000000000000003e  r9=ffffe00167a4a000 r10=000000000000001e
r11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0
r14=0000000000000001 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
nt!DbgBreakPointWithStatus:
fffff803`bb757020 cc              int     3

Como alternativa, puede mostrar el contenido de los registros seleccionando Ver>Registros. Para obtener más información, consulte r (Registros).

La visualización del contenido de los registros puede resultar útil al recorrer paso a paso la ejecución del código del lenguaje de ensamblado y en otros escenarios. Para obtener más información sobre el desensamblado del lenguaje de ensamblado, consulte Desensamblado anotado x86 y Desensamblado anotado x64.

Para obtener información sobre el contenido del registro, consulte Arquitectura x86 y Arquitectura x64.

Finalización de la sesión de WinDbg

Si desea salir del depurador conectado, pero quiere trabajar en el destino, borre los puntos de interrupción mediante bc *, de modo que el equipo de destino no intente conectarse al depurador del equipo host. A continuación, use el comando g para permitir que el equipo de destino vuelva a ejecutarse.

Para finalizar la sesión de depuración, en el sistema host, interrumpa en el depurador y escriba el comando qd (Salir y desasociar) o seleccione Detener depuración en el menú.

0: kd> qd

Para obtener más información, consulte Finalización de una sesión de depuración en WinDbg.

Recursos de depuración de Windows

Hay más información disponible sobre la depuración de Windows. Algunas de estas referencias utilizan versiones anteriores de Windows, como Windows Vista, en sus ejemplos, pero los conceptos tratados son aplicables a la mayoría de las versiones de Windows.

Consulte también