Partilhar via


Depurar drivers do Windows em laboratório passo a passo (modo kernel de eco)

Este laboratório apresenta o depurador do kernel WinDbg. Você usa WinDbg para depurar o código de driver de exemplo de modo kernel echo.

Objetivos do laboratório

Este laboratório inclui exercícios que introduzem as ferramentas de depuração, ensinam comandos de depuração comuns, ilustram o uso de pontos de interrupção e mostram como usar as extensões de depuração.

Neste laboratório, usa-se uma conexão de depuração do kernel ao vivo para explorar as seguintes ações:

  • Usar os comandos do depurador do Windows
  • Use comandos padrão (pilhas de chamadas, variáveis, threads, IRQL)
  • Usar Comandos Avançados de Depuração de Driver (!commands)
  • Usar símbolos
  • Definir pontos de interrupção na depuração ao vivo
  • Ver pilhas de chamadas
  • Exibir a árvore de dispositivos Plug and Play
  • Trabalhar com thread e contexto de processo

Depuração do modo de usuário e do kernel

Ao trabalhar com o depurador do Windows, você pode fazer dois tipos de depuração:

Modo de usuário - Aplicativos e subsistemas são executados no computador no modo de usuário. Os processos que são executados no modo de usuário o fazem dentro de seus próprios espaços de endereço virtual. Eles são impedidos de obter acesso direto a muitas partes do sistema, incluindo hardware do sistema, memória que não está alocada para seu uso e outras partes do sistema que podem comprometer a integridade do sistema. Como os processos executados no modo de usuário são efetivamente isolados do sistema e de outros processos do modo de usuário, eles não podem interferir nesses recursos.

Modo kernel - O sistema operacional e os programas privilegiados são executados no modo kernel. O código do modo kernel tem permissão para acessar qualquer parte do sistema. Ele não é restrito como o código do modo de usuário. Ele pode obter acesso a qualquer parte de qualquer outro processo em execução no modo de usuário ou no modo kernel. Grande parte da funcionalidade principal do sistema operacional e muitos drivers de dispositivo de hardware são executados no modo kernel.

Este exercício abrange comandos de depuração frequentemente usados durante a depuração em modo de utilizador e em modo kernel. O exercício também abrange extensões de depuração, às vezes chamadas de "bang" !commands, que são usadas para depuração em modo kernel.

Configuração do laboratório

Você precisa do seguinte hardware para concluir o laboratório:

  • Um laptop ou computador desktop (host) executando o Windows 10
  • Um segundo laptop ou computador desktop (destino) executando o Windows 10
  • Um hub de rede ou roteador e cabos de rede para conectar os dois computadores
  • Acesso à internet para baixar arquivos de símbolos

Você precisa do seguinte software para concluir o laboratório:

  • Estúdio Visual
  • Kit de Desenvolvimento de Software (SDK) do Windows para Windows 10
  • Kit de driver do Windows (WDK) para Windows 10
  • O driver de eco de exemplo para Windows 10

O laboratório tem as seguintes secções:

Conectar-se a uma sessão WinDbg de modo kernel

Nesta secção, configure a depuração de rede no computador anfitrião e no sistema de destino.

Os computadores neste laboratório precisam ser configurados para usar uma conexão de rede Ethernet para debug do kernel.

Este laboratório utiliza dois computadores. O depurador do Windows é executado no sistema host e o driver KMDF (Kernel Mode Driver Framework) de eco é executado no sistema de destino .

Use um hub ou roteador de rede e cabos de rede para conectar os dois computadores.

Diagrama ilustrando dois computadores conectados através de um hub de rede ou roteador.

Para trabalhar com aplicativos de modo kernel e usar o WinDbg, recomendamos que você use o transporte KDNET over Ethernet. Para obter informações sobre como usar o protocolo de transporte Ethernet, consulte Introdução ao WinDbg (modo kernel). Para obter mais informações sobre como configurar o computador de destino, consulte Preparação de um computador para a implantação manual de drivers e Configuração da depuração do kernel de rede KDNET automaticamente.

Configurar a depuração no modo kernel usando a Ethernet

Para habilitar a depuração em modo kernel no sistema de destino:

  1. No sistema host, abra uma janela de prompt de comando e digite ipconfig para determinar seu endereço IPv4.

    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 o endereço IP do sistema host: ______________________________________

  3. No sistema de destino, abra uma janela do Prompt de Comando e use o comando ping para confirmar a conectividade de rede entre os dois sistemas.

    ping 169.182.1.1
    

    Use o endereço IP real do sistema host que você gravou em vez de 169.182.1.1 que é mostrado na saída de exemplo.

    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
    

Ative a depuração em modo kernel no sistema de destino seguindo os passos a seguir.

Importante

