Depurar drivers: laboratório passo a passo (modo kernel Sysvad)

Este laboratório fornece exercícios práticos que demonstram como depurar o driver de dispositivo de modo kernel de áudio Sysvad.

O Microsoft Windows Debugger (WinDbg) é uma ferramenta de depuração avançada baseada no Windows a ser usada para executar depuração nos modos de usuário e kernel. O WinDbg fornece depuração em nível de origem para o kernel do Windows, drivers no modo kernel e serviços do sistema, bem como aplicativos e drivers no modo de usuário.

O WinDbg pode percorrer o código-fonte, definir pontos de interrupção, exibir variáveis (incluindo objetos C++), rastreamentos de pilha e memória. A janela de comando do depurador permite que o usuário emita diversos comandos.

Configuração do laboratório

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

  • Um notebook ou computador desktop (host) com o Windows 10
  • Um notebook ou computador desktop (destino) com o Windows 10
  • Um hub/roteador de rede e cabos de rede para conectar os dois computadores
  • Acesso à Internet para baixar arquivos de símbolos

Você precisará do software a seguir para concluir o laboratório.

  • Microsoft Visual Studio 2017
  • SDK (Software Development Kit) do Windows para o Windows 10
  • WDK (Kit de driver do Windows) para o Windows 10
  • O driver de áudio Sysvad de exemplo para o Windows 10

Para saber mais sobre como baixar e instalar o WDK, confira Baixar o WDK (Kit de driver do Windows).

Passo a passo de depuração do Sysvad

Este laboratório orienta você pelo processo de depuração de um driver no modo kernel. Os exercícios usam o exemplo de driver de áudio virtual Syvad. Como o driver de áudio Syvad não interage com o hardware de áudio real, é possível usá-lo na maioria dos dispositivos. O laboratório abrange as seguintes tarefas:

Laboratório de driver de eco

O driver de eco é um driver mais simples do que o driver de áudio Sysvad. Se não estiver familiarizado com o WinDbg, considere primeiro terminar Depurar drivers universais: laboratório passo a passo (modo de kernel echo). Este laboratório reutiliza as instruções de configuração desse laboratório; portanto, se você tiver concluído esse laboratório, poderá ignorar as seções 1 e 2 aqui.

Seção 1: conectar-se a uma sessão WinDbg no modo kernel

Na Seção 1, você configurará a depuração de rede no host e no sistema de destino.

É preciso configurar computadores neste laboratório para usar uma conexão de rede Ethernet para depuração do kernel.

Este laboratório usa dois computadores. O WinDbg é executado no sistema host e o driver Sysvad é executado no sistema de destino.

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

O diagrama mostra dois computadores conectados por um hub/roteador de rede.

Para trabalhar com aplicativos de modo kernel e usar o WinDbg, é recomendável usar o KDNET em vez do transporte Ethernet. Para saber mais sobre como usar o protocolo de transporte Ethernet, confira Introdução ao WinDbg (modo kernel). Para saber mais sobre como configurar o computador de destino, confira Preparar um computador para implantação manual de driver e Configurar automaticamente a depuração do kernel de rede KDNET.

Configurar depuração no modo kernel usando a Ethernet

Execute as etapas a seguir para habilitar a depuração no modo kernel no sistema de destino.

<- No sistema host

  1. Abra uma janela do Prompt de comando no sistema host e digite ipconfig /all para determinar o endereço IP.
C:\>ipconfig /all
Windows IP Configuration

 Host Name . . . . . . . . . . . . : TARGETPC
...

Ethernet adapter Ethernet:
   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b3
   Autoconfiguration IPv4 Address. . : 169.182.1.1
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Default Gateway . . . . . . . . . :
  1. Registre o endereço IP do sistema host: ______________________________________

  2. Registre o nome do host do sistema host: ______________________________________

-> No sistema de destino

  1. Abra uma janela do Prompt de comando no sistema de destino e use o comando ping para confirmar a conectividade de rede entre os dois sistemas. Use o endereço IP real do sistema host gravado em vez de 169.182.1.1 que aparece na saída de exemplo.
C:\> ping 169.182.1.1

Pinging 169.182.1.1 with 32 bytes of data:
Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255

Ping statistics for 169.182.1.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms

Para usar o utilitário KDNET para habilitar a depuração no modo kernel no sistema de destino, execute as etapas a seguir.

  1. No sistema host, localize o diretório WDK KDNET. Ele está localizado aqui, por padrão.

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

Esse laboratório supõe que ambos os computadores estão executando 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 o mesmo "bitness" de ferramentas no host que o destino está executando. Por exemplo, se o destino estiver executando o Windows de 32 bits, execute uma versão de 32 do depurador no host. Para saber mais, confira Escolher as ferramentas de depuração de 32 ou 64 bits.

  1. Localize esses dois arquivos e copie-os em um compartilhamento de rede ou em uma unidade USB; assim, eles serão disponibilizados no computador de destino.

    kdnet.exe

    VerifiedNICList.xml

  2. No computador de destino, abra uma janela do prompt de comando como Administrador. Insira este comando para validar se a NIC tem suporte no PC de destino.

C:\KDNET>kdnet

Network debugging is supported on the following NICs:
busparams=0.25.0, Intel(R) 82579LM Gigabit Network Connection, KDNET is running on this NIC.kdnet.exe
  1. Digite este comando para definir o endereço IP do sistema host. Use o endereço IP real do sistema host gravado em vez de 169.182.1.1 que aparece na saída de exemplo. Escolha um endereço de porta único para cada par de destino/host de trabalho, como 50010.
C:\>kdnet 169.182.1.1 50010

Enabling network debugging on Intel(R) 82577LM Gigabit Network Connection.
Key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p

Importante

Antes de usar o BCDEdit para alterar as informações de inicialização, talvez você precise suspender de forma temporária os recursos de segurança do Windows, como o BitLocker e a Inicialização Segura, no computador de teste. Reabilite esses recursos de segurança quando o teste terminar e gerencie adequadamente o PC de teste, quando os recursos de segurança estiverem desabilitados. A inicialização segura costuma ser desabilitada na UEFI. Para acessar a configuração UEFI, Usar sistema, Recuperação, Inicialização avançada. Na reinicialização, selecione Solução de problemas, Opções avançadas, Configurações de firmware UEFI. Tenha cuidado porque a definição incorreta de opções da UEFI ou a desabilitação do BitLocker pode tornar o sistema inoperante.

  1. Digite o comando para confirmar se as dbgsettings estão definidas corretamente.
C:\> bcdedit /dbgsettings
busparams               0.25.0
key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
debugtype               NET
hostip                  169.182.1.1
port                    50010
dhcp                    Yes
The operation completed successfully.

Copie a chave exclusiva gerada de forma automática para um arquivo de texto, para evitar precisar digitá-la no computador host. Copie o arquivo de texto com a chave para o sistema host.

ObservaçãoFirewalls e depuradores

Se você receber uma mensagem pop-up do firewall e desejar usar o depurador, marque as três caixas.

Captura de tela do Alerta de segurança do Windows indicando que o Firewall do Windows bloqueou alguns recursos de um aplicativo.

<- No sistema host

  1. No computador host, abra uma janela do Prompt de Comando como administrador. Altere para o diretório WinDbg.exe. Usaremos 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.
C:\> Cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 
  1. Inicie o WinDbg com depuração de usuário remoto usando o comando a seguir. O valor da chave e da porta correspondem ao que você definiu antes por meio do BCDEdit no destino.
C:\> WinDbg –k net:port=50010,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p

->No sistema de destino

Reinicialize o sistema de destino.

<-No sistema host

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

Captura de tela do Depurador do Windows exibindo a saída da janela de comando de uma conexão de kernel ao vivo.

A janela Comando do Depurador é a principal janela de informações da 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. Você digita comandos no painel menor (painel de entrada de comandos) na parte inferior da janela e exibe 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 para baixo para rolar pelo histórico de comandos. Quando um comando aparece, você pode editá-lo ou pressionar ENTER para executá-lo.

Seção 2: comandos e técnicas de depuração no modo kernel

Na Seção 2, você usará comandos de depuração para exibir informações sobre o sistema de destino.

<- No sistema host

Habilitar DML (linguagem de marcação do depurador) com .prefer_dml

Alguns comandos de depuração exibem texto usando a DML (linguagem de marcação do depurador), que você pode selecionar para coletar rapidamente mais informações.

  1. Use Ctrl+Break (Scroll Lock) no WinDBg para entrar no código em execução no sistema de destino. Pode demorar para o sistema de destino responder.
  2. Digite o comando a seguir para habilitar a DML na janela Comando do Depurador.
0: kd> .prefer_dml 1
DML versions of commands on by default

Use .hh para obter ajuda

Você pode acessar a ajuda de referência do comando usando por meio do comando .hh.

  1. Digite o comando a seguir para exibir a ajuda de referência do comando para .prefer_dml.
    0: kd> .hh .prefer_dml
    

O arquivo de ajuda do depurador exibirá ajuda para o comando .prefer_dml.

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

Exibir a versão do Windows no sistema de destino

  1. Exiba informações detalhadas sobre a versão do sistema de destino, digitando o comando vertarget (mostrar versão do computador de destino) na janela do 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

Listar os módulos carregados

  1. Você pode verificar se está trabalhando com o processo correto no modo kernel ao exibir os módulos carregados digitando o comando lm (listar módulos carregados) na janela do WinDbg.
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
...

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

Como ainda não definimos o caminho do símbolo e os símbolos carregados, há informações limitadas disponíveis no depurador.

Seção 3: baixar e compilar o driver de áudio Sysvad

Na Seção 3, você baixará e compilará o driver de áudio Sysvad.

Em geral, você trabalharia com seu próprio código de driver ao usar o WinDbg. Para se familiarizar com a depuração de drivers de áudio, usa-se o driver de exemplo de áudio virtual Sysvad. Este exemplo é usado para ilustrar como você pode usar uma única etapa para percorrer o código nativo no modo kernel. Essa técnica pode ser muito valiosa para depurar problemas complexos de código no modo kernel.

