Partilhar via


Lendo dados de retorno de chamada de verificação de erro

Muitos drivers fornecem rotinas de retorno de chamada de verificação de bugs. Quando o Windows emite uma verificação de bug, ele chama essas rotinas antes de desligar o sistema. Essas rotinas podem especificar e gravar em áreas da memória conhecidas como dados de retorno de chamada e dados de retorno de chamada secundários.

BugCheckCallback utilizar KBUGCHECK_CALLBACK_ROUTINE
Os dados gravados por esta rotina tornam-se parte dos dados de retorno de chamada. Os dados não estão incluídos no arquivo de despejo de falha.

BugCheckSecondaryDumpDataCallback usa a KBUGCHECK_REASON_CALLBACK_ROUTINE
Os dados escritos por esta rotina tornam-se parte dos dados de retorno de chamada secundários. Os dados estão incluídos no arquivo de despejo de memória.

BugCheckAddPagesCallback usar KBUGCHECK_REASON_CALLBACK_ROUTINE
As páginas especificadas por esta rotina tornam-se parte dos dados de retorno de chamada. Os dados dessas páginas são incluídos no arquivo de despejo de memória.

A quantidade de dados de retorno de chamada e de retorno de chamada secundário que está disponível para o depurador depende de vários fatores:

  • Se estiveres a executar a análise em tempo real de um sistema que falhou, os dados de retorno de chamada que já foram gravados por BugCheckCallback ou especificados por BugCheckAddPagesCallback estarão disponíveis. Os dados de retorno de chamada secundários não estarão disponíveis, porque não são armazenados em nenhum local de memória fixa.

  • Se estiver a depurar um Despejo de Memória Completo ou um Despejo de Memória do Kernel, os dados de callback especificados por BugCheckAddPagesCallback e os dados de callback secundários gravados por BugCheckSecondaryDumpDataCallback estarão disponíveis. Os dados de retorno de chamada gravados por BugCheckCallback não estarão disponíveis.

  • Se estiver a depurar um despejo de memória pequeno, os dados de retorno de chamada não estarão disponíveis. Dados secundários de retorno de chamada estarão disponíveis.

Consulte Variedades de arquivos de despejo de Kernel-Mode para obter mais detalhes sobre esses diferentes tamanhos de arquivo de despejo.

Exibindo dados de retorno de chamada

Para exibir dados de retorno de chamada de verificação de bug, pode usar a extensão !bugdump.

Sem quaisquer parâmetros, !bugdump exibirá dados para todos os retornos de chamada.

Para exibir dados de uma rotina de retorno de chamada específica, use !bugdumpComponent, onde Component é o mesmo parâmetro que foi passado para KeRegisterBugCheckCallback quando essa rotina foi registrada.

Exibindo dados secundários de chamada de retorno

Há dois métodos para exibir dados de retorno de chamada secundários. Você pode usar o comando .enumtag ou pode escrever sua própria extensão de depurador.

Cada bloco de dados secundários de retorno de chamada é identificado por um identificador GUID. Essa tag é especificada pelo campo Guid do parâmetro (KBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData passado para BugCheckSecondaryDumpDataCallback.

O comando .enumtag (Enumerate Secondary Callback Data) não é um instrumento muito preciso. Ele exibe todos os blocos de dados secundários, mostrando a tag e, em seguida, mostrando os dados em formato hexadecimal e ASCII. Geralmente, é útil apenas para determinar quais tags estão realmente sendo usadas para blocos de dados secundários.

Para usar esses dados de uma maneira mais prática, é recomendável que você escreva sua própria extensão de depurador. Esta extensão deve chamar métodos no arquivo de cabeçalho dbgeng.h. Para obter detalhes, consulte Escrevendo novas extensões do depurador.

Se você souber a marca GUID do bloco de dados secundário, sua extensão deve usar o método IDebugDataSpaces3::ReadTagged para acessar os dados. O seu protótipo é o seguinte:

STDMETHOD(ReadTagged)(
    THIS_
    IN LPGUID Tag,
    IN ULONG Offset,
    OUT OPTIONAL PVOID Buffer,
    IN ULONG BufferSize,
    OUT OPTIONAL PULONG TotalSize
    ) PURE; 

Aqui está um exemplo de como usar esse método:

UCHAR RawData[MY_DATA_SIZE];
GUID MyGuid = .... ;

Success = DataSpaces->ReadTagged(  &MyGuid,  0,  RawData,
                                   sizeof(RawData),  NULL); 

Se você fornecer um BufferSize muito pequeno, ReadTagged terá êxito, mas gravará apenas o número solicitado de bytes no Buffer. Se você especificar um BufferSize que é muito grande, ReadTagged terá êxito, mas gravará apenas o tamanho real do bloco no Buffer. Se você fornecer um ponteiro para TotalSize, ReadTagged irá usá-lo para retornar o tamanho do bloco real. Se o bloco não puder ser acessado, ReadTagged retornará um código de status de falha.

Se dois blocos tiverem tags GUID idênticas, o primeiro bloco correspondente será retornado e o segundo bloco ficará inacessível.

Se você não tiver certeza da marca GUID do seu bloco, poderá usar os métodos IDebugDataSpaces3::StartEnumTagged, IDebugDataSpaces3::GetNextTagged e IDebugDataSpaces3::EndEnumTagged para enumerar os blocos marcados. Os seus protótipos são os seguintes:

STDMETHOD(StartEnumTagged)(
    THIS_
    OUT PULONG64 Handle
    ) PURE;

STDMETHOD(GetNextTagged)(
    THIS_
    IN ULONG64 Handle,
    OUT LPGUID Tag,
    OUT PULONG Size
    ) PURE;

STDMETHOD(EndEnumTagged)(
    THIS_
    IN ULONG64 Handle
    ) PURE;

Depurando rotinas de retorno de chamada

Também é possível depurar a própria rotina de retorno de chamada. Os pontos de interrupção dentro das rotinas de 'callback' funcionam como qualquer outro ponto de interrupção.

Se a rotina de retorno de chamada causar uma segunda verificação de erro, essa nova verificação de erro será processada primeiro. No entanto, o Windows não repetirá determinadas partes do processo Stop — por exemplo, não gravará um segundo arquivo de despejo de falha. O código de interrupção exibido na tela azul será o segundo código de verificação de erro. Se um depurador do kernel for anexado, mensagens sobre ambas as verificações de bugs geralmente aparecerão.