Antes de usar o BCDEdit para alterar as informações de inicialização, talvez seja necessário suspender temporariamente os recursos de segurança do Windows, como BitLocker e Inicialização Segura, no computador de teste. Reative esses recursos de segurança quando o teste estiver concluído. Gerencie adequadamente o computador de teste quando os recursos de segurança estiverem desativados. A inicialização segura normalmente é desativada na UEFI. Para acessar a configuração UEFI, Use Sistema, Recuperação, Inicialização avançada. Ao reiniciar, selecione Solução de problemas, Opções avançadas, Configurações de firmware UEFI. Tenha cuidado, pois definir incorretamente as opções de UEFI ou desativar o BitLocker pode tornar o sistema inoperante.

  1. No computador de destino, abra uma janela da Linha de Comandos enquanto Administrador. Digite este comando para habilitar a depuração:

    bcdedit /set {default} DEBUG YES
    
  2. Digite este comando para habilitar a assinatura de teste:

    bcdedit /set TESTSIGNING ON 
    
  3. Digite este comando para definir o endereço IP do sistema host. Use o endereço IP do sistema host que você gravou anteriormente, não o mostrado.

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

    Advertência

    Para aumentar a segurança da conexão e diminuir o risco de solicitações aleatórias de conexão do depurador do cliente, use uma chave aleatória gerada automaticamente. Para mais informações, consulte Configuração automática da depuração do kernel de rede KDNET.

  4. Digite este comando para confirmar se os valores para dbgsettings estão definidos corretamente:

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

    Observação

    Se você receber uma mensagem do firewall e quiser usar o depurador, selecione todas as três caixas.

    Captura de ecrã da caixa de diálogo Alerta de Segurança do Windows a indicar que a Firewall do Windows bloqueou algumas funcionalidades de uma aplicação.

  5. No computador host, abra uma janela do Prompt de Comando como Administrador. Este laboratório usa a versão x64 do WinDbg.exe do Kit de Driver do Windows (WDK) que foi instalado como parte da instalação do kit do Windows. Mude para o diretório WinDbg padrão, o local padrão é mostrado abaixo.

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

    Este laboratório pressupõe que ambos os computadores executam uma versão de 64 bits do Windows no destino e no host. Se esse não for o caso, a melhor abordagem é executar a mesma de bits de ferramentas no host que o destino executa. Por exemplo, se o destino executar o Windows de 32 bits, execute uma versão de 32 bits do depurador no host. Para obter mais informações, consulte Escolhendo as ferramentas de depuração de 32 bits ou 64 bits.

  6. Abra o WinDbg com depuração de usuário remoto usando o seguinte comando. Os valores da chave e da porta correspondem aos valores definidos anteriormente usando o BCDEdit no computador de destino.

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

  8. Em um ou dois minutos, a saída de depuração deve ser exibida no sistema anfitrião.

    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
    

A janela Comando do Depurador é a principal janela de informações de depuração no WinDbg. Pode introduzir comandos do depurador e visualizar os resultados dos comandos nesta janela.

A Janela de Comando do Depurador é dividida em dois painéis. Insira comandos no painel menor, que é o painel de entrada de comando na parte inferior da janela, e exiba a saída do comando no painel maior na parte superior da janela.

No painel de entrada de comandos, use as teclas de seta para cima e seta para baixo para percorrer o histórico de comandos. Quando um comando aparece, você pode editá-lo ou pressionar Enter para executá-lo.

Comandos e técnicas de depuração no modo kernel

Nesta seção, use comandos de depuração para exibir informações sobre o sistema de destino.

Alguns comandos de depuração exibem texto usando DML (Debugger Markup Language) que você pode selecionar para coletar rapidamente mais informações.

  1. No sistema host, use Ctrl+Scroll Lock no WinDBg para interromper o código que está a executar-se no sistema de destino. Pode levar algum tempo para o sistema de destino responder.

    Tela principal no depurador mostrando a saída da janela de comando de uma conexão de kernel ao vivo.

  2. Digite o seguinte comando para ativar o DML na janela de comando do depurador:

    0: kd> .prefer_dml 1
    DML versions of commands on by default
    
  3. Você pode acessar a ajuda do comando de referência usando o comando .hh. Digite o seguinte comando para exibir a ajuda de referência de comando para .prefer_dml:

    0: kd> .hh .prefer_dml
    

    O ficheiro de ajuda do Depurador exibe a ajuda para o comando .prefer_dml.

    Captura de ecrã da aplicação de ajuda do depurador exibindo a ajuda para o comando .prefer-dml.

  4. Para exibir informações detalhadas sobre a versão do sistema de destino, digite o comando vertarget (Show Target Computer Version) na janela 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 verificar se você está trabalhando com o processo de modo kernel correto, digite o comando lm (List Loaded Modules) na janela WinDbg para exibir os módulos carregados:

    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
    ...
    

    A saída que foi omitida é indicada com "..." neste laboratório.

  6. Para solicitar informações detalhadas sobre um módulo específico, use a opção v (verbose):

    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
    

    Não há um caminho de símbolo definido, nem símbolos carregados, por isso, estão disponíveis informações limitadas no depurador.

Baixe e compile o driver de eco KMDF

Nesta seção, baixe e crie o driver de eco KMDF.

Normalmente, você estaria trabalhando com seu próprio código de driver quando você usa WinDbg. Para se familiarizar com o funcionamento do WinDbg, este laboratório utiliza o driver de exemplo "Echo" do Modelo KMDF. O código-fonte está disponível para ajudar a entender as informações exibidas no WinDbg. Este exemplo também é usado para ilustrar como se pode avançar passo a passo através do código nativo em modo kernel. Essa técnica pode ser valiosa para depurar problemas complexos de código de modo kernel.

