Lendo e filtrando mensagens de depuração
As rotinas DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix e KdPrintEx enviam uma mensagem para o depurador de kernel em condições especificadas. Este procedimento permite filtrar mensagens de baixa prioridade.
Observação
No Microsoft Windows Server 2003 e versões anteriores do Windows, as rotinas DbgPrint e KdPrint enviam mensagens para o depurador de kernel incondicionalmente. No Windows Vista e versões posteriores do Windows, essas rotinas enviam mensagens condicionalmente, como DbgPrintEx e KdPrintEx. Seja qual for a versão do Windows que você estiver usando, você deve usar DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix e KdPrintEx, pois essas rotinas permitem controlar as condições sob as quais a mensagem é enviada.
Para filtrar mensagens de depuração
Para cada mensagem que você deseja enviar para o depurador, use DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix ou KdPrintEx no código do driver. Passe o nome do componente apropriado para o parâmetro ComponentId e passe um valor para o parâmetro Level que reflete a gravidade ou a natureza dessa mensagem. A mensagem em si é passada para os parâmetros Format e arguments usando a mesma sintaxe que printf.
Defina o valor da máscara de filtro de componente apropriada. Cada componente tem uma máscara diferente. O valor da máscara indica quais mensagens desse componente são exibidas. Você pode definir a máscara de filtro de componente no Registro usando um editor do Registro ou na memória usando um depurador de kernel.
Anexe um depurador de kernel ao computador. Sempre que o driver passa uma mensagem para DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix ou KdPrintEx, os valores passados para ComponentId e Level são comparados com o valor da máscara de filtro de componente correspondente. Se esses valores atenderem a determinados critérios, a mensagem será enviada para o depurador de kernel e exibida. Caso contrário, nenhuma mensagem será enviada.
Observação
Todas as referências nesta página a DbgPrintEx se aplicam igualmente a KdPrintEx, vDbgPrintEx e vDbgPrintExWithPrefix.
Identificando o nome do componente
Cada componente tem uma máscara de filtro separada. Isso permite que o depurador configure o filtro para cada componente separadamente.
Cada componente é referenciado de maneiras diferentes, dependendo do contexto. No parâmetro ComponentId de DbgPrintEx, o nome do componente é prefixado com "DPFLTR_" e sufixo com "_ID". No Registro, a máscara de filtro de componente tem o mesmo nome que o próprio componente. No depurador, a máscara de filtro de componente é prefixada com "Kd_" e sufixo com "_Mask".
Há uma lista completa de todos os nomes de componente (no formato DPFLTR_XXXX_ID) no cabeçalho dpfilter.h do WDK (Microsoft Windows Driver Kit). A maioria desses nomes de componentes é reservada para o Windows e para drivers escritos pela Microsoft.
Há seis nomes de componentes reservados para fornecedores independentes de hardware. Para evitar misturar a saída do driver com a saída dos componentes do Windows, você deve usar um dos seguintes nomes de componente:
Nome do Componente | Tipo de driver |
---|---|
IHVVIDEO | Driver de vídeo |
IHVAUDIO | Driver de áudio |
IHVNETWORK | Driver de rede |
IHVSTREAMING | Driver de streaming de kernel |
IHVBUS | Motorista de ônibus |
IHVDRIVER | Qualquer outro tipo de driver |
Por exemplo, se você estiver escrevendo um driver de vídeo, use DPFLTR_IHVVIDEO_ID como o parâmetro ComponentId de DbgPrintEx, use o nome do valor IHVVIDEO no registro e consulte Kd_IHVVIDEO_Mask no depurador.
Todas as mensagens enviadas por DbgPrint e KdPrint estão associadas ao componente DEFAULT .
Escolhendo o nível correto
O parâmetro Level da rotina DbgPrintEx é do tipo DWORD. Ele é usado para determinar o campo de bits de importância. A conexão entre o parâmetro Level e esse campo de bits depende do tamanho de Level:
Se Level for igual a um número entre 0 e 31, inclusive, ele será interpretado como um deslocamento de bits. O campo de bits de importância é definido como o valor 1 <<Level. Assim, escolher um valor entre 0 e 31 para Level resulta em um campo de bits com exatamente um bit definido. Se Level for 0, o campo de bits será equivalente a 0x00000001; se Level for 31, o campo de bits será equivalente a 0x80000000.
Se Level for um número entre 32 e 0xFFFFFFFF inclusivo, o campo de bits de importância será definido como o valor do próprio Nível .
Portanto, se você quiser definir o campo de bits como 0x00004000, poderá especificar Level como 0x00004000 ou simplesmente como 14. Observe que determinados valores de campo de bit não são possíveis por esse sistema , incluindo um campo de bits que é totalmente zero.
As constantes a seguir podem ser úteis para definir o valor de Level. Eles são definidos no cabeçalho do WDK (Microsoft Windows Driver Kit) dpfilter.h e no cabeçalho do SDK do Windows ntrtl.h:
#define DPFLTR_ERROR_LEVEL 0
#define DPFLTR_WARNING_LEVEL 1
#define DPFLTR_TRACE_LEVEL 2
#define DPFLTR_INFO_LEVEL 3
#define DPFLTR_MASK 0x80000000
Uma maneira fácil de usar o parâmetro Level é sempre usar valores entre 0 e 31 – usando os bits 0, 1, 2, 3 com o significado fornecido por DPFLTR_XXXX_LEVEL e usando os outros bits para significar o que você escolher.
Outra maneira fácil de usar o parâmetro Level é sempre usar campos de bit explícitos. Se você escolher esse método, convém ou o valor DPFLTR_MASK com seu campo de bits; isso garante que você não usará acidentalmente um valor menor que 32.
Para tornar seu driver compatível com a maneira como o Windows usa níveis de mensagem, você só deve definir o bit mais baixo (0x1) do campo de bits de importância se ocorrer um erro grave. Se você estiver usando valores de Nível inferiores a 32, isso corresponderá a DPFLTR_ERROR_LEVEL. Se esse bit estiver definido, sua mensagem será exibida sempre que alguém anexar um depurador de kernel a um computador no qual o driver está em execução.
Os níveis de aviso, rastreamento e informações devem ser usados nas situações apropriadas. Outros bits podem ser usados livremente para qualquer finalidade que você achar útil. Isso permite que você tenha uma ampla variedade de tipos de mensagens que podem ser vistos ou ocultos seletivamente.
Todas as mensagens enviadas por DbgPrint e KdPrint se comportam como mensagens DbgPrintEx e KdPrintEx com Level igual a DPFLTR_INFO_LEVEL. Em outras palavras, essas mensagens têm o terceiro bit de seu campo de bits de importância definido.
Definindo a máscara de filtro de componente
Há duas maneiras de definir uma máscara de filtro de componente:
A máscara de filtro de componente pode ser acessada na chave do Registro HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. Usando um editor do Registro, crie ou abra essa chave. Sob essa chave, crie um valor com o nome do componente desejado, em letras maiúsculas. Defina-o igual ao valor DWORD que você deseja usar como a máscara de filtro de componente.
Se um depurador de kernel estiver ativo, ele poderá acessar o valor da máscara de filtro de componente desreferenciando o endereço armazenado no símbolo Kd_XXXX_Mask, em que XXXX é o nome do componente desejado. Você pode exibir o valor dessa máscara em WinDbg ou KD com o comando dd (Display DWORD) ou inserir uma nova máscara de filtro de componente com o comando ed (Enter DWORD). Se houver um perigo de ambiguidade de símbolo, convém especificar esse símbolo como nt! Kd_XXXX_Mask.
As máscaras de filtro armazenadas no registro têm efeito durante a inicialização. As máscaras de filtro criadas pelo depurador entrarão em vigor imediatamente e persistirão até que o Windows seja reinicializado. Um valor definido no registro pode ser substituído pelo depurador, mas a máscara de filtro de componente retornará ao valor especificado no registro se o sistema for reinicializado.
Há também uma máscara em todo o sistema chamada WIN2000. Isso é igual a 0x1 por padrão, embora possa ser alterado por meio do registro ou do depurador, como todos os outros componentes. Quando a filtragem é executada, cada máscara de filtro de componente é primeiro ORed com a máscara de WIN2000 . Em particular, isso significa que os componentes cujas máscaras nunca foram especificadas padrão para 0x1.
Critérios para exibir a mensagem
Quando DbgPrintEx é chamado no código do modo kernel, o Windows compara o campo de bits de importância da mensagem especificado por Level com a máscara de filtro do componente especificado por ComponentId.
Observação
Lembre-se de que quando o parâmetro Level está entre 0 e 31, o campo de bits de importância é igual a 1 <<Level. Mas quando o parâmetro Level é 32 ou superior, o campo de bits de importância é simplesmente igual a Level.
O Windows executa uma operação AND no campo de bits de importância e na máscara de filtro de componente. Se o resultado for diferente de zero, a mensagem será enviada ao depurador.
Exemplo de filtro de depuração
Suponha que, antes da última inicialização, você tenha criado os seguintes valores na chave Depurar Filtro de Impressão :
IHVVIDEO, com um valor igual a DWORD 0x2
IHVBUS, igual a DWORD 0x7FF
Agora você emite os seguintes comandos no depurador de kernel:
kd> ed Kd_IHVVIDEO_Mask 0x8
kd> ed Kd_IHVAUDIO_Mask 0x7
Neste ponto, o componente IHVVIDEO tem uma máscara de filtro de 0x8, o componente IHVAUDIO tem uma máscara de filtro de 0x7 e o componente IHVBUS tem uma máscara de filtro de 0x7FF.
No entanto, como essas máscaras são automaticamente ORed com a máscara de todo o sistema WIN2000 (que geralmente é igual a 0x1), a máscara IHVVIDEO é efetivamente igual a 0x9. De fato, os componentes cujas máscaras de filtro não foram definidas (por exemplo, IHVSTREAMING ou DEFAULT) terão uma máscara de filtro de 0x1.
Agora suponha que as seguintes chamadas de função ocorram em vários drivers:
DbgPrintEx( DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID, 7, "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID, DPFLTR_MASK | 0x10, "Third message.\n");
DbgPrint( "Fourth message.\n");
A primeira mensagem tem seu parâmetro Level igual a DPFLTR_INFO_LEVEL, que é 3. Como isso é menor que 32, ele é tratado como uma mudança de bit, resultando em um campo de bits de importância de 0x8. Esse valor é anded com a máscara de filtro de componente IHVVIDEO eficaz de 0x9, dando um resultado diferente de zero. Portanto, a primeira mensagem é transmitida para o depurador.
A segunda mensagem tem seu parâmetro Level igual a 7. Novamente, isso é tratado como uma mudança de bit, resultando em um campo de bits de importância de 0x80. Em seguida, isso é ANDed com a máscara de filtro de componente IHVAUDIO de 0x7, dando um resultado de zero. Portanto, a segunda mensagem não é transmitida.
A terceira mensagem tem seu parâmetro Level igual a DPFLTR_MASK | 0x10. Isso é maior que 31 e, portanto, o campo de bits de importância é definido como igual ao valor de Level , em outras palavras, para 0x80000010. Em seguida, isso é ANDed com a máscara de filtro de componente IHVBUS de 0x7FF, dando um resultado diferente de zero. Portanto, a terceira mensagem é transmitida para o depurador.
A quarta mensagem foi passada para DbgPrint em vez de DbgPrintEx. No Windows Server 2003 e em versões anteriores do Windows, as mensagens passadas para essa rotina são sempre transmitidas. No Windows Vista e em versões posteriores do Windows, as mensagens passadas para essa rotina sempre recebem um filtro padrão. O campo de bits de importância é igual a 1 << DPFLTR_INFO_LEVEL, que é 0x00000008. O componente para essa rotina é DEFAULT. Como você não definiu a máscara de filtro de componente DEFAULT , ela tem um valor de 0x1. Quando este é ANDed com o campo de bits de importância, o resultado é zero. Portanto, a quarta mensagem não é transmitida.
Buffer DbgPrint e o depurador
Quando a rotina DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint ou KdPrintEx transmite uma mensagem para o depurador, a cadeia de caracteres formatada é enviada para o buffer DbgPrint . O conteúdo desse buffer é exibido imediatamente na janela Comando do Depurador, a menos que você desabilite essa exibição usando a opção Buffer DbgPrint Output de GFlags.
Durante a depuração do kernel local e em qualquer outro momento em que essa exibição tiver sido desabilitada, o conteúdo do buffer DbgPrint só poderá ser exibido usando o comando !dbgprint extension.
Qualquer chamada única para DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint ou KdPrintEx transmite apenas 512 bytes de informações. Qualquer saída maior que os 512 bytes é perdida. O próprio buffer DbgPrint pode conter até 4 KB de dados em uma compilação gratuita do Windows e até 32 KB de dados em uma compilação verificada do Windows. No Windows Server 2003 e versões posteriores do Windows, você pode usar a ferramenta KDbgCtrl para alterar o tamanho do buffer DbgPrint. Essa ferramenta faz parte das Ferramentas de Depuração para Windows.
Observação
Os builds verificados estavam disponíveis em versões mais antigas do Windows, antes de Windows 10 versão 1803. Use ferramentas como Driver Verifier e GFlags para marcar código de driver em versões posteriores do Windows.
Se uma mensagem for filtrada devido aos valores ComponentId e Level , ela não será transmitida pela conexão de depuração. Portanto, não há como exibir essa mensagem no depurador.