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

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

Objetivos de laboratório

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

Neste laboratório, você usa uma conexão de depuração de kernel dinâmico para explorar as seguintes ações:

  • Usar os comandos do depurador do Windows
  • Usar comandos padrão (pilhas de chamadas, variáveis, threads, IRQL)
  • Usar comandos avançados de depuração de driver (!comandos)
  • Usar símbolos
  • Definir pontos de interrupção na depuração dinâmica
  • Exibir pilhas de chamadas
  • Exibir a árvore de dispositivos Plug and Play
  • Trabalhar com o thread e o contexto do processo

Depuração do modo de usuário e 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 executados no modo de usuário fazem isso em 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 é alocada para 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 de 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 aborda comandos de depuração que são frequentemente usados durante o modo de usuário e a depuração do modo kernel. O exercício também aborda extensões de depuração, às vezes chamadas de comandos !, que são usadas para depuração no modo kernel.

Configuração do laboratório

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

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

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

  • Visual Studio
  • Software Development Kit do Windows (SDK do Windows) para Windows 10
  • WDK (Windows Driver Kit) para Windows 10
  • O driver de eco de exemplo para Windows 10

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

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

Nesta seção, configure a depuração de rede no host e no sistema de destino.

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

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

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

Diagrama ilustrando dois computadores conectados por meio de um hub de rede ou roteador.

Para trabalhar com aplicativos no modo kernel e usar o WinDbg, recomendamos que você use a KDNET por meio do transporte 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 Preparando um computador para implantação manual de driver e Configurando a depuração de kernel de rede KDNET automaticamente.

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

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

  1. No sistema host, abra uma janela do Prompt de Comando e insira ipconfig para determinar seu endereço 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 o endereço IP do sistema host: ______________________________________

  3. No sistema de destino, abra uma janela do Prompt de Comando e use o ping comando 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ê registrou 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
    

Habilite a depuração no modo kernel no sistema de destino concluindo as etapas a seguir.

Importante

Antes de usar 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. Habilite novamente esses recursos de segurança quando o teste for concluído. Gerencie adequadamente o computador de teste quando os recursos de segurança estiverem desabilitados.

  1. No computador de destino, abra uma janela do Prompt de Comando como Administrador. Insira este comando para habilitar a depuração:

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

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

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

    Aviso

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

  4. Insira este comando para confirmar se os valores de 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 tela da caixa de diálogo Alerta Segurança do Windows indicando que o Firewall do Windows bloqueou alguns recursos de um aplicativo.

  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 WDK (Kit de Driver do Windows) que foi instalado como parte da instalação do kit do Windows. Altere para o diretório WinDbg padrão, o local padrão é mostrado abaixo.

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

    Esse laboratório pressupõe que ambos os computadores executem uma versão de 64 bits do Windows no destino e no host. Se esse não for o caso, a melhor abordagem será executar a mesma bitness de ferramentas no host executado pelo destino. 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 comando a seguir. Os valores da chave e da porta correspondem aos valores definidos anteriormente usando BCDEdit no computador de destino.

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

  8. Em um minuto ou dois, a saída de depuração deve ser exibida no 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
    

A janela Comando do Depurador é a janela principal de informações de depuração no WinDbg. Você pode inserir comandos do depurador e exibir a saída do comando nesta janela.

A janela 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 comando, use as teclas Seta para cima e Seta para baixo para rolar pelo histórico de comandos. Quando um comando é exibido, você pode editá-lo ou pressionar Enter para executar o comando.

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 (Linguagem de Marcação do Depurador) que você pode selecionar para coletar mais informações rapidamente.

  1. No sistema host, use Ctrl+Scroll Lock no WinDBg para invadir o código em execução 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 dinâmico.

  2. Insira o seguinte comando para habilitar o DML na janela 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 .hh comando . Insira o seguinte comando para exibir a ajuda de referência de comando para .prefer_dml:

    0: kd> .hh .prefer_dml
    

    O arquivo de ajuda do depurador exibe a ajuda para o .prefer_dml comando .

    Captura de tela do aplicativo de ajuda do depurador exibindo ajuda para o comando .prefer-dml.

  4. Para exibir informações detalhadas sobre a versão no sistema de destino, insira o comando vertarget (Mostrar Versão do Computador de Destino) 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, insira o comando lm (Listar Módulos Carregados) 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 (detalhada):

    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á nenhum caminho de símbolo definido e símbolos carregados, portanto, informações limitadas estão disponíveis no depurador.