Para baixar e criar o driver de exemplo Echo:

  1. Primeiro, descarregue e extraia o exemplo KMDF Echo do GitHub.

    O exemplo de eco KMDF está localizado na pasta geral.

    Captura de tela da página Windows-driver-samples do GitHub destacando a pasta geral e o botão zip de download.

    1. Baixe as amostras de driver em um arquivo zip: Amostras de driver

    2. Transfira o ficheiro zip para o seu disco rígido local.

    3. Selecione e segure ou clique com o botão direito do mouse no arquivo zip e selecione Extrair tudo. Especifique uma nova pasta ou navegue até uma pasta existente para armazenar os arquivos extraídos. Por exemplo, você pode especificar C:\DriverSamples\ como a nova pasta para a qual extrair os arquivos.

    4. Depois que os arquivos forem extraídos, vá para a seguinte subpasta: C:\DriverSamples\general\echo\kmdf

  2. No Microsoft Visual Studio, selecione Arquivo>Abrir>Projeto/Solução... e vá para a pasta que contém os arquivos extraídos, por exemplo, C:\DriverSamples\general\echo\kmdf. Clique duas vezes no arquivo de solução kmdfecho para abri-lo.

    No Visual Studio, localize o Gerenciador de Soluções. Se essa janela ainda não estiver aberta, selecione Gerenciador de Soluções no menu Exibir. No Gerenciador de Soluções, você pode ver uma solução que tem três projetos.

    Captura de tela do Visual Studio exibindo o arquivo device.c carregado do projeto kmdfecho.

  3. Defina a configuração e a plataforma da amostra. No Gerenciador de Soluções, selecione e segure ou clique com o botão direito do rato Solução 'kmdfecho' (3 projetos)e selecione Gestor de Configuração. Certifique-se de que a configuração e as configurações da plataforma são as mesmas para os três projetos. Por padrão, a configuração é definida como Win10 Debuge a plataforma é definida como Win64 para todos os projetos. Se você fizer alterações de configuração ou plataforma para um projeto, faça as mesmas alterações para os três projetos restantes.

  4. As amostras de driver precisam ser modificadas para usar valores que não se sobreponham com os drivers existentes. Consulte Do Código de Exemplo ao Driver de Produção - O que Alterar nos Exemplos sobre como criar um exemplo exclusivo de driver que coexistirá com os drivers reais já instalados no Windows.

  5. Defina a biblioteca de tempo de execução. Abra a página de propriedades do driver de eco e localize C/C++>Code Generation. Altere a biblioteca de execução para Debug Multithreaded (/MTd). Para obter mais informações sobre as opções de compilação, consulte /MD, /MT, /LD (Use Run-Time Library).

    Captura de tela da página de propriedades de eco no Visual Studio destacando a configuração da biblioteca de tempo de execução.

  6. Nas propriedades do driver, verifique se Assinatura de Driver>Modo de Assinatura está definido como Sinal de Teste.

    Captura de tela da página de propriedades de eco no Visual Studio destacando a configuração do modo de sinalização.

  7. No Visual Studio, selecione Build>Build Solution.

    As janelas de compilação devem exibir uma mensagem indicando que a compilação para todos os três projetos foi bem-sucedida.

Dica

Se você encontrar uma mensagem de erro de compilação, use o número de erro de compilação para determinar uma correção. Por exemplo, erro MSBuild MSB8040 descreve como trabalhar com bibliotecas de espectro atenuado.

  1. No Explorador de Ficheiros, vá para a pasta que contém os ficheiros extraídos para o exemplo. Por exemplo, vá para C:\DriverSamples\general\echo\kmdf, se essa for a pasta especificada anteriormente. Dentro dessa pasta, o local dos arquivos de driver compilados varia dependendo da configuração e das definições de plataforma selecionadas no Configuration Manager. Se você deixou as configurações padrão inalteradas, os arquivos de driver compilados serão salvos em uma pasta chamada \x64\Debug para uma compilação de depuração de 64 bits.

    Vá para a pasta que contém os arquivos criados para o driver Autosync: C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug.

    A pasta deve conter estes ficheiros:

    Ficheiro Descrição
    Echo.sys O arquivo do driver.
    Echo.inf Um arquivo de informações (INF) que contém informações necessárias para instalar o driver.

    Além disso, o arquivo echoapp.exe foi criado e deve ser localizado aqui: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug.

    Ficheiro Descrição
    EchoApp.exe Um arquivo de teste executável do prompt de comando que se comunica com o driver echo.sys.
  2. Localize um pen drive USB ou configure um compartilhamento de rede para copiar os arquivos de driver construídos e o teste EchoApp do host para o sistema de destino.

Na próxima seção, copie o código para o sistema de destino e instale e teste o driver.

Instalar o exemplo de driver de eco KMDF no sistema de destino

Nesta seção, utilize a ferramenta DevCon para instalar o driver de exemplo de eco.

O computador onde você instala o driver é chamado de computador de destino ou o computador de teste . Normalmente, este computador é separado do computador no qual você desenvolve e compila o pacote de driver. O computador onde o utilizador desenvolve e compila o driver é chamado de computador host.

O processo de mover o pacote de driver para o computador de destino e instalar o driver é chamado implantação o driver.

Antes de implantar um driver assinado de teste, prepare o computador de destino ativando a assinatura de teste. Você também precisa localizar a ferramenta DevCon na instalação do WDK e copiá-la para o sistema de destino.

Para instalar o driver no sistema de destino, execute as etapas a seguir.

No sistema de destino, ative controladores assinados de teste:

  1. Abra Configurações do Windows.

  2. No Atualização e Segurança, selecione Recuperação.

  3. Em Inicialização Avançada, selecione Reiniciar agora.

  4. Quando o computador for reiniciado, selecione Opções de inicialização. No Windows 10, selecione Solucionar problemas>opções avançadas>Configurações de inicialização e, em seguida, selecione Reiniciar.

  5. Selecione Desativar imposição de assinatura de driver pressionando a tecla F7.

  6. Reinicie o computador de destino.

