Compartilhar via


Gravando um plug-in de extensão de análise para estender !analyze

Você pode estender os recursos do comando de depurador !analyze escrevendo um plug-in de extensão de análise. Ao fornecer um plug-in de extensão de análise, você pode participar da análise de um bug marcar ou uma exceção de uma maneira específica para seu próprio componente ou aplicativo.

Ao escrever um plug-in de extensão de análise, você também escreve um arquivo de metadados que descreve as situações para as quais você deseja que seu plug-in seja chamado. Quando !analyze é executado, ele localiza, carrega e executa os plug-ins de extensão de análise apropriados.

Para escrever um plug-in de extensão de análise e disponibilizá-lo para !analisar, siga estas etapas.

  • Crie uma DLL que exporte uma função _EFN_Analyze .
  • Crie um arquivo de metadados que tenha o mesmo nome que sua DLL e uma extensão de .alz. Por exemplo, se a DLL for nomeada MyAnalyzer.dll, o arquivo de metadados deverá ser chamado de MyAnalyzer.alz. Para obter informações sobre como criar um arquivo de metadados, consulte Arquivos de metadados para extensões de análise. Coloque o arquivo de metadados no mesmo diretório que sua DLL.
  • No depurador, use o comando .extpath para adicionar seu diretório ao caminho do arquivo de extensão. Por exemplo, se a DLL e o arquivo de metadados estiverem na pasta chamada c:\MyAnalyzer, insira o comando .extpath+ c:\MyAnalyzer.

Quando o comando !analyze é executado no depurador, o mecanismo de análise procura no caminho do arquivo de extensão os arquivos de metadados que têm a extensão .alz. O mecanismo de análise lê os arquivos de metadados para determinar quais plug-ins de extensão de análise devem ser carregados. Por exemplo, suponha que o mecanismo de análise esteja em execução em resposta ao 0xA IRQL_NOT_LESS_OR_EQUAL de Verificação de Bugs e leia um arquivo de metadados chamado MyAnalyzer.alz que contém as entradas a seguir.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

A entrada BugCheckCode 0x0A especifica que esse plug-in deseja participar da análise do 0xA de Verificação de Bugs, portanto, o mecanismo de análise carrega MyAnalyzer.dll (que deve estar no mesmo diretório que MyAnalyzer.alz) e chama sua função _EFN_Analyze .

Nota A última linha do arquivo de metadados deve terminar com um caractere de nova linha.

Exemplo de esqueleto