Para baixar e compilar o driver de áudio Sysvad de exemplo, execute as etapas a seguir.

  1. Baixar e extrair o exemplo de áudio Sysvad do GitHub

    Você pode usar um navegador para exibir o Sysvad de exemplo e o arquivo Readme.md aqui:

    https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad

    Captura de tela do repositório do GitHub exibindo a pasta geral e o botão Baixar ZIP.

    Este laboratório mostra como baixar os drivers universais de exemplo em um arquivo zip.

    a. Baixe o arquivo master.zip no disco rígido local.

    https://github.com/Microsoft/Windows-driver-samples/archive/master.zip

    b. Selecione e segure (ou clique com o botão direito do mouse) Windows-driver-samples-master.zip e selecione Extrair tudo. Especifique uma nova pasta ou navegue até uma existente que armazenará os arquivos extraídos. Por exemplo, você pode especificar C:\WDK_Samples\ como a nova pasta em que os arquivos são extraídos.

    c. Após a extração dos arquivos, navegue até a subpasta a seguir.

    C:\WDK_Samples\Sysvad

  2. Abra a solução do driver no Visual Studio.

    No Visual Studio, selecione Arquivo>Abrir>Projeto/Solução... e navegue até a pasta contendo os arquivos extraídos (por exemplo, C:\WDK_Samples\Sysvad). Clique duas vezes no arquivo de solução Syvad.

    No Visual Studio, localize o Gerenciador de Soluções. (Se isso ainda não estiver aberto, escolha Gerenciador de Soluções no menu Exibir.) No Gerenciador de Soluções, você pode ver uma solução com vários projetos.

    Captura de tela do Visual Studio com o arquivo adapter.cpp carregado do projeto Sysvad.

  3. Defina a configuração e a plataforma do exemplo

    No Gerenciador de Soluções, selecione e segure (ou clique com o botão direito do mouse) Solução 'sysvad' (7 de 7 projetos) e escolha Gerenciador de Configurações. Verifique se a configuração e as definições da plataforma são iguais para os quatro projetos. Por padrão, a configuração é definida como "Depuração do Win10" e a plataforma é definida como "Win64" para todos os projetos. Se fizer alterações na configuração e/ou na plataforma de um projeto, você precisará fazer as mesmas alterações nos três projetos restantes.

    Observação Este laboratório pressupõe que o Windows de 64 bits está em uso. Se você estiver usando o Windows de 32 bits, compile o driver para 32 bits.

  4. Verificar a assinatura do driver

    Localize o TabletAudioSample. Abra a página de propriedades do driver Sysvad e verifique se Assinatura do Driver>Modo de Assinatura está definido como Assinatura de Teste.

  5. É necessário modificar os drivers de exemplo para usar valores que não sobrepõem os drivers existentes. Consulte Do código de exemplo ao driver de produção: o que alterar nos exemplos sobre como criar um driver de exemplo exclusivo que coexistirá com drivers reais existentes instalados no Windows.

  6. Compile o exemplo usando o Visual Studio

    No Visual Studio, selecione Criar>Criar Solução.

    As janelas de compilação devem exibir uma mensagem que indica que os seis projetos foram criados com êxito.

Dica

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

  1. Localizar os arquivos do driver compilado

    No Explorador de Arquivos, navegue até a pasta que contém os arquivos extraídos para o exemplo. Por exemplo, você navegaria até C:\WDK_Samples\Sysvad se essa fosse a pasta especificada antes. Nessa pasta, o local dos arquivos de driver compilados varia de acordo com a configuração e as definições da plataforma selecionadas no Gerenciador de Configurações. Por exemplo, se você deixou as configurações padrão inalteradas, os arquivos do driver compilado serão salvos em uma pasta chamada \x64\Debug para um build de depuração de 64 bits.

    Navegue até a pasta que contém os arquivos compilados para o driver TabletAudioSample:

    C:\WDK_Samples\Sysvad\TabletAudioSample\x64\Debug. A pasta conterá o driver .SYS TabletAudioSample, o arquivo pdp de símbolo e o arquivo inf. Você também precisará localizar as DLLs DelayAPO, KWSApo e KeywordDetectorContosoAdapter e arquivos de símbolo.

    Para instalar o driver, você precisará dos arquivos a seguir.

    Nome do arquivo Descrição
    TabletAudioSample.sys O arquivo do driver.
    TabletAudioSample.pdb O arquivo de símbolo do driver.
    tabletaudiosample.inf Um arquivo de informações (INF) contendo informações necessárias para instalar o driver.
    KeywordDetectorContosoAdapter.dll Um detector de palavras-chave de exemplo.
    KeywordDetectorContosoAdapter.pdb O arquivo de símbolo do detector de palavra-chave de exemplo.
    DelayAPO.dll Uma APO de atraso de exemplo.
    DelayAPO.pdb O arquivo de símbolo APO de atraso.
    KWSApo.dll Um localizador de palavras-chave APO de exemplo.
    KWSApo.pdb O arquivo de símbolo do localizador de palavras-chave.
    TabletAudioSample.cer O arquivo de certificado TabletAudioSample.
  2. Localize uma unidade USB ou configure um compartilhamento de rede para copiar os arquivos do driver compilado do host para o sistema de destino.

Na próxima seção, você copiará o código para o sistema de destino, e instalará e testará o driver.

Seção 4: instalar o driver de áudio Sysvad de exemplo no sistema de destino

Na Seção 4, você usará o devcon para instalar o driver de áudio Sysvad.

-> No sistema de destino

O computador em que você instala o driver é chamado de computador de destino ou o computador de teste. Em geral, este é um computador separado do computador em que você desenvolve e compila o pacote de driver. O computador onde você 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 é denominado implantação do driver.

Antes de implantar um driver, você deve preparar o computador de destino ativando a assinatura de teste. Depois disso, você estará pronto para executar o driver compilado de exemplo no sistema de destino.

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

  1. Habilitar drivers assinados de teste

    Para habilitar a capacidade de executar 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 Solução de problemas.

    5. Depois, selecione Opções avançadas, Configurações de Inicialização e, depois, selecione Reiniciar.

    6. Pressione a tecla F7 para selecionar Desativar imposição de assinatura de driver.

    7. O computador começará com os novos valores em vigor.

  2. -> No sistema de destino

    Instalar o driver

    As instruções a seguir mostram como instalar e testar o driver de exemplo.

    O TabletAudioSample.inf é o arquivo INF necessário para instalar este driver. No computador de destino, abra uma janela do prompt de comando como Administrador. Navegue até a pasta do pacote de driver, clique com o botão direito do mouse no arquivo TabletAudioSample.inf e selecione Instalar.

    Uma caixa de diálogo aparecerá indicando que o driver de teste é um driver não assinado. Selecione Instalar este driver mesmo assim para prosseguir.

    Captura de tela do Aviso de segurança do Windows informando que o Windows não pode verificar o fornecedor.

    Dica

     Em caso de problema com a instalação, verifique o arquivo a seguir para obter mais informações. %windir%\inf\setupapi.dev.log

    Para saber mais detalhadas, confira Configurar um computador para implantação, teste e depuração de driver.

    O arquivo INF contém a ID do hardware para instalar o tabletaudiosample.sys. Para o Syvad de exemplo, a ID do hardware é: root\sysvad_TabletAudioSample

  3. Examine o driver no Gerenciador de Dispositivos

    No computador de destino, em uma janela Prompt de comando, insira devmgmt para abrir o Gerenciador de Dispositivos. No Gerenciador de Dispositivos, no menu Exibir, selecione Dispositivos por tipo.

    Na árvore de dispositivos, localize WDM (dispositivo de áudio virtual): exemplo de tablet no nó do dispositivo de áudio. Isso costuma estar no nó Controladores de som, vídeo e jogos. Confirme se ele está instalado e ativo.

    Realce o driver para o hardware real no computador no Gerenciador de Dispositivos. Selecione e segure (ou clique com o botão direito do mouse) o driver e selecione Desativar para desativar o driver.

    Confirme no Gerenciador de Dispositivos que o driver de hardware de áudio exibe a seta para baixo, indicando que ele está desabilitado.

    Captura de tela da árvore do Gerenciador de Dispositivos com o exemplo de tablet de dispositivo de áudio virtual destacado.

    Após a instalação com êxito do driver de exemplo, agora você está pronto para testá-lo.

Testar o driver de áudio Sysvad

  1. No computador de destino, em uma janela Prompt de comando, insira devmgmt para abrir o Gerenciador de Dispositivos. No Gerenciador de Dispositivos, no menu Exibir, selecione Dispositivos por tipo. Na árvore de dispositivos, localize WDM (dispositivo de áudio virtual): exemplo de tablet.

  2. Abra o Painel de controle e navegue até Hardware e Som>Gerenciar dispositivos de áudio. Na caixa de diálogo Som, selecione o ícone do alto-falante rotulado como WDM (dispositivo de áudio virtual): exemplo de tablet e selecione Definir Padrão, mas não selecione OK. Isso manterá a caixa de diálogo Som aberta.

  3. Localize um MP3 ou outro arquivo de áudio no computador de destino e clique duas vezes para reproduzi-lo. Na caixa de diálogo Som, verifique se há atividade no indicador de nível de volume associado ao driver de WDN (dispositivo de áudio virtual): exemplo de tablet.

Seção 5: usar o WinDbg para exibir informações sobre o driver

Na seção 5, você definirá o caminho do símbolo e usará os comandos do depurador de kernel para exibir informações sobre o driver Sysvad de exemplo .

Os símbolos permitem que o WinDbg exiba informações adicionais, como nomes de variáveis, que podem ser valiosas na depuração. O WinDbg usa os formatos de símbolo de depuração do Microsoft Visual Studio para a depuração no nível de origem. Ele pode acessar qualquer símbolo ou variável de um módulo com arquivos de símbolo PDB.

Para carregar o depurador, execute as etapas a seguir.

<-No sistema host

  1. Se você fechou o depurador, abra-o novamente usando o comando a seguir na janela do prompt de comando do administrador. Substitua a chave e a porta pelo que você configurou antes.

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

Definir o caminho do símbolo

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

    0: kd> .symfix
    
  2. Para adicionar o local do símbolo local e usar os símbolos locais, adicione o caminho usando .sympath+ e, depois, .reload /f.

    0: kd> .sympath+ C:\WDK_Samples\Sysvad
    0: kd> .reload /f
    

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

Observação Você precisa carregar os símbolos adequados para usar a funcionalidade avançada fornecida pelo WinDbg. Se você não tiver símbolos configurados corretamente, receberá mensagens indicando que os símbolos não estarão disponíveis quando você tentar usar a funcionalidade que depende de símbolos.

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

ObservaçãoServidores de símbolos

Há uma série de abordagens a serem usadas para trabalhar com símbolos. Em muitas situações, você pode configurar o computador para acessar os símbolos de um servidor de símbolos fornecido pela Microsoft quando eles são necessários. Este passo a passo supõe que essa abordagem será usada. Se os símbolos em seu ambiente estiverem em um local distinto, modifique as etapas para usar esse local. Para saber mais, confira Caminho do símbolo para o depurador do Windows.

ObservaçãoEntender os requisitos de símbolo do código-fonte

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

Os arquivos de símbolo não contêm o texto do código-fonte. Para a depuração, convém que o vinculador não otimize seu código. A depuração de origem e o acesso a variáveis locais serão mais difíceis e, às vezes, quase impossíveis se o código tiver sido otimizado. Em caso de problemas para exibir as variáveis locais ou as linhas de origem, defina as opções de build a seguir.

