Condividi tramite


Scrittura di un plug-in di estensione di analisi per estendere !analyze

È possibile estendere le funzionalità del comando !analyze debugger scrivendo un plug-in di estensione di analisi. Fornendo un plug-in di estensione di analisi, è possibile partecipare all'analisi di un controllo di bug o un'eccezione in un modo specifico per il proprio componente o applicazione.

Quando si scrive un plug-in di estensione di analisi, si scrive anche un file di metadati che descrive le situazioni per cui si vuole chiamare il plug-in. Quando !analyze viene eseguito, individua, carica ed esegue i plug-in dell'estensione di analisi appropriati.

Per scrivere un plug-in di estensione di analisi e renderlo disponibile per !analyze, seguire questa procedura.

  • Creare una DLL che esporta una funzione _EFN_Analyze .
  • Creare un file di metadati con lo stesso nome della DLL e un'estensione di .alz. Ad esempio, se la DLL è denominata MyAnalyzer.dll, il file di metadati deve essere denominato MyAnalyzer.alz. Per informazioni su come creare un file di metadati, vedere File di metadati per le estensioni di analisi. Inserire il file di metadati nella stessa directory della DLL.
  • Nel debugger usare il comando extpath per aggiungere la directory al percorso del file di estensione. Ad esempio, se la DLL e il file di metadati si trovano nella cartella denominata c:\MyAnalyzer, immettere il comando .extpath+ c:\MyAnalyzer.

Quando il comando !analyze viene eseguito nel debugger, il motore di analisi cerca nel percorso del file di estensione per i file di metadati con estensione alz. Il motore di analisi legge i file di metadati per determinare quali plug-in di estensione di analisi devono essere caricati. Si supponga, ad esempio, che il motore di analisi sia in esecuzione in risposta alla 0xA IRQL_NOT_LESS_OR_EQUAL controllo bug e che legge un file di metadati denominato MyAnalyzer.alz che contiene le voci seguenti.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

La voce BugCheckCode 0x0A specifica che questo plug-in vuole partecipare all'analisi del controllo bug 0xA, quindi il motore di analisi carica MyAnalyzer.dll (che deve trovarsi nella stessa directory di MyAnalyzer.alz) e chiama la relativa funzione _EFN_Analyze .

Nota L'ultima riga del file di metadati deve terminare con un carattere di nuova riga.

Esempio di scheletro

Di seguito è riportato uno scheletro di esempio che è possibile usare come punto di partenza.

  1. Compilare una DLL denominata MyAnalyzer.dll che esporta la funzione _EFN_Analyze illustrata qui.

    #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. Creare un file di metadati denominato MyAnalyzer.alz con le voci seguenti.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    Nota L'ultima riga del file di metadati deve terminare con un carattere di nuova riga.

  3. Stabilire una sessione di debug in modalità kernel tra un host e un computer di destinazione.

  4. Nel computer host inserire MyAnalyzer.dll e MyAnalyzer.alz nella cartella c:\MyAnalyzer.

  5. Nel computer host immettere questi comandi nel debugger.

    .extpath+ c:\MyAnalyzer

    .scontro

  6. Il comando con estensione crash genera il controllo bug 0xE2 MANUALLY_INITIATED_CRASH nel computer di destinazione, causando un'interruzione nel debugger nel computer host. Il motore di analisi del controllo dei bug (in esecuzione nel debugger nel computer host) legge MyAnalyzer.alz e rileva che MyAnalyzer.dll è in grado di partecipare all'analisi del controllo dei bug 0xE2. Il motore di analisi carica quindi MyAnalyzer.dll e chiama la funzione _EFN_Analyze .

    Verificare che l'output sia simile al seguente nel debugger.

    *                        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.
    

L'output del debugger precedente mostra che il motore di analisi ha chiamato la funzione _EFN_Analyze quattro volte: una volta per ogni fase dell'analisi. Il motore di analisi passa il _EFN_Analyze funzione due puntatori a interfaccia. Il client è un'interfaccia IDebugClient4 e pAnalysis è un'interfaccia IDebugFailureAnalysis2 . Il codice nell'esempio di scheletro precedente mostra come ottenere due puntatori di interfaccia in più. Client->QueryInterface ottiene un'interfaccia IDebugControl e pAnalysis->GetDebugFATagControl ottiene un'interfaccia IDebugFAEntryTags .

Voci, tag e tipi di dati di analisi degli errori