Aqui está um exemplo de esqueleto que você pode usar como ponto de partida.

  1. Crie uma DLL chamada MyAnalyzer.dll que exporta a função _EFN_Analyze mostrada aqui.

    #include <windows.h>
    #define KDEXT_64BIT
    #include <wdbgexts.h>
    #include <dbgeng.h>
    #include <extsfns.h>
    
    extern "C" __declspec(dllexport) HRESULT _EFN_Analyze(_In_ PDEBUG_CLIENT4 Client, 
       _In_ FA_EXTENSION_PLUGIN_PHASE CallPhase, _In_ PDEBUG_FAILURE_ANALYSIS2 pAnalysis)
    { 
       HRESULT hr = E_FAIL;
    
       PDEBUG_CONTROL pControl = NULL;
       hr = Client->QueryInterface(__uuidof(IDebugControl), (void**)&pControl);
    
       if(S_OK == hr && NULL != pControl)
       {
          IDebugFAEntryTags* pTags = NULL;
          pAnalysis->GetDebugFATagControl(&pTags);
    
          if(NULL != pTags)
          {
             if(FA_PLUGIN_INITILIZATION == CallPhase)
             { 
                pControl->Output(DEBUG_OUTPUT_NORMAL, "My analyzer: initialization\n");  
             }
             else if(FA_PLUGIN_STACK_ANALYSIS == CallPhase)
             {
                pControl->Output(DEBUG_OUTPUT_NORMAL, "My analyzer: stack analysis\n"); 
             }
             else if(FA_PLUGIN_PRE_BUCKETING == CallPhase)
             {
                pControl->Output(DEBUG_OUTPUT_NORMAL, "My analyzer: prebucketing\n");
             }
             else if(FA_PLUGIN_POST_BUCKETING == CallPhase)
             {
                pControl->Output(DEBUG_OUTPUT_NORMAL, "My analyzer: post bucketing\n");    
                FA_ENTRY_TYPE entryType = pTags->GetType(DEBUG_FLR_BUGCHECK_CODE);       
                pControl->Output(DEBUG_OUTPUT_NORMAL, "The data type for the DEBUG_FLR_BUGCHECK_CODE tag is 0x%x.\n\n", entryType);
             }
          }
    
          pControl->Release();
       }
       return hr;
    }
    
  2. Crie um arquivo de metadados chamado MyAnalyzer.alz que tenha as entradas a seguir.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    Nota A última linha do arquivo de metadados deve terminar com um caractere de nova linha.

  3. Estabeleça uma sessão de depuração no modo kernel entre um host e um computador de destino.

  4. No computador host, coloque MyAnalyzer.dll e MyAnalyzer.alz na pasta c:\MyAnalyzer.

  5. No computador host, no depurador, insira esses comandos.

    .extpath+ c:\MyAnalyzer

    .Acidente

  6. O comando .crash gera 0xE2 MANUALLY_INITIATED_CRASH de Verificação de Bugs no computador de destino, o que causa uma interrupção no depurador no computador host. O mecanismo de análise de marcar de bugs (em execução no depurador no computador host) lê MyAnalyzer.alz e vê que MyAnalyzer.dll pode participar na análise de marcar 0xE2 de bugs. Portanto, o mecanismo de análise carrega MyAnalyzer.dll e chama sua função _EFN_Analyze .

    Verifique se você vê uma saída semelhante à seguinte no depurador.

    *                        Bugcheck Analysis                                    *
    *                                                                             *
    *******************************************************************************
    
    Use !analyze -v to get detailed debugging information.
    
    BugCheck E2, {0, 0, 0, 0}
    
    My analyzer: initialization
    My analyzer: stack analysis
    My analyzer: prebucketing
    My analyzer: post bucketing
    The data type for the DEBUG_FLR_BUGCHECK_CODE tag is 0x1.
    

A saída do depurador anterior mostra que o mecanismo de análise chamou a função _EFN_Analyze quatro vezes: uma vez para cada fase da análise. O mecanismo de análise passa a função _EFN_Analyze dois ponteiros de interface. O cliente é uma interface IDebugClient4 e pAnalysis é uma interface IDebugFailureAnalysis2 . O código no exemplo de esqueleto anterior mostra como obter mais dois ponteiros de interface. Client->QueryInterface obtém uma interface IDebugControl e pAnalysis->GetDebugFATagControl obtém uma interface IDebugFAEntryTags .

Entradas, marcas e tipos de dados de análise de falha

O mecanismo de análise cria um objeto DebugFailureAnalysis para organizar os dados relacionados a uma falha de código específica. Um objeto DebugFailureAnalysis tem uma coleção de entradas de análise de falha (entradas FA), cada uma representada por uma estrutura FA_ENTRY . Um plug-in de extensão de análise usa a interface IDebugFailureAnalysis2 para obter acesso a essa coleção de entradas fa. Cada entrada fa tem uma marca que identifica o tipo de informação que a entrada contém. Por exemplo, uma entrada fa pode ter a marca DEBUG_FLR_BUGCHECK_CODE, que nos diz que a entrada contém um bug marcar código. As marcas são valores na enumeração DEBUG_FLR_PARAM_TYPE (definida em extsfns.h), que também é chamada de enumeração FA_TAG .

typedef enum _DEBUG_FLR_PARAM_TYPE {
    ...
    DEBUG_FLR_BUGCHECK_CODE,
    ...
    DEBUG_FLR_BUILD_VERSION_STRING,
    ...
} DEBUG_FLR_PARAM_TYPE;

typedef DEBUG_FLR_PARAM_TYPE FA_TAG;

A maioria das entradas fa tem um bloco de dados associado. O membro DataSize da estrutura FA_ENTRY contém o tamanho do bloco de dados. Algumas entradas de FA não têm um bloco de dados associado; todas as informações são transmitidas pela marca. Nesses casos, o membro DataSize tem um valor igual a 0.

typedef struct _FA_ENTRY
{
    FA_TAG Tag;
    USHORT FullSize;
    USHORT DataSize;
} FA_ENTRY, *PFA_ENTRY;

Cada marca tem um conjunto de propriedades: por exemplo, nome, descrição e tipo de dados. Um objeto DebugFailureAnalysis está associado a um objeto DebugFailureAnalysisTags , que contém uma coleção de propriedades de marca. O diagrama a seguir ilustra essa associação.