defina COMPILE_DEBUG=1

defina ENABLE_OPTIMIZER=0

  1. Digite os itens a seguir na área de comando do depurador para exibir informações sobre o driver Sysvad.

    0: kd> lm m tabletaudiosample v
    Browse full module list
    start             end                 module name
    fffff801`14b40000 fffff801`14b86000   tabletaudiosample   (private pdb symbols)  C:\Debuggers\sym\TabletAudioSample.pdb\E992C4803EBE48C7B23DC1596495CE181\TabletAudioSample.pdb
        Loaded symbol image file: tabletaudiosample.sys
        Image path: \SystemRoot\system32\drivers\tabletaudiosample.sys
        Image name: tabletaudiosample.sys
        Browse all global symbols  functions  data
        Timestamp:        Thu Dec 10 12:20:26 2015 (5669DE8A)
        CheckSum:         0004891E
    ...  
    

    Para saber mais, confira lm.

  2. Selecione o link Procurar todos os símbolos globais na saída de depuração para exibir informações sobre símbolos de itens iniciados com a letra "a".

  3. Como a DML está habilitada, alguns elementos da saída são hot links a serem selecionados. Selecione o link dados na saída da depuração para exibir informações sobre símbolos de itens iniciados com a letra a.

    0: kd> x /D /f tabletaudiosample!a*
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
    
    fffff806`9adb1000 tabletaudiosample!AddDevice (struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *)
    

    Para obter informações, confira x (examinar símbolos).

  4. A extensão !lmi mostra informações detalhadas sobre um módulo. Digite !lmi tabletaudiosample. A saída deverá ser semelhante ao texto a seguir.

    0: kd> !lmi tabletaudiosample
    Loaded Module Info: [tabletaudiosample] 
             Module: tabletaudiosample
       Base Address: fffff8069ad90000
         Image Name: tabletaudiosample.sys
       Machine Type: 34404 (X64)
         Time Stamp: 58ebe848 Mon Apr 10 13:17:12 2017
               Size: 48000
           CheckSum: 42df7
    Characteristics: 22  
    Debug Data Dirs: Type  Size     VA  Pointer
                 CODEVIEW    a7,  e5f4,    d1f4 RSDS - GUID: {5395F0C5-AE50-4C56-AD31-DD5473BD318F}
                   Age: 1, Pdb: C:\Windows-driver-samples-master\audio\sysvad\TabletAudioSample\x64\Debug\TabletAudioSample.pdb
                       ??   250,  e69c,    d29c [Data not mapped]
         Image Type: MEMORY   - Image read successfully from loaded memory.
        Symbol Type: PDB      - Symbols loaded successfully from image header.
                     C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb
           Compiler: Resource - front end [0.0 bld 0] - back end [14.0 bld 24210]
        Load Report: private symbols & lines, not source indexed 
                     C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb
    
  5. Use a extensão !dh para exibir informações de cabeçalho, conforme mostrado abaixo.

    0: kd> !dh tabletaudiosample 
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
        8664 machine (X64)
           9 number of sections
    5669DE8A time date stamp Thu Dec 10 12:20:26 2015
    
           0 file pointer to symbol table
           0 number of symbols
          F0 size of optional header
          22 characteristics
                Executable
                App can handle >2gb addresses
    ...
    

Seção 6: exibir informações sobre a árvore de dispositivos Plug and Play

Na Seção 6, você exibirá informações sobre o driver de dispositivo Sysvad de exemplo e onde ele reside 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 solução de problemas. Por exemplo, se um driver de dispositivo não residir na árvore de dispositivos, talvez exista um problema com a instalação do driver de dispositivo.

Para saber mais sobre a extensão de depuração do nó de dispositivo, confira !devnode.

<-No sistema host

  1. Para ver todos os nós de dispositivo na árvore de dispositivos Plug and Play, insira o comando !devnode 0 1. A execução desse comando pode levar um ou dois minutos. Durante esse tempo, "*Busy" será exibido na área de status do WinDbg.

    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 e procurar o nome do driver de dispositivo, sysvad.

    Caixa de diálogo Localizar com o termo 'sysvad' inserido no campo de pesquisa.

    Uma entrada de nó de dispositivo com um nome de sysvad_TabletAudioSample estará presente na saída !devnode para Syvad.

      DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0
        InstancePath is "ROOT\sysvad_TabletAudioSample\0000"
        ServiceName is "sysvad_tabletaudiosample"
        State = DeviceNodeStarted (0x308)
    ...
    

    Observe que os endereços PDO e DevNode são exibidos.

  3. Use o comando !devnode 0 1 sysvad_TabletAudioSample para exibir informações de Plug and Play associadas ao nosso driver de dispositivo Sysvad.

    0: kd> !devnode 0 1 sysvad_TabletAudioSample
    Dumping IopRootDeviceNode (= 0xffffe00082df8d30)
    DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0
      InstancePath is "ROOT\sysvad_TabletAudioSample\0000"
      ServiceName is "sysvad_tabletaudiosample"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe000897fb650 for PDO 0xffffe00089927e30
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{64097438-cdc0-4007-a19e-62e789062e20}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00086d2f5f0 for PDO 0xffffe00089939ae0
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{78880f4e-9571-44a4-a9df-960bde446487}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00089759bb0 for PDO 0xffffe000875aa060
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{7cad07f2-d0a0-4b9b-8100-8dc735e9c447}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00087735010 for PDO 0xffffe000872068c0
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{fc38551b-e69f-4b86-9661-ae6da78bc3c6}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00088457670 for PDO 0xffffe0008562b830
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{0894b831-c9fe-4c56-86a6-092380fc5628}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe000893dbb70 for PDO 0xffffe00089d68060
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{15eb6b5c-aa54-47b8-959a-0cff2c1500db}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00088e6f250 for PDO 0xffffe00089f6e990
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{778c07f0-af9f-43f2-8b8d-490024f87239}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe000862eb4b0 for PDO 0xffffe000884443a0
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{e4b72c7c-be50-45df-94f5-0f2922b85983}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
    
  4. A saída exibida no comando anterior inclui o PDO associado à instância em execução do nosso driver. Neste exemplo, é 0xffffe00089c575a0. Insira o comando !devobj<endereço PDO> para exibir informações de Plug and Play associadas ao driver de dispositivo Sysvad. Use o endereço PDO exibido pelo !devnode em seu computador, não o mostrado aqui.

    0: kd> !devobj 0xffffe00089c575a0
    Device object (ffffe00089c575a0) is for:
    0000004e \Driver\PnpManager DriverObject ffffe00082d47e60
    Current Irp 00000000 RefCount 65 Type 0000001d Flags 00001040
    SecurityDescriptor ffffc102b0f6d171 DevExt 00000000 DevObjExt ffffe00089c576f0 DevNode ffffe00086e68190 
    ExtensionFlags (0000000000)  
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe00088386a50 \Driver\sysvad_tabletaudiosample
    Device queue is not busy.
    
  5. A saída exibida no comando !devobj inclui o nome do dispositivo conectado: \Driver\sysvad_tabletaudiosample. Use o comando !drvobj com uma máscara de bits de 2 para exibir informações associadas ao dispositivo conectado.

    0: kd> !drvobj \Driver\sysvad_tabletaudiosample 2
    Driver object (ffffe0008834f670) is for:
    \Driver\sysvad_tabletaudiosample
    DriverEntry:   fffff80114b45310  tabletaudiosample!FxDriverEntry
    DriverStartIo: 00000000 
    DriverUnload:  fffff80114b5fea0                tabletaudiosample!DriverUnload
    AddDevice:     fffff80114b5f000  tabletaudiosample!AddDevice
    
    Dispatch routines:
    [00] IRP_MJ_CREATE                      fffff80117b49a20             portcls!DispatchCreate
    [01] IRP_MJ_CREATE_NAMED_PIPE           fffff8015a949a00          nt!IopInvalidDeviceRequest
    [02] IRP_MJ_CLOSE                       fffff80115e26f90                ks!DispatchCleanup
    [03] IRP_MJ_READ                        fffff80115e32710                ks!DispatchRead
    [04] IRP_MJ_WRITE                       fffff80115e327e0              ks!DispatchWrite
    [05] IRP_MJ_QUERY_INFORMATION           fffff8015a949a00         nt!IopInvalidDeviceRequest
    [06] IRP_MJ_SET_INFORMATION             fffff8015a949a00              nt!IopInvalidDeviceRequest
    [07] IRP_MJ_QUERY_EA                    fffff8015a949a00         nt!IopInvalidDeviceRequest
    [08] IRP_MJ_SET_EA                      fffff8015a949a00              nt!IopInvalidDeviceRequest
    [09] IRP_MJ_FLUSH_BUFFERS               fffff80115e32640  ks!DispatchFlush
    [0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff8015a949a00           nt!IopInvalidDeviceRequest
    [0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff8015a949a00               nt!IopInvalidDeviceRequest
    [0c] IRP_MJ_DIRECTORY_CONTROL           fffff8015a949a00           nt!IopInvalidDeviceRequest
    [0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff8015a949a00         nt!IopInvalidDeviceRequest
    [0e] IRP_MJ_DEVICE_CONTROL              fffff80115e27480               ks!DispatchDeviceIoControl
    [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff8015a949a00   nt!IopInvalidDeviceRequest
    [10] IRP_MJ_SHUTDOWN                    fffff8015a949a00      nt!IopInvalidDeviceRequest
    [11] IRP_MJ_LOCK_CONTROL                fffff8015a949a00  nt!IopInvalidDeviceRequest
    [12] IRP_MJ_CLEANUP                     fffff8015a949a00           nt!IopInvalidDeviceRequest
    [13] IRP_MJ_CREATE_MAILSLOT             fffff8015a949a00               nt!IopInvalidDeviceRequest
    [14] IRP_MJ_QUERY_SECURITY              fffff80115e326a0 ks!DispatchQuerySecurity
    [15] IRP_MJ_SET_SECURITY                fffff80115e32770      ks!DispatchSetSecurity
    [16] IRP_MJ_POWER                       fffff80117b3dce0            portcls!DispatchPower
    [17] IRP_MJ_SYSTEM_CONTROL              fffff80117b13d30              portcls!PcWmiSystemControl
    [18] IRP_MJ_DEVICE_CHANGE               fffff8015a949a00 nt!IopInvalidDeviceRequest
    [19] IRP_MJ_QUERY_QUOTA                 fffff8015a949a00  nt!IopInvalidDeviceRequest
    [1a] IRP_MJ_SET_QUOTA                   fffff8015a949a00       nt!IopInvalidDeviceRequest
    [1b] IRP_MJ_PNP                         fffff80114b5f7d0 tabletaudiosample!PnpHandler
    
  6. Digite o comando !devstack<endereço PDO> para exibir informações de Plug and Play associadas ao driver de dispositivo. A saída exibida no comando !devnode 0 1 inclui o endereço PDO associado à instância em execução do nosso driver. Neste exemplo, é 0xffffe00089c575a0. Use o endereço PDO exibido pelo !devnode em seu computador, não o mostrado abaixo.

    0: kd> !devstack 0xffffe00089c575a0
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe00088d212e0  \Driver\ksthunk    ffffe00088d21430  0000007b
      ffffe00088386a50  \Driver\sysvad_tabletaudiosampleffffe00088386ba0  0000007a
    > ffffe00089c575a0  \Driver\PnpManager 00000000  0000004e
    !DevNode ffffe00086e68190 :
      DeviceInst is "ROOT\sysvad_TabletAudioSample\0000"
      ServiceName is "sysvad_tabletaudiosample"
    

A saída mostra que temos uma pilha de driver de dispositivo muito simples. O driver sysvad_TabletAudioSample é filho do nó PnPManager. O PnPManager é um nó raiz.

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

Diagrama de uma árvore de nós do dispositivo com cerca de 20 nós.

Observação Para conhecer melhor pilhas de drivers mais complexas, confira Pilhas de drivers e Nós de dispositivo e pilhas de dispositivos.

Seção 7: trabalhar com pontos de interrupção

Na Seção 7, você trabalhará com pontos de interrupção para interromper a execução de código em pontos específicos.

Definir pontos de interrupção usando comandos

Os pontos de interrupção são usados para interromper a execução do código em uma linha de código específica. Você pode avançar no código a partir desse ponto para depurar essa seção de código específica.

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

bp

Define um ponto de interrupção que ficará ativo até o descarregamento do módulo em que reside.

bu

Define um ponto de interrupção que não é resolvido quando o módulo é descarregado e é reativado quando o módulo é recarregado.

bm

Define um ponto de interrupção para um símbolo. Esse comando usará bu ou bp de forma adequada e permite o uso de curingas * para definir pontos de interrupção em cada símbolo correspondente (como todos os métodos em uma classe).

  1. Use a interface do usuário do WinDbg para confirmar se Depurar>Modo de Origem está habilitado na sessão atual do WinDbg.

  2. Adicione a localização do seu código local ao caminho de origem digitando o comando a seguir.

    .sympath+ C:\WDK_Samples\Sysvad
    
  3. Adicione a localização do seu símbolo local ao caminho do símbolo digitando o comando a seguir.

    .sympath+ C:\WDK_Samples\Sysvad
    
  4. Definir a máscara de depuração

    Como você está trabalhando com um driver, pode ser útil ver todas as mensagens que ele pode exibir. 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
    
  5. Defina o ponto de interrupção com o comando bm usando o nome do driver, seguido do nome da função (AddDevice) onde você deseja definir o ponto de interrupção, separado por um ponto de exclamação.

    0: kd> bm tabletaudiosample!AddDevice
    breakpoint 1 redefined
      1: fffff801`14b5f000 @!"tabletaudiosample!AddDevice"
    

    Você pode usar sintaxes distintas associadas a variáveis de configuração, como <módulo>!<símbolo>, <classe>::<método>,'<file.cpp>:<número da linha>’, ou ignorar várias vezes <condição><#>. Para saber mais, confira Usar pontos de interrupção.

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

    0: kd> bl
    1 e fffff801`14b5f000     0001 (0001) tabletaudiosample!AddDevice
    
  7. Reinicie a execução do código no sistema de destino digitando o comando ir g.

  8. ->No sistema de destino

    No Windows, abra o Gerenciador de Dispositivos usando o ícone ou inserindo mmc devmgmt.msc. No Gerenciador de Dispositivos, expanda o nó Controladores de som, vídeo e jogos. Selecione e segure (ou clique com o botão direito do mouse) a entrada do driver de áudio virtual e selecione Desabilitar no menu.

  9. Selecione e segure (ou clique com o botão direito do mouse) a entrada do driver de áudio virtual novamente e selecione Habilitar no menu.

  10. <- No sistema host

    Isso deve fazer com que o Windows recarregue o driver, chamado AddDevice. Isso levará o ponto de interrupção de depuração AddDevice a ser acionado e à interrupção na execução do código do driver no sistema de destino.

    Breakpoint 1 hit
    tabletaudiosample!AddDevice:
    fffff801`14baf000 4889542410      mov     qword ptr [rsp+10h],rdx
    

    Se o caminho de origem estiver definido corretamente, você deverá parar na rotina AddDevice em adapter.cpp

    {
        PAGED_CODE();
    
        NTSTATUS        ntStatus;
        ULONG           maxObjects;
    
        DPF(D_TERSE, ("[AddDevice]"));
    
        maxObjects = g_MaxMiniports;
    
        #ifdef SYSVAD_BTH_BYPASS
        // 
        // Allow three (3) Bluetooth hands-free profile devices.
        //
        maxObjects += g_MaxBthHfpMiniports * 3; 
        #endif // SYSVAD_BTH_BYPASS
    
        // Tell the class driver to add the device.
        //
        ntStatus = 
            PcAddAdapterDevice
            ( 
                DriverObject,
                PhysicalDeviceObject,
                PCPFNSTARTDEVICE(StartDevice),
                maxObjects,
                0
            );
        return ntStatus;
    } // AddDevice
    
  11. Passe linha por linha o código digitando o comando p ou pressionando F10. Você pode avançar do código sysvad AddDevice para PpvUtilCall, PnpCallAddDevice e, depois, para o código PipCallDriverAddDevice do Windows. Você pode fornecer um número para o comando p para avançar várias linhas; por exemplo p 5.

  12. Quando terminar de percorrer o código, use o comando ir g para reiniciar a execução no sistema de destino.