Baixar e compilar o driver de eco KMDF

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

Normalmente, você estaria trabalhando com seu próprio código de driver ao usar o WinDbg. Para se familiarizar com a operação WinDbg, este laboratório usa 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 você pode executar uma única etapa por meio do código nativo do modo kernel. Essa técnica pode ser valiosa para depurar problemas complexos de código no modo kernel.

Para baixar e criar o driver de áudio de exemplo echo:

  1. Baixe 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 realçando a pasta geral e o botão zip de download.

    1. Baixe os exemplos de driver em um arquivo zip: Exemplos de driver

    2. Baixe o arquivo zip no 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 existente para armazenar os arquivos extraídos. Por exemplo, você pode especificar C:\DriverSamples\ como a nova pasta na 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. Em 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 do exemplo. Em Gerenciador de Soluções, selecione e segure ou clique com o botão direito do mouse em Solução 'kmdfecho' (3 projetos)e selecione Configuration Manager. Verifique se as definições de configuração e plataforma são as mesmas para os três projetos. Por padrão, a configuração é definida como Depuração do Win10 e 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. Os exemplos de driver precisam ser modificados para usar valores que não se sobrepõem aos drivers existentes. Consulte Do Código de Exemplo ao Driver de Produção – O que alterar nos exemplos sobre como criar um exemplo de driver exclusivo que coexistirá com drivers reais existentes instalados no Windows.

  5. Defina a biblioteca de runtime. Abra a página de propriedades do driver de eco e localize Geração de CódigoC/C++>. Altere a Biblioteca de Runtime para Depuração multi-threaded (/MTd). Para obter mais informações sobre as opções de build, consulte /MD, /MT, /LD (Use Run-Time Library).

    Captura de tela da página de propriedades de eco no Visual Studio realçando a configuração da biblioteca de runtime.

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

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

  7. No Visual Studio, selecione Compilar>solução de build.

    As janelas de build devem exibir uma mensagem indicando que o build para todos os três projetos foi bem-sucedido.

Dica

Se você encontrar uma mensagem de erro de build, use o número de erro de build para determinar uma correção. Por exemplo, o erro do MSBuild MSB8040 descreve como trabalhar com bibliotecas mitigadas pelo spectre.

  1. Em Explorador de Arquivos, vá para a pasta que contém os arquivos extraídos para o exemplo. Por exemplo, vá para C:\DriverSamples\general\echo\kmdf, se essa for a pasta especificada anteriormente. Nessa pasta, o local dos arquivos de driver compilados varia dependendo das configurações e das configurações da 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 um build de depuração de 64 bits.

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

    A pasta deve conter estes arquivos:

    Arquivo Descrição
    Echo.sys O arquivo de 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 estar localizado aqui: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug.

    Arquivo 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 compilados e o EchoApp de teste 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, use a ferramenta DevCon para instalar o driver de exemplo de eco.

O computador em que você instala o driver é chamado de computador de destino ou computador de teste. Normalmente, esse computador é separado do computador no qual você desenvolve e cria o pacote de driver. O computador em que você desenvolve e cria o driver é chamado de computador host.

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

Antes de implantar um driver assinado de teste, prepare o computador de destino habilitando 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, habilite os drivers assinados de teste:

  1. Abra as Configurações do Windows.

  2. Em 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. Em Windows 10, selecione Solucionar> problemas deconfigurações de inicialização deopções> avançadas e, em seguida, selecione Reiniciar.

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

  6. Reinicie o computador de destino.

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

Crie uma pasta no destino para o pacote de driver criado, por exemplo, C:\EchoDriver. Copie devcon.exe para o sistema de destino. Localize o certificado .cer no sistema host. Ele está na mesma pasta no computador host na pasta que contém os arquivos de driver criados. Copie todos os arquivos do driver criado descritos 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 Instalar e siga os prompts para instalar o certificado de teste.

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

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