Diagrama mostrando o mecanismo de análise, o objeto DebugFailureAnalysis e o objeto DebugFailureAnalysisTags.

Um objeto DebugFailureAnalysis tem uma coleção de entradas FA que pertencem a uma sessão de análise específica. O objeto DebugFailureAnalysisTags associado tem uma coleção de propriedades de marca que inclui apenas as marcas usadas por essa mesma sessão de análise. Como mostra o diagrama anterior, o mecanismo de análise tem uma tabela de marcas global que contém informações limitadas sobre um grande conjunto de marcas que geralmente estão disponíveis para uso por sessões de análise.

Normalmente, a maioria das marcas usadas por uma sessão de análise são marcas padrão; ou seja, as marcas são valores na enumeração FA_TAG . No entanto, um plug-in de extensão de análise pode criar marcas personalizadas. Um plug-in de extensão de análise pode adicionar uma entrada FA a um objeto DebugFailureAnalysis e especificar uma marca personalizada para a entrada. Nesse caso, as propriedades da marca personalizada são adicionadas à coleção de propriedades de marca no objeto DebugFailureAnalysisTags associado.

Você pode acessar um DebugFailureAnalysisTags por meio de uma interface de marcas IDebugFAEntry. Para obter um ponteiro para uma interface IDebugFAEntry, chame o método GetDebugFATagControl da interface IDebugFailureAnalysis2 .

Cada marca tem uma propriedade de tipo de dados que você pode inspecionar para determinar o tipo de dados dos dados em uma entrada de análise de falha. Um tipo de dados é representado por um valor na enumeração FA_ENTRY_TYPE .

A linha de código a seguir obtém o tipo de dados da marca DEBUG_FLR_BUILD_VERSION_STRING . Nesse caso, o tipo de dados é DEBUG_FA_ENTRY_ANSI_STRING. No código, pAnalysis é um ponteiro para uma interface IDebugFailureAnalysis2 .

IDebugFAEntryTags* pTags = pAnalysis->GetDebugFATagControl(&pTags);

if(NULL != pTags)
{
   FA_ENTRY_TYPE entryType = pTags->GetType(DEBUG_FLR_BUILD_VERSION_STRING);
}

Se uma entrada de análise de falha não tiver nenhum bloco de dados, o tipo de dados da marca associada será DEBUG_FA_ENTRY_NO_TYPE.

Lembre-se de que um objeto DebugFailureAnalysis tem uma coleção de entradas FA. Para inspecionar todas as entradas FA na coleção, use o método NextEntry . O exemplo a seguir mostra como iterar por toda a coleção de entradas FA. Suponha que pAnalysis seja um ponteiro para uma interface IDebugFailureAnalysis2 . Observe que obtemos a primeira entrada passando NULL para NextEntry.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

while(NULL != entry)
{
   // Do something with the entry

   entry = pAnalysis->NextEntry(entry);
}

Uma marca pode ter um nome e uma descrição. No código a seguir, pAnalysis é um ponteiro para uma interface IDebugFailureAnalysis , pControl é um ponteiro para uma interface IDebugControl e pTags é um ponteiro para uma interface IDebugFAEntryTags . O código mostra como usar o método GetProperties para obter o nome e a descrição da marca associada a uma entrada FA.

#define MAX_NAME_LENGTH 64
#define MAX_DESCRIPTION_LENGTH 512

CHAR name[MAX_NAME_LENGTH] = {0};
ULONG nameSize = MAX_NAME_LENGTH;
CHAR desc[MAX_DESCRIPTION_LENGTH] = {0};
ULONG descSize = MAX_DESCRIPTION_LENGTH;
                  
PFA_ENTRY pEntry = pAnalysis->NextEntry(NULL); 
pTags->GetProperties(pEntry->Tag, name, &nameSize, desc, &descSize, NULL);
pControl->Output(DEBUG_OUTPUT_NORMAL, "The name is %s\n", name);
pControl->Output(DEBUG_OUTPUT_NORMAL, "The description is %s\n", desc);

Confira também

Gravando extensões do depurador de análise personalizada

_EFN_Analyze

Arquivos de metadados para plug-ins de extensão de análise

IDebugFailureAnalysis2

IDebugFAEntryTags