Definir pontos de interrupção de acesso à memória

Também é possível definir pontos de interrupção acionados quando um local de memória é acessado. Use o comando ba (interrupção no acesso), com a sintaxe a seguir.

ba <access> <size> <address> {options}
Opção Descrição

e

execute (quando a CPU procura 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)

Note que você só pode definir quatro pontos de interrupção de dados de uma vez e cabe a você verificar se está alinhando seus dados corretamente ou não acionará o ponto de interrupção (as palavras devem terminar em endereços divisíveis por 2, dwords devem ser divisíveis por 4 e quadwords 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.

ba r 4 fffff800`7bc9eff0

Modificar o estado do ponto de interrupção

Você pode alterar os pontos de interrupção existentes com os comandos a seguir:

bl

Lista 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. Utilize be * para habilitar todos os pontos de interrupção.

Como alternativa, você também pode modificar pontos de interrupção selecionando editar>pontos de interrupção. Observe que a caixa de diálogo de ponto de interrupção só funciona com os pontos de interrupção existentes. Deve-se definir novos pontos de interrupção a partir da linha de comando.

Definir um ponto de interrupção no MixerVolume.

Partes do código do driver de áudio distintas são chamadas para responder a vários eventos, depois que o driver de dispositivo é carregado. Na próxima seção, definimos um ponto de interrupção que será acionado quando o usuário ajustar o controle de volume para o driver de áudio virtual.

Para definir um ponto de interrupção no MixerVolume, execute as etapas a seguir.

  1. <- No sistema host

    Para localizar o método que altera o volume, use o comando x para listar os símbolos em CAdapterCommon, que contêm o volume de cadeia de caracteres.

    kd> x tabletaudiosample!CAdapterCommon::*
    ...
    fffff800`7bce26a0 tabletaudiosample!CAdapterCommon::MixerVolumeWrite (unsigned long, unsigned long, long)
    …
    

    Use CTRL+F para pesquisar para cima na saída por volume e localize o método MixerVolumeWrite.

  2. Limpe os pontos de interrupção anteriores usando bc *.

  3. Defina um ponto de interrupção de símbolo na rotina CAdapterCommon::MixerVolumeWrite usando o comando a seguir.

    kd> bm tabletaudiosample!CAdapterCommon::MixerVolumeWrite
      1: fffff801`177b26a0 @!"tabletaudiosample!CAdapterCommon::MixerVolumeWrite"
    
  4. Liste os pontos de interrupção para confirmar se o ponto de interrupção está definido de forma adequada.

    kd> bl
    1 e fffff801`177b26a0 [c:\WDK_Samples\audio\sysvad\common.cpp @ 1668]    0001 (0001) tabletaudiosample!CAdapterCommon::MixerVolumeWrite
    
  5. Reinicie a execução do código no sistema de destino digitando o comando ir g.

  6. No Painel de controle, selecione Hardware e Som>Som. Selecione e segure (ou clique com o botão direito do mouse) Descrição do coletor de exemplo e selecione Propriedades. Selecione a guia Níveis. Ajuste o controle deslizante de volume.

  7. Isso deve fazer com que o ponto de interrupção de depuração SetMixerVolume seja acionado e deve-se interromper a execução do código do driver no sistema de destino.

    kd> g
    Breakpoint 1 hit
    tabletaudiosample!CAdapterCommon::MixerVolumeWrite:
    fffff801`177b26a0 44894c2420      mov     dword ptr [rsp+20h],r9d
    

    Você deve parar nesta linha em common.cpp

    {
        if (m_pHW)
        {
            m_pHW->SetMixerVolume(Index, Channel, Value);
        }
    } // MixerVolumeWrite
    
  8. Use o comando dv para exibir as variáveis atuais e os valores. Na próxima seção deste laboratório, você encontra mais informações sobre variáveis.

    2: kd> dv
               this = 0x00000000`00000010
             ulNode = 0x344
          ulChannel = 0x210a45f8
            lVolume = 0n24
    
  9. Pressione F10 para percorrer o código.

  10. Pressione F5 para concluir a execução do código MixerVolumeWrite.

Resumo: percorrer o código a partir da janela Comando do depurador

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

  • Invadir (Ctrl+Break): este comando interromperá um sistema enquanto o sistema estiver em execução e em comunicação com o WinDbg (a sequência no Depurador de kernel é Ctrl+C).

  • Contornar (F10): esse comando faz com que a execução do código prossiga com uma instrução por vez. Se uma chamada for encontrada, a execução de código passará a chamada sem entrar na rotina que foi 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 Depurar>Modo de origem).

  • Entrar (F11): esse comando é como contornar, exceto pelo fato da execução de uma chamada entrar na rotina que foi chamada.

  • Sair (Shift+F11): esse comando faz com que a execução aconteça e saia da rotina atual (local atual na pilha de chamadas). Isso será útil se você já tiver visto o suficiente da rotina.

  • Executar até o cursor (F7 ou Ctrl+F10): coloque o cursor em uma janela de origem ou desmontagem onde você deseja que a execução seja interrompida e pressione F7. A execução do código acontecerá até esse ponto. Observe que se o fluxo de execução do código não atingir o ponto indicado pelo cursor (por exemplo, uma instrução IF não for executada), o WinDbg não será interrompido, porque a execução do código não atingiu o ponto indicado.

  • Executar (F5): executa até encontrar um ponto de interrupção ou até que ocorra um evento como uma verificação de depuração.