No sistema host, vá para a pasta Tools na instalação do WDK e localize a ferramenta DevCon. Por exemplo, procure na seguinte pasta: C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe.

Crie uma pasta no destino para o pacote de driver compilado, por exemplo, C:\EchoDriver. Copie devcon.exe para o sistema de destino. Localize o certificado .cer no sistema host. Está na mesma pasta no computador host, na pasta que contém os arquivos de driver compilados. Copie todos os arquivos do driver construído descrito anteriormente no computador host e salve-os na mesma pasta que você criou no computador de destino.

No computador de destino, selecione e segure ou clique com o botão direito do mouse no arquivo de certificado e selecione Instalare, em seguida, siga as instruções para instalar o certificado de teste.

Se precisar de instruções mais detalhadas para configurar o computador de destino, consulte Preparando um computador para implantação manual de driver.

As instruções a seguir mostram como instalar e testar o driver de exemplo. Aqui está a sintaxe geral para a ferramenta devcon que você usa para instalar o driver:

devcon install <INF file> <hardware ID>

O arquivo INF necessário para instalar este driver é echo.inf. O ficheiro inf contém o ID de hardware para instalar o echo.sys. Para a amostra de eco, o ID de hardware é root\ECHO.

No computador de destino, abra uma janela da Linha de Comandos como Administrador. Vá para a pasta do pacote de driver e digite o seguinte comando:

devcon install echo.inf root\ECHO

Se você receber uma mensagem de erro indicando que o devcon não está a ser reconhecido, tente adicionar o caminho à ferramenta devcon. Por exemplo, se você copiou para uma pasta chamada C:\Tools, tente usar o seguinte comando:

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

É exibida uma caixa de diálogo que indica que o driver de teste é um driver não assinado. Selecione Instalar este driver mesmo assim para continuar.

Captura de tela do aviso de Segurança do Windows informando que o Windows não pode verificar o editor do software de driver.

Dica

 Se você tiver algum problema com a instalação, verifique o seguinte arquivo para obter mais informações. %windir%\inf\setupapi.dev.log

Depois de instalar com êxito o driver de exemplo, você está pronto para testá-lo.

No computador de destino, em uma janela do Prompt de Comando, digite devmgmt para abrir o Gerenciador de Dispositivos. No Gestor de Dispositivos, no menu Ver, selecione Dispositivos por tipo. Na árvore de dispositivos, localize Sample WDF Echo Driver no nó Sample Device.

Captura de tela da árvore do Gerenciador de Dispositivos destacando o driver de eco WDF de exemplo.

Digite echoapp para iniciar o aplicativo de eco de teste para confirmar se o driver está 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

Utilize o WinDbg para exibir informações sobre o driver

Nesta seção, defina o caminho do símbolo e use os comandos do depurador do kernel para exibir informações sobre o driver de exemplo de eco KMDF.

Para visualizar informações sobre o driver:

  1. No sistema host, se você fechou o depurador, abra-o novamente usando o seguinte comando na janela do prompt de comando do administrador.

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Use Ctrl+Break (Scroll Lock) para quebrar o código em execução no sistema de destino.

  3. Para definir o caminho dos símbolos para o servidor de símbolos da Microsoft no ambiente WinDbg, use o comando .symfix.

    0: kd> .symfix
    
  4. Para adicionar a localização do símbolo local e utilizar os símbolos locais, adicione o caminho usando .sympath+ e, em seguida, .reload /f.

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

    O comando .reload com a opção /f force exclui todas as informações de símbolos do módulo especificado e recarrega os símbolos. Em alguns casos, este comando também recarrega ou descarrega o próprio módulo.

Você deve carregar os símbolos adequados para usar a funcionalidade avançada que o WinDbg fornece. Se você não tiver símbolos configurados corretamente, ao tentar usar a funcionalidade que depende de símbolos, receberá mensagens indicando que os símbolos não estão disponíveis.

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

Existem muitas abordagens que podem ser usadas para trabalhar com símbolos. Em muitas situações, você pode configurar o computador para acessar símbolos de um servidor de símbolos que a Microsoft fornece quando eles são necessários. Este laboratório usa essa abordagem. Se os símbolos em seu ambiente estiverem em um local diferente, modifique as etapas para usar esse local. Para obter mais informações, consulte caminho dos símbolos para o depurador do Windows.

Para executar a depuração de origem, você deve criar uma versão verificada (depuração) de seus binários. O compilador cria arquivos .pdb de símbolo (). Esses arquivos de símbolo mostram ao depurador como as instruções binárias correspondem às linhas de origem. Os próprios arquivos de origem também devem estar acessíveis ao depurador.