devcon install <INF file> <hardware ID>

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

No computador de destino, abra uma janela do Prompt de Comando como Administrador. Vá para a pasta do pacote de driver e insira o seguinte comando:

devcon install echo.inf root\ECHO

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

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

Uma caixa de diálogo é exibida que indica que o driver de teste é um driver sem sinal. Selecione Instalar este driver de qualquer maneira 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 problemas com a instalação, marcar o arquivo a seguir para obter mais informações. %windir%\inf\setupapi.dev.log

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

No computador de destino, em uma janela do Prompt de Comando, insira devmgmt para abrir Gerenciador de Dispositivos. Em Gerenciador de Dispositivos, no menu Exibir, escolha Dispositivos por tipo. Na árvore de dispositivos, localize o Driver de Eco WDF de exemplo no nó Dispositivo de Exemplo.

Captura de tela de Gerenciador de Dispositivos árvore realçando o driver de eco WDF de exemplo.

Insira 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

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

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

Para exibir informações sobre o driver:

  1. No sistema host, se você fechou o depurador, abra-o novamente usando o comando a seguir na janela do Prompt de Comando do administrador.

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Use Ctrl+Break (Bloqueio de Rolagem) para invadir 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 .symfix comando .

    0: kd> .symfix
    
  4. Para adicionar o local do símbolo local para usar 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 .reload comando com a opção /f force exclui todas as informações de símbolo do módulo especificado e recarrega os símbolos. Em alguns casos, esse 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 dependente 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.

Há 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 necessário. 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 do símbolo 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 de símbolo (arquivos.pdb ). 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 reais também devem ser acessíveis para o 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 exibir variáveis locais ou linhas de origem, defina as seguintes opções de build:

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. Insira 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 esse laboratório foi definido prefer_dml anteriormente, alguns elementos da saída são links quentes que você 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. O exemplo de eco não contém nenhum símbolo que comece 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 !lmi extensão 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 !dh extensão 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. Insira 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 dd comando 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 de árvore de dispositivo Plug and Play

Nesta seção, exiba informações sobre o driver de dispositivo de exemplo de eco e onde ele reside na árvore de dispositivos Plug and Play.

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

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

  1. No sistema host, para ver todos os nós do dispositivo na árvore do dispositivo Plug and Play, insira o !devnode 0 1 comando .

    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 na saída gerada para procurar o nome do driver do dispositivo, eco.

    Captura de tela da caixa de diálogo Localizar no WinDbg pesquisando o termo 'echo'.

  3. O driver do dispositivo de eco deve ser carregado. Use o !devnode 0 1 echo comando para exibir Plug and Play informações associadas ao driver do dispositivo de eco, 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 driver, neste exemplo, 0xffffe0007b71a960. Insira o !devobj <PDO address> comando para exibir Plug and Play informações associadas ao driver do dispositivo de eco. Use o endereço PDO exibido !devnode no 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 !devnode 0 1 comando inclui o endereço PDO associado à instância em execução do driver, neste exemplo é 0xffffe0007b71a960. Insira o !devstack <PDO address> comando para exibir Plug and Play informações associadas ao driver do dispositivo. Use o endereço PDO exibido !devnode no 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 driver de dispositivo bastante simples. O driver de eco é um filho do nó PnPManager . PnPManager é um nó raiz.

\Driver\ECHO
\Driver\PnpManager

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

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

Para obter mais informações sobre pilhas de driver mais complexas, consulte Pilhas de driver 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 etapa única por meio do código-fonte do modo kernel.

Para poder percorrer o código e marcar os valores das variáveis em tempo real, habilite os pontos de interrupção e defina 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 desse ponto para depurar essa seção específica do código.

Para definir um ponto de interrupção usando um comando de depuração, use um dos comandos a seguir b .