Opções avançadas

  • Definir instrução para a linha atual (Ctrl+Shift+I): em uma janela de origem, você pode colocar o cursor em uma linha, inserir esse atalho de teclado e a execução do código começará a partir desse ponto assim que você permitir que ele prossiga (por exemplo, usando F5 ou F10). Isso é útil se você quiser tentar novamente uma sequência, mas requer alguns cuidados. Por exemplo, registradores e variáveis não são definidos para o que seriam se a execução do código tivesse atingido essa linha naturalmente.

  • Configuração direta do registro eip: você pode colocar um valor no registro eip e, assim que pressionar F5 (ou F10, F11 etc.), a execução começa a partir desse endereço. Isso é semelhante à configuração de instruções para a linha atual designada pelo cursor, exceto que você especifica o endereço de uma instrução de assembly.

Pode ser mais fácil percorrer a interface do usuário em vez da linha de comando, portanto, esse método é recomendado. Se necessário, os seguintes comandos podem ser usados para percorrer um arquivo de origem na linha de comando:

  • .lines: habilitar informações da linha de origem.

  • bp main: definir o ponto de interrupção inicial no começo do módulo.

  • l+t: o passo a passo será feito por linha de origem.

  • Selecione Depurar>Modo de origem para entrar no modo de origem, o L+t comando não é suficiente.

  • l+s: as linhas de origem serão exibidas no prompt.

  • g: executar o programa até que "principal" seja inserido.

  • p: executar uma linha de origem.

Para saber mais, confira Depuração de código-fonte no WinDbg (clássico) na documentação de referência de depuração.

Definir os pontos de interrupção no código

Para definir um ponto de interrupção no código, você pode adicionar a instrução DebugBreak(), recriar o projeto e reinstalar o driver. Esse ponto de interrupção será acionado sempre que o driver for habilitado; portanto, esta seria uma técnica a ser usada nos estágios iniciais de desenvolvimento, não no código de produção. Essa técnica não é tão flexível quanto definir pontos de interrupção de forma dinâmica por meio dos comandos de ponto de interrupção.

Dica: você pode querer manter uma cópia do driver Sysvad sem o ponto de interrupção adicionado para trabalho de laboratório posterior.

  1. Defina uma interrupção para ocorrer sempre que o método AddDevice for executado adicionando a instrução DebugBreak() ao código de exemplo.

    ...
        // Insert the DebugBreak() statment before the  PcAddAdapterDevice is called.
        //
    
        DebugBreak()
    
        // Tell the class driver to add the device.
        //
        ntStatus = 
            PcAddAdapterDevice
            ( 
                DriverObject,
                PhysicalDeviceObject,
                PCPFNSTARTDEVICE(StartDevice),
                maxObjects,
                0
            );
    
        return ntStatus;
    } // AddDevice
    
  2. Siga todas as etapas descritas anteriormente para recriar o driver no Microsoft Visual Studio e reinstalá-lo no computador de destino. Verifique se desinstalou o driver existente antes de instalar o driver atualizado.

  3. Limpe todos os pontos de interrupção anteriores e verifique se o depurador está conectado ao computador de destino.

  4. Quando o código for executado e atingir a instrução DebugBreak, a execução será interrompida e uma mensagem aparecerá.

    KERNELBASE!DebugBreak:
    77b3b770 defe     __debugbreak
    

Seção 8: exibir variáveis

Na Seção 8, você usará comandos do depurador para exibir variáveis.