Os arquivos de símbolo não contêm o texto do código-fonte. Para depuração, é melhor se o vinculador não otimizar seu código. A depuração de origem e o acesso a variáveis locais são mais difíceis e, às vezes, quase impossíveis, se o código tiver sido otimizado. Se você estiver tendo problemas para visualizar variáveis locais ou linhas de origem, defina as seguintes opções de compilação:

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. Digite o seguinte comando na área de comando do depurador para exibir informações sobre o driver 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 obter mais informações, consulte lm.

  2. Como este conjunto de laboratório prefer_dml foi configurado anteriormente, alguns elementos da saída são links ativos que pode selecionar. Selecione o link Procurar todos os símbolos globais na saída de depuração para exibir informações sobre símbolos de itens que começam com a letra "a".

    0: kd> x /D Echo!a*
    
  3. A amostra de eco não contém símbolos que comecem com a letra "a", portanto, digite x ECHO!Echo* para exibir informações sobre todos os símbolos associados ao driver de eco que começam com "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 obter mais informações, consulte x (Examinar símbolos).

  4. A extensão !lmi exibe informações detalhadas sobre um módulo. Digite !lmi echo. Sua saída deve ser semelhante ao texto mostrado neste exemplo:

    0: kd> !lmi echo
    Loaded Module Info: [echo] 
             Module: ECHO
       Base Address: fffff8010bf94000
         Image Name: ECHO.sys
    … 
    
  5. Use a extensão !dh para exibir informações de cabeçalho, conforme mostrado neste exemplo:

    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. Digite o seguinte para alterar a máscara de bits de depuração padrão para que todas as mensagens de depuração do sistema de destino sejam exibidas no depurador:

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    

    Alguns drivers exibem informações adicionais quando a máscara de 0xFFFFFFFF é usada. Defina a máscara como 0x00000000 se quiser reduzir a quantidade de informações exibidas.

    0: kd> ed nt!Kd_DEFAULT_MASK 0x00000000
    

    Use o comando dd para confirmar se a máscara está definida para exibir todas as mensagens do 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
    

Exibir informações da árvore de dispositivos Plug and Play

Nesta seção, apresente informações sobre o driver de dispositivo de amostra de eco e a sua posição na árvore de dispositivos Plug and Play.

As informações sobre o driver de dispositivo na árvore de dispositivos Plug and Play podem ser úteis para solucionar problemas. Por exemplo, se um driver de dispositivo não for residente na árvore de dispositivos, pode haver um problema com a instalação do driver de dispositivo.

Para obter mais informações sobre a extensão de depuração do nó do dispositivo, consulte !devnode.

  1. No sistema anfitrião, para ver todos os nós de dispositivos na árvore de dispositivos Plug and Play, introduza o 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 pesquisar no resultado gerado para procurar o nome do driver de dispositivo, echo.

    Captura de ecrã da caixa de diálogo Localizar no WinDbg procurando pelo termo 'echo'.

  3. O driver do dispositivo de eco deve ser carregado. Use o comando !devnode 0 1 echo para exibir informações Plug and Play associadas ao driver do dispositivo echo, conforme mostrado neste exemplo:

    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. A saída exibida no comando anterior inclui o PDO associado à instância em execução do seu driver, neste exemplo, 0xffffe0007b71a960. Digite o comando !devobj <PDO address> para exibir informações Plug and Play associadas ao driver de dispositivo echo. Use o endereço DOP que !devnode exibe no seu computador, não o mostrado aqui.

    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. A saída exibida no comando !devnode 0 1 inclui o endereço PDO associado à instância em execução do seu driver, neste exemplo é 0xffffe0007b71a960. Digite o comando !devstack <PDO address> para exibir informações Plug and Play associadas ao driver de dispositivo. Use o endereço DOP que !devnode exibe no seu computador, não o mostrado neste exemplo.

    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"
    

A saída mostra que você tem uma pilha de drivers de dispositivo bastante simples. O driver de eco é filho do nó PnPManager. PnPManager é um nó raiz.

\Driver\ECHO
\Driver\PnpManager

Este diagrama mostra uma árvore de nós de dispositivo mais complexa.

Diagrama ilustrando uma árvore de nós de dispositivo que consiste em aproximadamente 20 nós.

Para obter mais informações sobre pilhas de drivers mais complexas, consulte Pilhas de drivers e Nós de dispositivo e pilhas de dispositivos.

Trabalhar com pontos de interrupção e código-fonte

Nesta seção, defina pontos de interrupção e execute o código-fonte do modo kernel passo a passo.

Para ser capaz de percorrer o código e verificar os valores das variáveis em tempo real, habilitar pontos de interrupção e definir um caminho para o código-fonte.

Os pontos de interrupção interrompem a execução de código em uma linha de código específica. Avance no código a partir daquele ponto para corrigir essa seção específica do código.

Para definir um ponto de interrupção usando um comando debug, use um dos seguintes comandos b.

Comando Descrição
bp Define um ponto de interrupção que fica ativo até que o módulo em que ele está seja descarregado.
bu Define um ponto de interrupção que não é resolvido quando o módulo é descarregado e reativa quando o módulo é recarregado.
bm Define um ponto de interrupção para um símbolo. Este comando usa bu ou bp apropriadamente e permite que curingas (*) sejam usados para definir pontos de interrupção em cada símbolo que corresponde, como todos os métodos em uma classe.