Il motore di analisi crea un oggetto DebugFailureAnalysis per organizzare i dati correlati a un errore di codice specifico. Un oggetto DebugFailureAnalysis dispone di una raccolta di voci di analisi degli errori (voci FA), ognuna delle quali è rappresentata da una struttura FA_ENTRY . Un plug-in di estensione di analisi usa l'interfaccia IDebugFailureAnalysis2 per ottenere l'accesso a questa raccolta di voci FA. Ogni voce FA ha un tag che identifica il tipo di informazioni contenute nella voce. Ad esempio, una voce FA potrebbe avere il tag DEBUG_FLR_BUGCHECK_CODE, che indica che la voce contiene un codice di controllo di bug. I tag sono valori nell'enumerazione DEBUG_FLR_PARAM_TYPE (definita in extsfns.h), chiamata anche enumerazione 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;

La maggior parte delle voci FA ha un blocco di dati associato. Il membro DataSize della struttura FA_ENTRY contiene le dimensioni del blocco di dati. Alcune voci FA non hanno un blocco di dati associato; tutte le informazioni vengono trasmesse dal tag . In questi casi, il membro DataSize ha un valore pari a 0.

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

Ogni tag ha un set di proprietà, ad esempio nome, descrizione e tipo di dati. Un oggetto DebugFailureAnalysis è associato a un oggetto DebugFailureAnalysisTags , che contiene una raccolta di proprietà di tag. Il diagramma seguente illustra questa associazione.

Diagramma che mostra il motore di analisi, l'oggetto DebugFailureAnalysis e l'oggetto DebugFailureAnalysisTags.

Un oggetto DebugFailureAnalysis dispone di una raccolta di voci FA che appartengono a una determinata sessione di analisi. L'oggetto DebugFailureAnalysisTags associato dispone di una raccolta di proprietà di tag che include solo i tag utilizzati dalla stessa sessione di analisi. Come illustrato nel diagramma precedente, il motore di analisi dispone di una tabella di tag globale che contiene informazioni limitate su un ampio set di tag disponibili a livello generale per l'uso da parte delle sessioni di analisi.

In genere la maggior parte dei tag usati da una sessione di analisi sono tag standard; ovvero, i tag sono valori nell'enumerazione FA_TAG . Tuttavia, un plug-in di estensione di analisi può creare tag personalizzati. Un plug-in di estensione di analisi può aggiungere una voce FA a un oggetto DebugFailureAnalysis e specificare un tag personalizzato per la voce. In tal caso, le proprietà per il tag personalizzato vengono aggiunte all'insieme di proprietà dei tag nell'oggetto DebugFailureAnalysisTags associato.

È possibile accedere a DebugFailureAnalysisTags tramite un'interfaccia tag IDebugFAEntry. Per ottenere un puntatore a un'interfaccia IDebugFAEntry, chiamare il metodo GetDebugFATagControl dell'interfaccia IDebugFailureAnalysis2 .

Ogni tag ha una proprietà del tipo di dati che è possibile esaminare per determinare il tipo di dati dei dati in una voce di analisi degli errori. Un tipo di dati è rappresentato da un valore nell'enumerazione FA_ENTRY_TYPE .

La riga di codice seguente ottiene il tipo di dati del tag DEBUG_FLR_BUILD_VERSION_STRING . In questo caso, il tipo di dati è DEBUG_FA_ENTRY_ANSI_STRING. Nel codice pAnalysis è un puntatore a un'interfaccia IDebugFailureAnalysis2 .

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

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

Se una voce di analisi degli errori non ha blocchi di dati, il tipo di dati del tag associato viene DEBUG_FA_ENTRY_NO_TYPE.

Tenere presente che un oggetto DebugFailureAnalysis ha una raccolta di voci FA. Per esaminare tutte le voci FA nella raccolta, utilizzare il metodo NextEntry . Nell'esempio seguente viene illustrato come scorrere l'intera raccolta di voci FA. Si supponga che pAnalysis sia un puntatore a un'interfaccia IDebugFailureAnalysis2 . Si noti che si ottiene la prima voce passando NULL a NextEntry.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

Un tag può avere un nome e una descrizione. Nel codice seguente pAnalysis è un puntatore a un'interfaccia IDebugFailureAnalysis , pControl è un puntatore a un'interfaccia IDebugControl ed pTags è un puntatore a un'interfaccia IDebugFAEntryTags . Il codice illustra come utilizzare il metodo GetProperties per ottenere il nome e la descrizione del tag associato a una voce 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);

Vedi anche

Scrittura di estensioni del debugger di analisi personalizzate

_EFN_Analyze

File di metadati per i plug-in dell'estensione di analisi

IDebugFailureAnalysis2

IDebugFAEntryTags