Pode ser útil examinar variáveis à medida que o código é executado para confirmar que o código está funcionando conforme o esperado. Este laboratório examina variáveis à medida que o driver de áudio produz som.

  1. Use o comando dv para examinar as variáveis locais associadas ao tabletaudiosample!CMiniportWaveRT::New*.

    kd> dv tabletaudiosample!CMiniportWaveRT::New*
    
  2. Limpar os pontos de interrupção anteriores

    bc *
    
  3. Defina um ponto de interrupção de símbolo nas rotinas CMiniportWaveCyclicStreamMSVAD com o comando a seguir.

    0: kd> bm tabletaudiosample!CMiniportWaveRT::NewStream
      1: fffff801`177dffc0 @!"tabletaudiosample!CMiniportWaveRT::NewStream"
    
  4. Reinicie a execução do código no sistema de destino digitando o comando ir g.

  5. -> No sistema de destino

    Localize um pequeno arquivo de mídia (como o arquivo de som de notificação do Windows com uma extensão .wav) e selecione-o para reproduzi-lo. Por exemplo, você pode usar o Ring05.wav localizado no diretório Windows\Media.

  6. <- No sistema host

    Quando o arquivo de mídia é reproduzido, o ponto de interrupção deve ser acionado e a execução do código do driver no sistema de destino deve ser interrompida.

    Breakpoint 1 hit
    tabletaudiosample!CMiniportWaveRT::NewStream:
    fffff801`177dffc0 44894c2420      mov     dword ptr [rsp+20h],r9d
    

    A janela do código-fonte deve realçar a chave na entrada da função NewStream.

    /*++
    
    Routine Description:
    
      The NewStream function creates a new instance of a logical stream 
      associated with a specified physical channel. Callers of NewStream should 
      run at IRQL PASSIVE_LEVEL.
    
    Arguments:
    
      OutStream -
    
      OuterUnknown -
    
      Pin - 
    
      Capture - 
    
      DataFormat -
    
    Return Value:
    
      NT status code.
    
    --*/
    {
    
    ...
    
  7. Variáveis locais

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

    0: kd> dv
                    this = 0xffffe000`4436f8e0
               OutStream = 0xffffe000`49d2f130
            OuterUnknown = 0xffffe000`4436fa30
                     Pin = 0
                 Capture = 0x01 '
              DataFormat = 0xffffe000`44227790
    signalProcessingMode = {487E9220-E000-FFFF-30F1-D24900E0FFFF}
                ntStatus = 0n1055
                  stream = 0x00000000`00000200
    
  8. Usar DML para exibir variáveis

    Para usar DML para explorar variáveis, selecione os elementos sublinhados. A ação de seleção cria um comando dx (exibir expressão NatVis) que permite detalhar estruturas de dados aninhadas.

    0: kd> dx -r1 (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380))
    (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380)) :  [Type: CMiniportWaveRT]
        [+0x020] m_lRefCount      : 0
        [+0x028] m_pUnknownOuter  : 0xffffe001d1477e50 : [Type: IUnknown *]
        [+0x030] m_ulLoopbackAllocated : 0x2050
        [+0x034] m_ulSystemAllocated : 0x180
        [+0x038] m_ulOffloadAllocated : 0x0
        [+0x03c] m_dwCaptureAllocatedModes : 0x0
    
    0: kd> dx -r1 (*((tabletaudiosample!_GUID *)0xffffd001c8acd348))
    (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) : {487E9220-E000-FFFF-30F1-D24900E0FFFF} [Type: _GUID]
        [<Raw View>]    
    
    0: kd> dx -r1 -n (*((tabletaudiosample!_GUID *)0xffffd001c8acd348))
    (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) :  [Type: _GUID]
        [+0x000] Data1            : 0x487e9220
        [+0x004] Data2            : 0xe000
        [+0x006] Data3            : 0xffff
        [+0x008] Data4            :  [Type: unsigned char [8]]
    
    0: kd> dx -r1 -n (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350))
    (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350)) :  [Type: unsigned char [8]]
        [0]              : 0x30
        [1]              : 0xf1
        [2]              : 0xd2
        [3]              : 0x49
        [4]              : 0x0
        [5]              : 0xe0
        [6]              : 0xff
        [7]              : 0xff
    
  9. Variáveis globais

    Você pode encontrar o local de memória de uma variável global digitando ? <nome da variável>.

    0: kd> ? signalProcessingMode
    Evaluate expression: -52768896396472 = ffffd001`c8acd348
    
  10. Isso retorna o local de memória da variável. Neste caso, ffffd001'c8acd348. Você pode exibir o conteúdo do local de memória despejando o valor desse local ao digitar o comando dd por meio do local de memória retornado pelo comando anterior.

    0: kd> dd ffffd001`c8acd348
    ffffd001`c8acd348  487e9220 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd358  4837c468 ffffe000 18221570 ffffc000
    ffffd001`c8acd368  4436f8e0 ffffe000 487e9220 ffffe000
    ffffd001`c8acd378  18ab145b fffff801 4837c420 ffffe000
    ffffd001`c8acd388  4436f8e0 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd398  4436fa30 ffffe000 00000000 00000000
    ffffd001`c8acd3a8  00000001 00000000 44227790 ffffe000
    ffffd001`c8acd3b8  18adc7f9 fffff801 495972a0 ffffe000
    
  11. Você também pode usar nomes de variáveis com o comando dd.

    0: kd> dd signalProcessingMode
    ffffd001`c8acd348  487e9220 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd358  4837c468 ffffe000 18221570 ffffc000
    ffffd001`c8acd368  4436f8e0 ffffe000 487e9220 ffffe000
    ffffd001`c8acd378  18ab145b fffff801 4837c420 ffffe000
    ffffd001`c8acd388  4436f8e0 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd398  4436fa30 ffffe000 00000000 00000000
    ffffd001`c8acd3a8  00000001 00000000 44227790 ffffe000
    ffffd001`c8acd3b8  18adc7f9 fffff801 495972a0 ffffe000
    
  12. Exibir variáveis

    Use o item de menu Exibir>Locais para exibir variáveis locais. Essa interface também fornece a capacidade de detalhar estruturas de dados mais complexas.

    Interface WinDbg que exibe os locais de código de exemplo e as janelas de comando.

  13. Use p ou F10 para avançar cerca de 10 linhas no código até realçar a linha de código ntStatus = IsFormatSupported(Pin, Capture, DataFormat);.

        PAGED_CODE();
    
        ASSERT(OutStream);
        ASSERT(DataFormat);
    
        DPF_ENTER(("[CMiniportWaveRT::NewStream]"));
    
        NTSTATUS                    ntStatus = STATUS_SUCCESS;
        PCMiniportWaveRTStream      stream = NULL;
        GUID                        signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
    
        *OutStream = NULL;
    
         //
        // If the data format attributes were specified, extract them.
        //
        if ( DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES )
        {
            // The attributes are aligned (QWORD alignment) after the data format
            PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
            ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode);
        }
    
        // Check if we have enough streams.
        //
        if (NT_SUCCESS(ntStatus))
        {
            ntStatus = ValidateStreamCreate(Pin, Capture, signalProcessingMode);
        }
    
        // Determine if the format is valid.
        //
        if (NT_SUCCESS(ntStatus))
        {
            ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
        }
    
    ...
    
  14. Use o comando dv para exibir os nomes e valores de todas as variáveis locais para um quadro específico. Observe que, como esperado, os valores diferem da última vez que executamos este comando, pois foi executado um código adicional que altera as variáveis locais. Algumas variáveis agora não estão no quadro atual ou houve alteração nos valores.

    2: kd> dv
                    this = 0xffffe001`d1182000
               OutStream = 0xffffe001`d4776d20
            OuterUnknown = 0xffffe001`d4776bc8
                     Pin = 0
                 Capture = 0x00 '
              DataFormat = 0xffffe001`cd7609b0
    signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE}
                ntStatus = 0n0
                  stream = 0x00000000`00000000
    

Seção 9: exibir pilhas de chamadas

Na seção 9, você exibirá pilhas de chamadas para examinar o código do chamador/chamado.

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

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

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 do quadro ao lado dela.

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

Interface WinDbg exibindo a janela da pilha de chamadas.

Essa saída mostra a pilha de chamadas enquanto depura o código do adaptador de exemplo em um estado de interrupção.

0: kd> kb
# RetAddr           : Args to Child                                                           : Call Site
00 fffff800`7a0fa607 : ffffe001`d1182000 ffffe001`d4776d20 ffffe001`d4776bc8 ffffe001`00000000 : tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
01 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d122bb10 ffffe001`ceb81750 ffffe001`d173f058 : portcls!CPortPinWaveRT::Init+0x2e7
02 fffff800`7a0fc7f9 : ffffe001`d4776bc0 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
04 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
05 fffff800`7bd314b1 : ffffe001`d122bb10 ffffd001`c3098590 ffffe001`d122bd90 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
06 fffff803`cda1bfa8 : 00000000`00000024 00000000`00000000 00000000`00000000 ffffe001`d122bb10 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 fffff803`cda7b306 : 00000000`000001f0 ffffe001`d48ce690 ffffe001`d13d6400 ffffe001`d13d64c0 : nt!IopParseDevice+0x7c8
08 fffff803`cda12916 : 00000000`000001f0 ffffd001`c30988d0 ffffe001`d13d6490 fffff803`cda7b250 : nt!IopParseFile+0xb6
09 fffff803`cda1131c : ffffe001`d2ccb001 ffffd001`c30989e0 00ffffe0`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
0a fffff803`cd9fedb8 : ffffe001`00000001 ffffe001`d48ce690 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
0b fffff803`cd9fe919 : 000000ee`6d1fc8d8 000000ee`6d1fc788 000000ee`6d1fc7e0 000000ee`6d1fc7d0 : nt!IopCreateFile+0x3d8
0c fffff803`cd752fa3 : ffffc000`1f296870 fffff803`cd9d9fbd ffffd001`c3098be8 00000000`00000000 : nt!NtCreateFile+0x79
0d 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
0e 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
0f 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
10 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
11 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e

Você pode usar a DML para explorar ainda mais o código. Quando você seleciona a primeira entrada 00, o comando .frame (definir contexto local) é usado para definir o contexto e, depois, o comando dv (exibir variáveis locais) exibe as variáveis locais.

0: kd> .frame 0n0;dv /t /v
00 ffffd001`c30981d0 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
ffffd001`c30982b0 class CMiniportWaveRT * this = 0xffffe001`d1182000
ffffd001`c30982b8 struct IMiniportWaveRTStream ** OutStream = 0xffffe001`d4776d20
ffffd001`c30982c0 struct IPortWaveRTStream * OuterUnknown = 0xffffe001`d4776bc8
ffffd001`c30982c8 unsigned long Pin = 0
ffffd001`c30982d0 unsigned char Capture = 0x00 '
ffffd001`c30982d8 union KSDATAFORMAT * DataFormat = 0xffffe001`cd7609b0
ffffd001`c3098270 struct _GUID signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE}
ffffd001`c3098210 long ntStatus = 0n0
ffffd001`c3098218 class CMiniportWaveRTStream * stream = 0x00000000`00000000

Seção 10: exibir processos e threads

Na seção 10, você usará comandos do depurador para exibir processos e threads.

Processo

Para alterar o contexto do processo atual, use o comando .process <processo>. O exemplo a seguir demonstra como identificar um processo e alternar o contexto dele.

  • Use o comando !process para exibir o processo atual envolvido na reprodução do som.

    Para saber mais, confira !process

A saída mostra que o processo está associado ao audiodg.exe. Se você ainda estiver no ponto de interrupção descrito na seção anterior deste tópico, o processo atual deverá estar associado à imagem audiodg.exe.

<- No sistema host

0: kd> !process
PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
    VadRoot ffffe001d4222f70 Vads 70 Clone 0 Private 504. Modified 16. Locked 0.
    DeviceMap ffffc00019113080
    Token                             ffffc0001f1d4060
    ElapsedTime                       <Invalid>
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         81632
    QuotaPoolUsage[NonPagedPool]      9704
    Working Set Sizes (now,min,max)  (2154, 1814, 2109) (8616KB, 7256KB, 8436KB)
    PeakWorkingSetSize                2101
    VirtualSize                       2097192 Mb
    PeakVirtualSize                   2097192 Mb
    PageFaultCount                    2336
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      1573

        THREAD ffffe001d173e840  Cid 10f0.1dac  Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
            ffffe001d16c4dd0  NotificationEvent
            ffffe001d08b0840  ProcessObject

        THREAD ffffe001ceb77080  Cid 10f0.16dc  Teb: 000000ee6cf8d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001d112c840  Cid 10f0.0a4c  Teb: 000000ee6cf8f000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001d16c7840  Cid 10f0.13c4  Teb: 000000ee6cf91000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001cec67840  Cid 10f0.0dbc  Teb: 000000ee6cf93000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject

        THREAD ffffe001d1117840  Cid 10f0.1d6c  Teb: 000000ee6cf95000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject

        THREAD ffffe001cdeae840  Cid 10f0.0298  Teb: 000000ee6cf97000 Win32Thread: 0000000000000000 RUNNING on processor 2

Observe que um dos threads associados a esse processo está no estado EM EXECUÇÃO. Esse thread dava suporte à reprodução do clipe de mídia quando o ponto de interrupção foi atingido.

Use o comando !process 0 0 para exibir informações de resumo de todos os processos. Na saída do comando, use CTRL+F para localizar a ID do processo associado à imagem do audiodg.exe. No exemplo mostrado abaixo, a ID do processo é ffffe001d147c840.

Registre a ID do processo associada ao audiodg.exe em seu computador para usar mais adiante neste laboratório. ________________________

...

PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
...

Insira g no depurador para executar o código até que termine a reprodução do clipe de mídia. Entre no depurador pressionando Ctrl+ScrLk (Ctrl+Break). Use o comando !process para confirmar que agora você está executando um processo distinto.

!process
PROCESS ffffe001cd0ad040
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 001aa000  ObjectTable: ffffc00017214000  HandleCount: <Data Not Accessible>
    Image: System
    VadRoot ffffe001d402b820 Vads 438 Clone 0 Private 13417. Modified 87866. Locked 64.
    DeviceMap ffffc0001721a070
    Token                             ffffc00017216a60
    ElapsedTime                       05:04:54.716
    UserTime                          00:00:00.000
    KernelTime                        00:00:20.531
    QuotaPoolUsage[PagedPool]         0
    QuotaPoolUsage[NonPagedPool]      0
    Working Set Sizes (now,min,max)  (1720, 50, 450) (6880KB, 200KB, 1800KB)
    PeakWorkingSetSize                15853
    VirtualSize                       58 Mb
    PeakVirtualSize                   74 Mb
    PageFaultCount                    46128
   MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      66

        THREAD ffffe001cd0295c0  Cid 0004.000c  Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
            fffff803cd8e0120  SynchronizationEvent

        THREAD ffffe001cd02a6c0  Cid 0004.0010  Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
            fffff803cd8e0ba0  Semaphore Limit 0x7fffffff
...

A saída acima mostra que há um processo de sistema ffffe001cd0ad040 distinto em execução. O nome da imagem mostra Sistema, não audiodg.exe.

Agora use o comando !process e alterne para o processo que foi associado a audiodg.exe. No exemplo, a ID do processo é ffffe001d147c840. Substitua a ID do processo no exemplo pela sua ID do processo, registrada anteriormente.

0: kd> !process  ffffe001d147c840
PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
    VadRoot ffffe001d4222f70 Vads 60 Clone 0 Private 299. Modified 152. Locked 0.
    DeviceMap ffffc00019113080
    Token                             ffffc0001f1d4060
    ElapsedTime                       1 Day 01:53:14.490
    UserTime                          00:00:00.031
    KernelTime                        00:00:00.031
    QuotaPoolUsage[PagedPool]         81552
    QuotaPoolUsage[NonPagedPool]      8344
    Working Set Sizes (now,min,max)  (1915, 1814, 2109) (7660KB, 7256KB, 8436KB)
    PeakWorkingSetSize                2116
    VirtualSize                       2097189 Mb
    PeakVirtualSize                   2097192 Mb
    PageFaultCount                    2464
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      1418

        THREAD ffffe001d173e840  Cid 10f0.1dac  Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
            ffffe001d16c4dd0  NotificationEvent
            ffffe001d08b0840  ProcessObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      338852         Ticks: 197682 (0:00:51:28.781)
        Context Switch Count      36             IdealProcessor: 0             
        UserTime                  00:00:00.015
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007ff7fb928de0
        Stack Init ffffd001c2ec6dd0 Current ffffd001c2ec60c0
        Base ffffd001c2ec7000 Limit ffffd001c2ec1000 Call 0
        Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

        THREAD ffffe001d115c080  Cid 10f0.15b4  Teb: 000000ee6cf9b000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d0bf0640  QueueObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      338852         Ticks: 197682 (0:00:51:28.781)
        Context Switch Count      1              IdealProcessor: 0             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007fff6978b350
        Stack Init ffffd001c3143dd0 Current ffffd001c3143520
        Base ffffd001c3144000 Limit ffffd001c313e000 Call 0
        Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

        THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      518918         Ticks: 17616 (0:00:04:35.250)
        Context Switch Count      9              IdealProcessor: 1             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007fff6978b350
        Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
        Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
        Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

Como esse código não está ativo, todos os threads estão no estado de ESPERA, conforme esperado.

Threads

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

Para explorar threads associados ao Player de Mídia, reproduza o clipe de mídia novamente. Se o ponto de interrupção descrito na seção anterior ainda estiver em vigor, você interromperá no contexto do audiodg.exe.

Use o !thread -1 0 para exibir informações breves para o thread atual. Isso mostra o endereço do thread, as IDs de thread e processo, o endereço TEB (bloco de ambiente de thread), o endereço da função Win32 (se houver) na qual o thread foi criado para executar e o estado de agendamento do thread.

0: kd> !thread -1 0
THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0

Para exibir mais informações sobre o thread em execução, digite !thread. Devem ser exibidas informações similares às mostradas aqui.

0: kd> !thread
THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0
IRP List:
    ffffe001d429e580: (0006,02c8) Flags: 000008b4  Mdl: 00000000
Not impersonating
DeviceMap                 ffffc00019113080
Owning Process            ffffe001d147c840       Image:         audiodg.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      537630         Ticks: 0
Context Switch Count      63             IdealProcessor: 1             
UserTime                  00:00:00.000
KernelTime                00:00:00.015
Win32 Start Address 0x00007fff6978b350
Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Child-SP          RetAddr           : Args to Child                                                           : Call Site
ffffd001`c70c62a8 fffff800`7a0fa607 : ffffe001`d4aec5c0 ffffe001`cdefd3d8 ffffe001`d4aec5c0 ffffe001`cdefd390 : tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
ffffd001`c70c62b0 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d429e580 ffffe001`d4ea47b0 ffffe001`cdefd3d8 : portcls!CPortPinWaveRT::Init+0x2e7
ffffd001`c70c6340 fffff800`7a0fc7f9 : ffffe001`d4aec430 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
ffffd001`c70c63c0 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
ffffd001`c70c6450 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
ffffd001`c70c6510 fffff800`7bd314b1 : ffffe001`d429e580 ffffd001`c70c6590 ffffe001`d429e800 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
ffffd001`c70c6540 fffff803`cda1bfa8 : 00000000`00000025 00000000`00000000 00000000`00000000 ffffe001`d429e580 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
ffffd001`c70c65a0 fffff803`cda7b306 : 00000000`000002fc ffffe001`d5e0d510 00000000`00000000 ffffe001`d3341bd0 : nt!IopParseDevice+0x7c8
ffffd001`c70c6770 fffff803`cda12916 : 00000000`000002fc ffffd001`c70c68d0 ffffe001`d3341ba0 fffff803`cda7b250 : nt!IopParseFile+0xb6
ffffd001`c70c67d0 fffff803`cda1131c : ffffe001`ceb6c601 ffffd001`c70c69e0 00000000`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
ffffd001`c70c6970 fffff803`cd9fedb8 : ffff8ab8`00000001 ffffe001`d5e0d510 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
ffffd001`c70c6a90 fffff803`cd9fe919 : 000000ee`6d37c6e8 00000004`6d37c500 000000ee`6d37c5f0 000000ee`6d37c5e0 : nt!IopCreateFile+0x3d8
ffffd001`c70c6b40 fffff803`cd752fa3 : fffff6fb`7da05360 fffff6fb`40a6c0a8 fffff681`4d815760 ffff8ab8`92895e23 : nt!NtCreateFile+0x79
ffffd001`c70c6bd0 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`c70c6c40)
000000ee`6d37c568 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
000000ee`6d37c570 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
000000ee`6d37c578 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
000000ee`6d37c580 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e