Para obter mais informações, consulte Depuração de código-fonte no WinDbg.

  1. No sistema host, use a interface de utilizador do WinDbg para confirmar se Depurar >Modo de Origem está ativado na sessão WinDbg atual.

  2. Digite o seguinte comando para adicionar seu local de código local ao caminho de origem:

    .srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  3. Digite o seguinte comando para adicionar o local do símbolo local ao caminho do símbolo:

    .sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  4. Use o comando x para examinar os símbolos associados ao driver de eco para determinar o nome da função a ser usada para o ponto de interrupção. Você pode usar um curinga ou Ctrl+F para localizar o nome da função 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 
    …
    

    A saída mostra que o método DeviceAdd do driver de eco é ECHO!EchoEvtDeviceAdd.

    Como alternativa, revise o código-fonte para encontrar o nome da função para seu ponto de interrupção.

  5. Defina o ponto de interrupção com o comando bm usando o nome do driver, seguido pelo nome da função, por exemplo, AddDevice, onde você deseja definir o ponto de interrupção, separado por um ponto de exclamação. Este laboratório usa AddDevice para monitorizar o carregamento do controlador.

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

    Você pode usar sintaxe diferente em conjunto com a configuração de variáveis como <module>!<symbol>, <class>::<method>,'<file.cpp>:<line number>'ou ignorar várias vezes <condition> <#>. Para obter mais informações, consulte pontos de interrupção condicionais no WinDbg e outros depuradores do Windows.

  6. Liste os pontos de interrupção atuais para confirmar que o ponto de interrupção foi definido inserindo o comando bl:

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

    O "e" na saída mostrada aqui indica que o ponto de interrupção número 1 está habilitado para disparar.

  7. Reinicie a execução de código no sistema de destino inserindo o comando g (go).

  8. No sistema de destino, no Windows, abra Gestor de Dispositivos usando o ícone ou inserindo mmc devmgmt.msc. No Gestor de Dispositivos, expanda o nó Amostras.

  9. Selecione e segure ou clique com o botão direito do mouse na entrada do driver de eco KMDF e selecione Desativar no menu.

  10. Selecione e segure ou clique com o botão direito do mouse na entrada do driver de eco KMDF novamente e selecione Ativar no menu.

  11. No sistema host, quando o driver está habilitado, o ponto de interrupção de depuração do AddDevice deve ser acionado. A execução do código do driver no sistema de destino deve parar. Quando o ponto de interrupção é atingido, a execução deve ser interrompida no início da rotina de AddDevice. A saída do comando debug exibe Breakpoint 1 hit.

    Captura de tela do WinDbg exibindo locais de código de exemplo e janelas de comando.

  12. Percorra o código linha por linha inserindo o comando p ou pressionando F10 até chegar ao final da seguinte rotina AddDevice. O caractere Brace (}) é destacado como mostrado.

    Captura de tela da janela de código com o caractere de chave realçado no início da rotina AddDevice.

Na próxima seção, examine o estado das variáveis após a execução do código DeviceAdd.

Você pode modificar os pontos de interrupção existentes usando os seguintes comandos:

Comando Descrição
bl Lista os pontos de interrupção.
bc Remove um ponto de interrupção da lista. Use bc * para limpar todos os pontos de interrupção.
bd Desabilita um ponto de interrupção. Use bd * para desativar todos os pontos de interrupção.
be Permite um ponto de interrupção. Use be * para habilitar todos os pontos de interrupção.

Como alternativa, também pode modificar os pontos de interrupção na UI do WinDbg.

Você também pode definir pontos de interrupção que são acionados quando um local de memória é acessado. Use o comando ba (break on access), com a seguinte sintaxe:

ba <access> <size> <address> {options}
Opção Descrição
e execute: quando a CPU busca uma instrução do endereço
r leitura/gravação: quando a CPU lê ou grava no endereço
w gravação: quando a CPU grava no endereço

Você só pode definir quatro pontos de interrupção de dados a qualquer momento. Cabe a você certificar-se de que está alinhando seus dados corretamente para acionar o ponto de interrupção. As palavras devem terminar em endereços divisíveis por 2, as palavras devem ser divisíveis por 4 e as palavras quádruplas por 0 ou 8.

Por exemplo, para definir um ponto de interrupção de leitura/gravação em um endereço de memória específico, você pode usar um comando como este exemplo.

ba r 4 0x0003f7bf0

Você pode usar os comandos a seguir para percorrer seu código com os atalhos de teclado associados mostrados entre parênteses.

  • Entrada (Ctrl+Break). Este comando interrompe um sistema enquanto o sistema estiver em execução e estiver em comunicação com o WinDbg. A sequência no Depurador do Kernel é Ctrl+C.
  • Corra até ao cursor (F7 ou Ctrl+F10). Coloque o cursor numa janela de origem ou desmontagem onde pretende que a execução seja interrompida e, em seguida, prima F7. A execução do código continua até esse ponto. Se o fluxo de execução de código não atingir o ponto indicado pelo cursor, o WinDbg não quebrará. Essa situação pode acontecer se uma instrução IF não for executada.
  • Executar (F5). Execute até que um ponto de interrupção seja encontrado ou um evento como uma verificação de bug ocorra.
  • Avançar (F10). Este comando faz com que a execução de código prossiga uma declaração ou uma instrução de cada vez. Se uma chamada for encontrada, a execução de código ignora a chamada sem entrar na rotina chamada. Se a linguagem de programação for C ou C++ e o WinDbg estiver no modo de origem, o modo de origem poderá ser ativado ou desativado usando Debug>Source Mode.
  • Entrar (F11). Este comando é como step-over, exceto que a execução de uma chamada entra na rotina chamada.
  • Saia (Shift+F11). Este comando faz com que a execução continue até e termine na rotina atual ou no local atual na stack de chamadas. Este comando é útil se você já viu o suficiente da rotina.

Para obter mais informações, consulte Depuração de código-fonte no WinDbg.

Ver variáveis e pilhas de chamadas

Nesta seção, exiba informações sobre variáveis e pilhas de chamadas.

Este laboratório pressupõe que você está parado na rotina de AddDevice usando o processo descrito anteriormente. Para visualizar a saída mostrada aqui, repita as etapas descritas anteriormente, se necessário.

No sistema host, para exibir variáveis, use a visualização >item de menu local para exibir variáveis locais.