Comando Descrição
bp Define um ponto de interrupção que está 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 habilita novamente quando o módulo é recarregado.
bm Define um ponto de interrupção para um símbolo. Esse comando usa bu ou bp adequadamente e permite que curingas (*) sejam usados para definir pontos de interrupção em todos os símbolos correspondentes, 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 do usuário do WinDbg para confirmar se oModo de Origem de Depuração> está habilitado na sessão atual do WinDbg.

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

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

    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 DeviceAdd método para o driver de eco é ECHO!EchoEvtDeviceAdd.

    Como alternativa, examine o código-fonte para localizar o nome da função para o ponto de interrupção.

  5. Defina o ponto de interrupção com o bm comando usando o nome do driver, seguido pelo nome da função, por exemplo, AddDevice, em que você deseja definir o ponto de interrupção, separado por um ponto de exclamação. Este laboratório usa AddDevice para watch o driver que está sendo carregado.

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

    Você pode usar uma 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 se o ponto de interrupção foi definido inserindo o bl comando :

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

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

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

  9. Selecione e segure ou clique com o botão direito do mouse na entrada do driver de eco KMDF e selecione Desabilitar 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 Habilitar no menu.

  11. No sistema host, quando o driver está habilitado, o ponto de interrupção de depuração AddDevice deve ser acionado. A execução do código do driver no sistema de destino deve ser interrompida. Quando o ponto de interrupção é atingido, a execução deve ser interrompida no início da rotina AddDevice . A saída do comando de depuração 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 p comando ou pressionando F10 até chegar ao final a seguir da rotina AddDevice . O caractere Brace (}) é realçado conforme 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 Listas pontos de interrupção.
bc Limpa 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 desabilitar todos os pontos de interrupção.
be Habilita um ponto de interrupção. Use be * para habilitar todos os pontos de interrupção.

Como alternativa, você também pode modificar pontos de interrupção na interface do usuário do WinDbg.

Você também pode definir pontos de interrupção que são acionados quando um local de memória é acessado. Use o ba comando (interromper no acesso), 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 write: quando a CPU grava no endereço

Você só pode definir quatro pontos de interrupção de dados em um determinado momento. Cabe a você verificar se está alinhando seus dados corretamente para disparar o ponto de interrupção. As palavras devem terminar em endereços divisível por 2, dwords devem ser divisível por 4 e quad words 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.

  • Interrompa (Ctrl+Break). Esse 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.
  • Execute até o cursor (F7 ou Ctrl+F10). Coloque o cursor em uma janela de origem ou desmontagem em que você deseja que a execução seja interrompida e pressione F7. A execução de código é executada até esse ponto. Se o fluxo de execução de código não atingir o ponto indicado pelo cursor, o WinDbg não será interrompido. Essa situação poderá ocorrer 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 um bug marcar ocorrer.
  • Passo a passo (F10). Esse comando faz com que a execução do código prossiga com uma instrução ou uma instrução por vez. Se uma chamada for encontrada, a execução do código passará pela chamada sem entrar na rotina chamada. Se a linguagem de programação for C ou C++ e WinDbg estiver no modo de origem, o modo de origem poderá ser ativado ou desativado usando oModo de Origemde Depuração>.
  • Intervir (F11). Esse comando é como um passo a passo, exceto que a execução de uma chamada entra na rotina chamada.
  • Sair (Shift+F11). Esse comando faz com que a execução seja executada e saia da rotina atual ou do local atual na pilha de chamadas. Esse comando é útil se você já viu o suficiente da rotina.

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

Exibir 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ê esteja parado na rotina AddDevice usando o processo descrito anteriormente. Para exibir a saída mostrada aqui, repita as etapas descritas anteriormente, se necessário.

No sistema host, para exibir variáveis, use o item de menulocalde> exibição para exibir variáveis locais.

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

Para localizar o local de um endereço de variável global, insira ? <variable name>.

  • Sair (Shift+F11) – esse 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 você esteja parado na rotina AddDevice usando o processo descrito anteriormente. Para exibir a saída mostrada aqui, repita as etapas descritas anteriormente, se necessário.

<- No sistema host

Exibir variáveis

Use o item de menulocalde exibição> para exibir variáveis locais.

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

Variáveis globais