Use o comando k para exibir a pilha de chamadas associada ao thread.

0: kd> k
# Child-SP          RetAddr           Call Site
00 ffffd001`c70c62a8 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
01 ffffd001`c70c62b0 fffff800`7a0fb2c3 portcls!CPortPinWaveRT::Init+0x2e7
02 ffffd001`c70c6340 fffff800`7a0fc7f9 portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 ffffd001`c70c63c0 fffff800`7a180552 portcls!xDispatchCreate+0xd9
04 ffffd001`c70c6450 fffff800`7a109a9a ks!KsDispatchIrp+0x272
05 ffffd001`c70c6510 fffff800`7bd314b1 portcls!DispatchCreate+0x7a
06 ffffd001`c70c6540 fffff803`cda1bfa8 ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 ffffd001`c70c65a0 fffff803`cda7b306 nt!IopParseDevice+0x7c8
08 ffffd001`c70c6770 fffff803`cda12916 nt!IopParseFile+0xb6
09 ffffd001`c70c67d0 fffff803`cda1131c nt!ObpLookupObjectName+0x776
0a ffffd001`c70c6970 fffff803`cd9fedb8 nt!ObOpenObjectByNameEx+0x1ec
0b ffffd001`c70c6a90 fffff803`cd9fe919 nt!IopCreateFile+0x3d8
0c ffffd001`c70c6b40 fffff803`cd752fa3 nt!NtCreateFile+0x79
0d ffffd001`c70c6bd0 00007fff`69805b74 nt!KiSystemServiceCopyEnd+0x13
0e 000000ee`6d37c568 00007fff`487484e6 0x00007fff`69805b74
0f 000000ee`6d37c570 0000029b`00000003 0x00007fff`487484e6
10 000000ee`6d37c578 00000000`0000012e 0x0000029b`00000003
11 000000ee`6d37c580 00000000`00000000 0x12e

Insira g no depurador para executar o código até que termine a reprodução do clipe de mídia. Entre no depurador, pressionando Ctrl - ScrLk (Ctrl-Break). Use o comando !thread para confirmar que agora você está executando um thread distinto.

0: kd> !thread
THREAD ffffe001ce80b840  Cid 17e4.01ec  Teb: 00000071fa9b9000 Win32Thread: ffffe001d41690d0 RUNNING on processor 0
Not impersonating
DeviceMap                 ffffc0001974e2c0
Owning Process            ffffe001d1760840       Image:         rundll32.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      538040         Ticks: 0
Context Switch Count      3181840        IdealProcessor: 0             
UserTime                  00:00:08.250
KernelTime                00:00:10.796
Win32 Start Address 0x00007ff6d2f24270
Stack Init ffffd001cd16afd0 Current ffffd001cd16a730
Base ffffd001cd16b000 Limit ffffd001cd165000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5