Captura de tela do WinDbg exibindo a janela de variáveis locais.

Para encontrar a localização de um endereço variável global, introduza ? <variable name>.

  • Step out (Shift+F11) – Este comando faz com que a execução seja executada e saia da rotina atual (local atual na pilha de chamadas). Isso é útil se você já viu o suficiente da rotina.

Para obter mais informações, consulte Depuração de código-fonte no WinDbg (Clássico) na documentação de referência de depuração.

Seção 8: Exibindo variáveis e pilhas de chamadas

Na Seção 8, você exibirá informações sobre variáveis e pilhas de chamadas.

Este laboratório pressupõe que parou na rotina AddDevice usando o processo descrito anteriormente. Para visualizar o resultado que é apresentado aqui, repita as etapas descritas anteriormente, se necessário.

<- No sistema host

Exibir variáveis

Use o modo de exibição >item de menu local para exibir variáveis locais.

Captura de tela do WinDbg exibindo a janela de variáveis locais.

Variáveis globais

Você pode encontrar a localização de um endereço variável global digitando ? <nome da variável>.

Variáveis locais

Você pode exibir os nomes e valores de todas as variáveis locais para um determinado quadro digitando o comando dv. Para exibir os nomes e valores de todas as variáveis locais de um quadro específico, digite o comando dv:

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

A pilha de chamadas é a cadeia de chamadas de função que levaram à localização atual do contador do programa. A função superior na pilha de chamadas é a função atual, e a próxima função é a função que chamou a função atual, e assim por diante.

Para exibir a pilha de chamadas, use os comandos k*.

Comando Descrição
kb Exibe a pilha e os três primeiros parâmetros.
kp Mostra as pilhas e a lista completa de parâmetros.
kn Permite que você veja a pilha com as informações do quadro ao lado dela.
  1. No sistema host, se quiser manter a pilha de chamadas disponível, seleccione visualizar>pilha de chamadas para visualizá-la. Selecione as colunas na parte superior da janela para alternar a exibição de informações adicionais.

    Captura de ecrã do WinDbg exibindo a janela de pilhas de chamadas.

  2. Use o comando kn para mostrar a pilha de chamadas durante a depuração do código do adaptador de exemplo num estado de interrupção.

    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]
    ...
    

A pilha de chamadas mostra que o kernel (nt) chamou o código Plug and Play (PnP), que chamou o código do quadro de trabalho do driver (WDF), que mais tarde chamou a função DeviceAdd do driver de eco.

Exibir processos e threads

Nesta seção, exiba informações sobre os processos e threads em execução no modo kernel.

Processos

Você pode exibir ou definir informações de processos usando a extensão do depurador !process. Defina um ponto de interrupção para examinar o processo usado quando um som é reproduzido.

  1. No sistema host, insira o comando dv para examinar as variáveis de localidade associadas à rotina EchoEvtIo:

    0: kd> dv ECHO!EchoEvtIo*
    ECHO!EchoEvtIoQueueContextDestroy
    ECHO!EchoEvtIoWrite
    ECHO!EchoEvtIoRead         
    
  2. Limpe os pontos de interrupção anteriores usando bc *:

    0: kd> bc *  
    
  3. Defina um ponto de interrupção de símbolo nas rotinas de EchoEvtIo usando o seguinte comando:

    0: kd> bm ECHO!EchoEvtIo*
      2: aade5490          @!”ECHO!EchoEvtIoQueueContextDestroy”
      3: aade55d0          @!”ECHO!EchoEvtIoWrite”
      4: aade54c0          @!”ECHO!EchoEvtIoRead”
    
  4. Liste os pontos de interrupção para confirmar se o ponto de interrupção está definido corretamente:

    0: kd> bl
    1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197]    0001 (0001) ECHO!EchoEvtIoQueueContextDestroy
    ...
    
  5. Insira g para reiniciar a execução do código:

    0: kd> g
    
  6. No sistema de destino, execute o programa de teste de driver EchoApp.exe.

  7. No sistema host, quando o aplicativo de teste é executado, a rotina de E/S no driver é chamada. Essa chamada faz com que o ponto de interrupção seja acionado e a execução do código do driver no sistema de destino seja interrompida.

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. Use o comando !process para exibir o processo atual envolvido na execução 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
    

    A saída mostra que o processo está associado ao thread echoapp.exe, que estava em execução quando o ponto de interrupção no evento de gravação do driver foi atingido. Para obter mais informações, consulte !process.

  9. Use o !process 0 0 para exibir informações resumidas de todos os processos. Na saída, use Ctrl+F para localizar o mesmo endereço de processo para o processo associado à imagem echoapp.exe. No exemplo, o endereço do processo é ffffe0007e6a7780.

    ...
    
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
        DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
        Image: echoapp.exe
    
    ...
    
  10. Registre a ID do processo associada ao echoapp.exe para usar posteriormente neste laboratório. Você também pode usar Ctrl+C para copiar o endereço para o buffer de cópia para uso posterior.

    _____________________________________________________(echoapp.exe endereço do processo)

  11. Insira g conforme necessário no depurador para executar o código até que echoapp.exe termine a execução. Ele atinge frequentemente o ponto de interrupção durante o evento de leitura e escrita. Quando echoapp.exe terminar, entre no depurador, ao pressionar Ctrl+ScrLk, (Ctrl+Break).

  12. Use o comando !process para confirmar que você está executando um processo diferente. Na saída mostrada aqui, o processo com o valor da Imagem System é diferente do valor da Imagem 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
    ...
    

    A saída mostra que um processo do sistema ffffe0007b65d900 estava em execução quando você parou o sistema operacional.

  13. Use o comando !process para tentar ver o identificador do processo que foi associado a echoapp.exe que registrou anteriormente. Forneça seu endereço de processo echoapp.exe que você registrou anteriormente, em vez do endereço de processo de exemplo mostrado neste exemplo.

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

    O objeto de processo não está mais disponível, porque o processo de echoapp.exe não está mais em execução.