Você pode encontrar o local de um endereço de 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 para um quadro específico, insira o dv comando :

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

A pilha de chamadas é a cadeia de chamadas de função que levaram ao local 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 k* comandos .

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

    Captura de tela do WinDbg exibindo a janela pilhas de chamadas.

  2. Use o kn comando para mostrar a pilha de chamadas ao depurar o código do adaptador de exemplo em um 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 Plug and Play código (PnP) que chamou o código da estrutura de driver (WDF) que mais tarde chamou a função de driver DeviceAdd 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 processo 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 dv comando para examinar as variáveis de localidade associadas à EchoEvtIo rotina:

    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 EchoEvtIo rotinas 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 EchoApp.exe driver no sistema de destino.

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

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. Use o !process comando 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 threadechoapp.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 para 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 a echoapp.exe a ser usada 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.

    _____________________________________________________(endereço do processo echoapp.exe)

  11. Insira g conforme necessário no depurador para executar o código até queechoapp.exe termine de ser executado. Ele atinge o ponto de interrupção no evento de leitura e gravação muitas vezes. Quando echoapp.exe terminar, entre no depurador pressionando Ctrl+ScrLk (Ctrl+Break).

  12. Use o !process comando para confirmar que você está executando um processo diferente. Na saída mostrada aqui, o processo com o valor Imagem do Sistema é diferente do valor de Imagem de Eco .

    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 !process comando para tentar examinar a ID do processo que havia sido associada a echoapp.exe que você registrou anteriormente. Forneça seu echoapp.exe endereço de processo 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, pois o processo deechoapp.exe não está mais em execução.

Threads

Os comandos para exibir 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 de driver 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 em execução, insira !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á examinando o thread associado ao aplicativo de teste.

  5. Use o !process comando para determinar se esse thread é o único thread em execução no processo associado ao echoapp.exe. O número de thread do thread em execução no processo é o mesmo thread em execução que o !thread comando 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 !process 0 0 comando para localizar o endereço do processo de dois processos relacionados e registrar 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 desse comando pode ser longa. A saída pode ser pesquisada usando Ctrl+F.

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

    Este exemplo de saída é para a ID do processocmd.exeque foi registrada anteriormente. O nome da imagem para essa 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 do processoechoapp.exeque 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 !Thread comando 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
    ...
    

    Conforme esperado, o thread atual é o thread associado a echoapp.exe e está em um estado em execução.

  10. Use o !Thread comando para exibir informações sobre o thread associado a cmd.exe processo. Forneça o endereço de 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]
    ...
    

    Esse thread está associado a cmd.exe e está em estado de espera.

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

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. Use o k comando para exibir a pilha de chamadas associada ao thread de 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 de pilha de chamadas, como, indicam KiCommitThreadWait que esse thread não está em execução conforme o esperado.

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

IRQL, registra e encerra a sessão do WinDbg

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

Exibir o IRQL salvo

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

No sistema host, a extensão !irql exibe o IRQL no processador atual do computador de destino antes da interrupção do depurador ocorrer. Quando o computador de destino entra no depurador, o IRQL é alterado, mas o IRQL que foi eficaz pouco antes da quebra do depurador ser salvo e exibido por !irql.

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

Exibir os registros

No sistema host, exiba o conteúdo dos registros do thread atual no processador atual usando o 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, você pode exibir o conteúdo dos registros selecionando Exibir>Registros. Para obter mais informações, consulte r (Registros).

A exibição do conteúdo dos registros pode ser útil ao percorrer a execução do código do idioma do assembly e em outros cenários. Para obter mais informações sobre a desmontagem da linguagem do assembly, consulte Desmontagem anotada x86 e Desmontagem x64 anotada.

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

Encerrar a sessão do WinDbg

Se você quiser deixar o depurador anexado, mas quiser trabalhar no destino, desmarque todos os pontos de interrupção usando bc *, para que o computador de destino não tente se conectar ao depurador do computador host. Em seguida, use o g comando para permitir que o computador de destino seja executado novamente.

Para encerrar a sessão de depuração, no sistema host, interrompa o depurador e insira o qd comando (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 na depuração do 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.

Confira também