Compartilhar via


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

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

KBUGCHECK_CALLBACK_ROUTINE de uso de BugCheckCallback
Os dados gravados por essa rotina tornam-se parte dos dados de retorno de chamada. Os dados não estão incluídos no arquivo de despejo de memória.

BugCheckSecondaryDumpDataCallback usa KBUGCHECK_REASON_CALLBACK_ROUTINE
Os dados gravados por essa 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.

Uso de BugCheckAddPagesCallbackKBUGCHECK_REASON_CALLBACK_ROUTINE
As páginas especificadas por essa rotina tornam-se parte dos dados de retorno de chamada. Os dados nessas páginas estão incluídos no arquivo de despejo de memória.

A quantidade de dados de retorno de chamada e de retorno de chamada secundários disponíveis para o depurador depende de vários fatores:

  • Se você estiver executando a depuração ao vivo de um sistema com falha, 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, pois não são armazenados em nenhum local de memória fixa.

  • Se você estiver depurando um Despejo de Memória Completo ou Despejo de Memória do Kernel, os dados de retorno de chamada especificados por BugCheckAddPagesCallback e dados de retorno de chamada 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 você estiver depurando um despejo de memória pequeno, os dados de retorno de chamada não estarão disponíveis. Os dados de retorno de chamada secundários 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 bugs marcar dados de retorno de chamada, você pode usar a extensão !bugdump.

Sem 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, em que Component é o mesmo parâmetro que foi passado para KeRegisterBugCheckCallback quando essa rotina foi registrada.

Exibindo dados de retorno de chamada secundários

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 de retorno de chamada secundários é identificado por uma marca GUID. Essa marca é especificada pelo campo Guid do parâmetro (KBUGCHECK_SECONDARY_DUMP_DATA)ReasonSpecificData passado para BugCheckSecondaryDumpDataCallback.

O comando .enumtag (Enumerar Dados de Retorno de Chamada Secundários) não é um instrumento muito preciso. Ele exibe todos os blocos de dados secundários, mostrando a marca e mostrando os dados no formato hexadecimal e ASCII. Geralmente, é útil apenas determinar quais marcas estão sendo realmente usadas para blocos de dados secundários.

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

Se você souber a marca GUID do bloco de dados secundário, sua extensão deverá usar o método IDebugDataSpaces3::ReadTagged para acessar os dados. 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 este 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 muito grande, ReadTagged terá êxito, mas gravará apenas o tamanho real do bloco em Buffer. Se você fornecer um ponteiro para TotalSize, ReadTagged o usará para retornar o tamanho do bloco real. Se o bloco não puder ser acessado, ReadTagged retornará uma falha status código.

Se dois blocos tiverem marcas 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 bloco, poderá usar os métodos IDebugDataSpaces3::StartEnumTagged, IDebugDataSpaces3::GetNextTagged e IDebugDataSpaces3::EndEnumTagged para enumerar os blocos marcados. 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 retorno de chamada funcionam como qualquer outro ponto de interrupção.

Se a rotina de retorno de chamada causar um segundo bug marcar, esse novo bug marcar será processado primeiro. No entanto, o Windows não repetirá determinadas partes do processo de Parada, por exemplo, ele não gravará um segundo arquivo de despejo de memória. O código Stop exibido na tela azul será o segundo bug marcar código. Se um depurador de kernel estiver anexado, as mensagens sobre ambas as verificações de bug geralmente serão exibidas.