Tópicos

Os comandos para visualizar e definir threads são semelhantes aos comandos para processos. Use o comando !thread para exibir threads. Use .thread para definir os threads atuais.

  1. No sistema host, insira g no depurador para reiniciar a execução de código no sistema de destino.

  2. No sistema de destino, execute o programa de teste do controlador EchoApp.exe.

  3. No sistema host, o ponto de interrupção é atingido e a execução do código é interrompida.

    Breakpoint 4 hit
    ECHO!EchoEvtIoRead:
    aade54c0 55              push    ebp
    
  4. Para exibir os threads que estão em execução, digite !thread. Informações semelhantes ao exemplo a seguir devem ser exibidas:

    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
    ...
    

    Observe o nome da imagem de echoapp.exe. Isso indica que você está olhando para o thread associado ao aplicativo de teste.

  5. Use o comando !process para determinar se esse thread é o único thread em execução no processo associado ao echoapp.exe. O número do thread em execução no processo é o mesmo que o comando !thread exibiu.

    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 o comando !process 0 0 para localizar o endereço do processo de dois processos relacionados e registre o endereço do processo aqui.

    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
    …
    

    Como alternativa, você pode usar !process 0 17 para exibir informações detalhadas sobre cada processo. A saída deste comando pode ser longa. A saída pode ser pesquisada usando Ctrl+F.

  7. Use o comando !process para listar informações de processo para ambos os processos que executam o computador. Forneça o endereço do processo a partir da saída !process 0 0, não o endereço mostrado neste exemplo.

    Este exemplo de saída é para a ID de processo cmd.exe que foi registrada anteriormente. O nome da imagem para este ID de processo é 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
    ...
    

    Este exemplo de saída é para a ID de processo echoapp.exe que foi registrada 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 o primeiro endereço de thread associado aos dois processos aqui.

    Cmd.exe: ____________________________________________________

    EchoApp.exe: _________________________________________________

  9. Use o comando !Thread para exibir informações sobre o thread atual.

    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 esperado, o thread atual é o thread associado ao echoapp.exe e está em um estado de execução.

  10. Use o comando !Thread para exibir informações sobre o thread associado a cmd.exe processo. Forneça o endereço do thread que você gravou 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 thread está associado a cmd.exe e está em um estado de espera.

  11. Forneça o endereço do thread do thread de CMD.exe em espera para alterar o contexto para esse thread em espera.

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. Use o comando k para exibir a pilha de chamadas associada ao thread em 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]
    ...
    

    Elementos da pilha de chamadas, como KiCommitThreadWait indicam que esse thread não está sendo executado como esperado.

Para obter mais informações sobre threads e processos, consulte as seguintes referências:

IRQL, registos e encerramento da sessão do WinDbg

Nesta seção, exiba o nível de solicitação de interrupção (IRQL) e o conteúdo dos registros.

Ver o IRQL guardado

O IRQL é usado para gerenciar a prioridade de interrupção de serviço. Cada processador tem uma configuração IRQL que os threads podem aumentar ou diminuir. As interrupções que ocorrem na configuração IRQL do processador ou abaixo dela são mascaradas e não interferem na operação atual. As interrupções que ocorrem acima da configuração IRQL do processador têm precedência sobre a operação atual.

No sistema anfitrião, a extensão !irql exibe o IRQL no processador em uso do computador de destino antes da interrupção do depurador. Quando o computador de destino entra no depurador, o IRQL muda, mas o IRQL que estava em vigor pouco antes da pausa no depurador é salvo e exibido por !irql.

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

Ver os registos

No sistema host, exiba o conteúdo dos registos para o thread atual no processador atual usando o comando r (Registers).

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

Em alternativa, pode mostrar os conteúdos dos registos selecionando Ver>Registos. Para obter mais informações, consulte r (Registos).

A visualização do conteúdo dos registos pode ser útil ao analisar a execução de código em linguagem assembly e em outros cenários. Para obter mais informações sobre a desmontagem em linguagem de montagem, consulte Desmontagem x86 Anotada e Desmontagem x64 Anotada.

Para obter informações sobre o conteúdo do registro, consulte de arquitetura x86 e de arquitetura x64 .

Encerrar a sessão do WinDbg

Se quiseres deixar o depurador ligado, mas quiseres trabalhar no destino, remove todos os pontos de interrupção usando bc *, para que o computador de destino não tente se conectar ao depurador do computador anfitrião. Em seguida, use o comando g para permitir que o computador de destino seja executado novamente.

Para encerrar a sessão de depuração, no sistema host, entre no depurador e digite o comando qd (Sair e Desanexar) ou selecione Parar Depuração no menu.

0: kd> qd

Para obter mais informações, consulte Encerrar uma sessão de depuração no WinDbg.

Recursos de depuração do Windows

Mais informações estão disponíveis sobre depuração no Windows. Alguns desses livros usam versões anteriores do Windows, como o Windows Vista, em seus exemplos, mas os conceitos discutidos são aplicáveis à maioria das versões do Windows.

Ver também