Child-SP          RetAddr           : Args to Child                                                           : Call Site
fffff803`cf373d18 fffff800`7a202852 : fffff803`cf373e60 00000000`00000001 ffffe001`cf4ed330 00000000`0000ffff : nt!DbgBreakPointWithStatus
fffff803`cf373d20 fffff803`cd6742c6 : ffffe001`cf4ed2f0 fffff803`cf373e60 00000000`00000001 00000000`0004e4b8 : kdnic!TXSendCompleteDpc+0x142
fffff803`cf373d60 fffff803`cd74d495 : 00000000`00000000 fffff803`cd923180 fffff803`cde1f4b0 fffff901`40669010 : nt!KiRetireDpcList+0x5f6
fffff803`cf373fb0 fffff803`cd74d2a0 : 00000000`00000090 0000000e`0000006a 00000000`00000092 00000000`00000000 : nt!KxRetireDpcList+0x5 (TrapFrame @ fffff803`cf373e70)
ffffd001`cd16a6c0 fffff803`cd74bd75 : 00000000`00000000 fffff803`cd74a031 00000000`00000000 00000000`00000000 : nt!KiDispatchInterruptContinue
ffffd001`cd16a6f0 fffff803`cd74a031 : 00000000`00000000 00000000`00000000 ffffe001`cff4d2a0 fffff803`cd67738e : nt!KiDpcInterruptBypass+0x25
ffffd001`cd16a700 fffff960`50cdb5a4 : fffff901`400006d0 00000000`00000001 fffff901`40000d60 ffffd001`cd16a9f0 : nt!KiInterruptDispatchNoLockNoEtw+0xb1 (TrapFrame @ ffffd001`cd16a700)
ffffd001`cd16a890 fffff960`50c66b2f : 00000000`00000000 fffff901`40669010 fffff901`42358580 fffff901`40000d60 : win32kfull!Win32FreePoolImpl+0x34
ffffd001`cd16a8c0 fffff960`50c68cd6 : 00000000`00000000 ffffd001`cd16a9f0 fffff901`400006d0 fffff901`400c0460 : win32kfull!EXLATEOBJ::vAltUnlock+0x1f
ffffd001`cd16a8f0 fffff803`cd752fa3 : 00000000`00000000 00000000`00000000 ffffe001`ce80b840 00000000`00000000 : win32kfull!NtGdiAlphaBlend+0x1d16
ffffd001`cd16add0 00007fff`674c1494 : 00007fff`674b1e97 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`cd16ae40)
00000071`fa74c9a8 00007fff`674b1e97 : 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 00000000`00ffffff : 0x00007fff`674c1494
00000071`fa74c9b0 0000a7c6`daee0559 : 00000000`00000001 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 : 0x00007fff`674b1e97
00000071`fa74c9b8 00000000`00000001 : 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 00000000`01010bff : 0x0000a7c6`daee0559
00000071`fa74c9c0 0000020b`741f3c50 : 00000000`00ffffff 00000000`00000030 00000000`01010bff 00000000`00000000 : 0x1
00000071`fa74c9c8 00000000`00ffffff : 00000000`00000030 00000000`01010bff 00000000`00000000 00000000`000000c0 : 0x0000020b`741f3c50
00000071`fa74c9d0 00000000`00000030 : 00000000`01010bff 00000000`00000000 00000000`000000c0 00000000`00000030 : 0xffffff
00000071`fa74c9d8 00000000`01010bff : 00000000`00000000 00000000`000000c0 00000000`00000030 00000071`00000030 : 0x30
00000071`fa74c9e0 00000000`00000000 : 00000000`000000c0 00000000`00000030 00000071`00000030 00000071`01ff8000 : 0x1010bff

O nome da imagem é rundll32.exe que, na verdade, não é o nome da imagem associada à reprodução do clipe de mídia.

Observação Para definir o thread atual, digite .thread <número do thread>.

Para saber mais sobre threads e processos, confira as seguintes referências:

Threads e processos

Alterar contextos

Seção 11: IRQL, registros e desmontagem

Exibir o IRQL salvo

Na seção 11, você exibirá o IRQL e o conteúdo dos registros.

<- No sistema host

O IRQL (nível de solicitação de interrupção) é usado para gerenciar a prioridade do serviço de interrupção. Cada processador tem uma configuração de IRQL que pode aumentar ou diminuir por meio de threads. As interrupções que ocorrem na configuração IRQL do processador ou abaixo dela são mascaradas e não interferirão na operação atual. As interrupções acima da configuração IRQL do processador têm precedência sobre a operação atual. A extensão !irql mostra o IRQL (nível de solicitação de interrupção) no processador atual do computador de destino antes da interrupção do depurador. Quando o computador de destino entra no depurador, o IRQL é alterado, mas o IRQL que estava ativo antes da interrupção do depurador é salvo e exibido por !irql.

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

<Exibir os registros e desmontar

Exibir os registros

Exiba o conteúdo dos registros para o thread atual no processador atual por meio do 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

Outra alternativa é exibir o conteúdo dos registros selecionando Exibir>Registros.

Captura de tela da janela de registros do WinDbg exibindo em torno de 12 registros.

A exibição do conteúdo dos registros pode ser útil ao percorrer a execução do código de linguagem assembly e em outros cenários. Para saber mais, confira r (Registros).

Para saber mais sobre o conteúdo do registro, confira arquitetura x86 e arquitetura x64.

Desmontagem

Para desmontar o código em execução para exibir o código de linguagem assembly executado, selecione Exibir>Desmontagem.

Captura de tela da janela de desmontagem do WinDbg mostrando o código de linguagem assembly.

Para saber mais sobre a desmontagem de linguagem assembly, confira Desmontagem x86 anotada e Desmontagem x64 anotada.

Seção 12: trabalhar com memória

Na seção 12, você usará comandos do depurador para exibir o conteúdo da memória.

Exibir memória

Talvez seja necessário examinar a memória para identificar um problema ou inspecionar variáveis, ponteiros e assim por diante. Você pode exibir a memória digitando um dos comandos d* <endereço> a seguir.

db

Exibe dados em valores de bytes e caracteres ASCII.

dd

Exibe dados como palavras de largura dupla (4 bytes).

du

Exibe dados como caracteres Unicode.

dw

Exibe dados como valores de palavra (2 bytes) e caracteres ASCII.

Observação Se você tentar exibir um endereço inválido, o conteúdo aparecerá como pontos de interrogação (?).

Outra alternativa é exibir a memória selecionando Exibir>Memória. Use o menu suspenso Exibir formato para alterar a forma como a memória é exibida.

Captura de tela da janela exibir memória do WinDbg com várias opções de formato de exibição.

  1. Para exibir dados associados ao controle de volume, defina um ponto de interrupção para disparar na rotina PropertyHandlerAudioEngineVolumeLevel usando o comando bm. Antes de definirmos o novo ponto de interrupção, limparemos todos os pontos de interrupção anteriores usando bc *.

    kd> bc *
    
  2. Defina um ponto de interrupção para disparar na rotina PropertyHandlerAudioEngineVolumeLevel usando o comando bm.

    kd> bm tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume
      1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
    
  3. Liste os pontos de interrupção para confirmar se o ponto de interrupção está definido de forma adequada.

    kd> bl
      1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
    
  4. Use o comando g para reiniciar a execução do código.

    No sistema de destino, ajuste o volume na bandeja do sistema. Isso levará ao acionamento do ponto de interrupção.

    Breakpoint 1 hit
    tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume:
    fffff80f`02c3a4b0 44894c2420      mov     dword ptr [rsp+20h],r9d
    
  5. Use o item de menu Exibir>Local para exibir variáveis locais. Observe o valor atual da variável IVolome.

  6. Você pode exibir o tipo de dados e o valor atual da variável IVolume no código de exemplo digitando o comando dt e o nome da variável.

    kd> dt lVolume
    Local var @ 0xa011ea50 Type long
    0n-6291456
    
  7. O ponto de interrupção é atingido ao inserir SetDeviceChannelVolume.

    STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceChannelVolume(_In_  ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_  LONG  _Volume)
    {
        NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    
        PAGED_CODE ();
    
        DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelVolume]"));
        IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit);
    
        // Snap the volume level to our range of steppings.
        LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(_Volume); 
    
        ntStatus = SetChannelVolume(_uiChannel, lVolume);
    Exit:
        return ntStatus;
    }
    
  8. Tente exibir o valor no local de memória do IVolume usando o comando dt (exibir tipo).

    kd> dt dt lVolume
    Local var @ 0xffffb780b7eee664 Type long
    0n0
    

    Como a variável ainda não foi definida, ela não contém informações.

  9. Pressione F10 para avançar até a última linha do código em SetDeviceChannelVolume.

        return ntStatus;
    
  10. Exiba o valor no local de memória do IVolume usando o comando dt (exibir tipo).

    kd> dt lVolume
    Local var @ 0xffffb780b7eee664 Type long
    0n-6291456
    

    Agora que a variável está ativa, um valor de 6291456 é exibido neste exemplo.

  11. Você também pode exibir o local de memória do IVolume usando o comando ? (avaliar expressão).

    kd> ? lVolume
    Evaluate expression: -79711507126684 = ffffb780`b7eee664
    
  12. O endereço mostrado, ffffb780'b7eee664, é o endereço da variável lVolume. Use o comando dd para exibir o conteúdo da memória nesse local.

    kd>  dd ffffb780`b7eee664
    ffffb780`b7eee664  ffa00000 00000018 00000000 c52d7008
    ffffb780`b7eee674  ffffc98e e0495756 fffff80e c52d7008
    ffffb780`b7eee684  ffffc98e 00000000 fffff80e 00000000
    ffffb780`b7eee694  ffffc98e ffa00000 ffffb780 b7eee710
    ffffb780`b7eee6a4  ffffb780 00000000 00000000 c7477260
    ffffb780`b7eee6b4  ffffc98e b7eee7a0 ffffb780 b7eee6f0
    ffffb780`b7eee6c4  ffffb780 e04959ca fffff80e 00000000
    ffffb780`b7eee6d4  00000000 00000028 00000000 00000002
    
  13. Para exibir os primeiros quatro bytes de um endereço, você pode especificar o parâmetro de intervalo L4.

    kd> dd ffffb780`b7eee664 l4
    ffffb780`b7eee664  ffa00000 00000018 00000000 c52d7008
    
  14. Para ver os tipos de saída de memória distintos exibidos, digite os comandos du, da e db.

    kd> du ffffb780`b7eee664 
    ffffb780`b7eee664  ""
    
    kd> a ffffb780`b7eee664 
    ffffb780`b7eee664  ""
    
    kd> db 0xffffae015ff97664 
    ffffae01`5ff97664  00 80 bc ff 18 00 00 00-00 00 00 00 08 50 e0 51  .............P.Q
    ffffae01`5ff97674  00 c0 ff ff 56 57 da 56-0e f8 ff ff 08 50 e0 51  ....VW.V.....P.Q
    ffffae01`5ff97684  00 c0 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00  ................
    ffffae01`5ff97694  00 c0 ff ff aa 80 bc ff-01 ae ff ff 10 77 f9 5f  .............w._
    ffffae01`5ff976a4  01 ae ff ff 40 00 00 00-00 e6 ff ff 10 dc 30 55  ....@.........0U
    ffffae01`5ff976b4  00 c0 ff ff a0 77 f9 5f-01 ae ff ff f0 76 f9 5f  .....w._.....v._
    ffffae01`5ff976c4  01 ae ff ff ca 59 da 56-0e f8 ff ff 00 00 00 00  .....Y.V........
    ffffae01`5ff976d4  00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00  ....(...........
    

    Use a opção df float para exibir dados como números de ponto flutuante de precisão única (4 bytes).

    df ffffb780`b7eee664 
    ffffb780`b7eee664          -1.#QNAN   3.3631163e-044                0        -2775.002
    ffffb780`b7eee674          -1.#QNAN  -5.8032637e+019         -1.#QNAN        -2775.002
    ffffb780`b7eee684          -1.#QNAN                0         -1.#QNAN                0
    ffffb780`b7eee694          -1.#QNAN         -1.#QNAN         -1.#QNAN  -2.8479408e-005
    

Gravar na memória

Assim como nos comandos usados para ler a memória, você pode usar os comandos e* para modificar o conteúdo da memória.

Comando Descrição

ea

Cadeia de caracteres ASCII (não terminada em NULL)

eu

Cadeia de caracteres Unicode (não terminada em NULL)

ew

Valores de palavra (2 bytes)

eza

Cadeia de caracteres ASCII terminada em NULL

ezu

Cadeia de caracteres Unicode terminada em NULL

eb

Valores de byte

ed

Valores de palavra dupla (4 bytes)

O exemplo a seguir mostra como substituir a memória.

  1. Primeiro, localize o endereço do lVolume que é usado no código de exemplo.

    kd> ? lVolume
    Evaluate expression: -79711507126684 = ffffb780`b7eee664
    
  2. Substitua esse endereço de memória por novos caracteres por meio do comando eb.

    kd> eb 0xffffb780`b7eee664 11 11 11 11 11
    
  3. Exiba o local da memória para confirmar que os caracteres foram substituídos, digitando o comando db.

    kd> db 0xffffb780`b7eee664
    ffffb780`b7eee664  11 11 11 11 11 00 00 00-00 00 00 00 08 70 2d c5  .............p-.
    ffffb780`b7eee674  8e c9 ff ff 56 57 49 e0-0e f8 ff ff 08 70 2d c5  ....VWI......p-.
    ffffb780`b7eee684  8e c9 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00  ................
    ffffb780`b7eee694  8e c9 ff ff 00 00 a0 ff-80 b7 ff ff 10 e7 ee b7  ................
    ffffb780`b7eee6a4  80 b7 ff ff 00 00 00 00-00 00 00 00 60 72 47 c7  ............`rG.
    ffffb780`b7eee6b4  8e c9 ff ff a0 e7 ee b7-80 b7 ff ff f0 e6 ee b7  ................
    ffffb780`b7eee6c4  80 b7 ff ff ca 59 49 e0-0e f8 ff ff 00 00 00 00  .....YI.........
    ffffb780`b7eee6d4  00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00  ....(...........
    

Como alternativa, você pode modificar o conteúdo da memória em uma janela de observação ou locais. Para a janela de observação, você pode ver variáveis que estão fora do contexto do quadro atual. Modificá-los não será relevante se elas não estiverem no contexto.

Seção 13: encerrar a sessão do WinDbg

<-No sistema host

Se você quiser deixar o depurador conectado, mas desejar trabalhar no destino, limpe todos os pontos de interrupção por meio de bc * para que o computador de destino não tente se conectar ao depurador do computador host. Use o comando g para permitir a reexecução do computador de destino.

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

0: kd> qd

Para saber mais, confira Encerrar uma sessão de depuração no WinDbg (clássico) na documentação de referência de depuração.

Seção 14: recursos de depuração do Windows

Informações adicionais estão disponíveis sobre a depuração do Windows. Observe que alguns desses livros usam versões anteriores do Windows, como o Windows Vista nos exemplos, mas os conceitos discutidos se aplicam à maioria das versões do Windows.

Manuais

  • Depuração avançada do Windows por Mario Hewardt e Daniel Pravat

  • Por dentro da depuração do Windows: um guia prático sobre estratégias de depuração e rastreamento no Windows® por Tarik Soulami

  • Windows Internals por Pavel Yosifovich, Alex Ionescu, Mark Russinovich e David Solomon

Video

As ferramentas de desfragmentação mostram os episódios 13-29 do WinDbg: </shows/defrag-tools/>

Treinamento de fornecedores:

OSR: https://www.osr.com/

Confira também

Introdução à depuração do Windows