Schreiben eines Analyseerweiterungs-Plug-Ins zum Erweitern von !analyze

Sie können die Funktionen des !analyze-Debuggerbefehls erweitern , indem Sie ein Analyseerweiterungs-Plug-In schreiben. Durch Bereitstellen eines Analyseerweiterungs-Plug-Ins können Sie an der Analyse einer Fehlerüberprüfung oder einer Ausnahme auf eine Weise teilnehmen, die für Ihre eigene Komponente oder Anwendung spezifisch ist.

Wenn Sie ein Analyseerweiterungs-Plug-In schreiben, schreiben Sie auch eine Metadatendatei, die die Situationen beschreibt, für die Ihr Plug-In aufgerufen werden soll. Wenn !analyze ausgeführt wird, werden die entsprechenden Analyseerweiterungs-Plug-Ins gesucht, geladen und ausgeführt.

Führen Sie die folgenden Schritte aus, um ein Analyseerweiterungs-Plug-In zu schreiben und für !analyze verfügbar zu machen.

  • Erstellen Sie eine DLL, die eine _EFN_Analyze-Funktion exportiert.
  • Erstellen Sie eine Metadatendatei, die denselben Namen wie Ihre DLL und die Erweiterung .alz hat. Wenn Ihre DLL beispielsweise den Namen MyAnalyzer.dll hat, muss Ihre Metadatendatei den Namen MyAnalyzer.alz haben. Informationen zum Erstellen einer Metadatendatei finden Sie unter Metadatendateien für Analyseerweiterungen. Platzieren Sie die Metadatendatei im selben Verzeichnis wie Ihre DLL.
  • Verwenden Sie im Debugger den Befehl .extpath , um Ihr Verzeichnis dem Pfad der Erweiterungsdatei hinzuzufügen. Wenn sich ihre DLL und Ihre Metadatendatei beispielsweise im Ordner c:\MyAnalyzer befinden, geben Sie den Befehl .extpath+ c:\MyAnalyzer ein.

Wenn der Befehl !analyze im Debugger ausgeführt wird, sucht die Analyse-Engine im Pfad der Erweiterungsdatei nach Metadatendateien, die die Erweiterung .alz aufweisen. Die Analyse-Engine liest die Metadatendateien aus, um zu bestimmen, welche Analyseerweiterungs-Plug-Ins geladen werden sollen. Angenommen, die Analyse-Engine wird als Reaktion auf die Fehlerüberprüfung 0xA IRQL_NOT_LESS_OR_EQUAL ausgeführt und liest eine Metadatendatei namens MyAnalyzer.alz, die die folgenden Einträge enthält.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

Der Eintrag BugCheckCode 0x0A gibt an, dass dieses Plug-In an der Analyse von Bug Check 0xA teilnehmen möchte, sodass die Analyse-Engine MyAnalyzer.dll lädt (die sich im selben Verzeichnis wie MyAnalyzer.alz befinden muss) und ihre _EFN_Analyze-Funktion aufruft.

Hinweis Die letzte Zeile der Metadatendatei muss mit einem Zeilenumbruchzeichen enden.

Skelettbeispiel

Hier sehen Sie ein Skelettbeispiel, das Sie als Ausgangspunkt verwenden können.

  1. Erstellen Sie eine DLL mit dem Namen MyAnalyzer.dll, die die hier gezeigte _EFN_Analyze-Funktion exportiert.

    #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. Erstellen Sie eine Metadatendatei mit dem Namen MyAnalyzer.alz mit den folgenden Einträgen.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    Hinweis Die letzte Zeile der Metadatendatei muss mit einem Zeilenumbruchzeichen enden.

  3. Richten Sie eine Debugsitzung im Kernelmodus zwischen einem Host und einem Zielcomputer ein.

  4. Legen Sie auf dem Hostcomputer MyAnalyzer.dll und MyAnalyzer.alz in den Ordner c:\MyAnalyzer ein.

  5. Geben Sie auf dem Hostcomputer im Debugger diese Befehle ein.

    .extpath+ c:\MyAnalyzer

    .Absturz

  6. Der Befehl .crash generiert fehlerüberprüfung 0xE2 MANUALLY_INITIATED_CRASH auf dem Zielcomputer, wodurch der Debugger auf dem Hostcomputer unterbrochen wird. Die Fehlerüberprüfungsanalyse-Engine (die im Debugger auf dem Hostcomputer ausgeführt wird) liest MyAnalyzer.alz und sieht, dass MyAnalyzer.dll an der Analyse der Fehlerüberprüfung 0xE2 teilnehmen kann. Daher lädt die Analyse-Engine MyAnalyzer.dll und ruft ihre _EFN_Analyze-Funktion auf.

    Stellen Sie sicher, dass eine Ausgabe ähnlich der folgenden im Debugger angezeigt wird.

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

Die obige Debuggerausgabe zeigt, dass die Analyse-Engine die _EFN_Analyze-Funktion viermal aufgerufen hat: einmal für jede Phase der Analyse. Die Analyse-Engine übergibt die _EFN_Analyze Funktion zwei Schnittstellenzeiger. Client ist eine IDebugClient4-Schnittstelle , und pAnalysis ist eine IDebugFailureAnalysis2-Schnittstelle . Der Code im vorherigen Skelettbeispiel zeigt, wie zwei weitere Schnittstellenzeiger abgerufen werden. Client->QueryInterface ruft eine IDebugControl-Schnittstelle ab und pAnalysis->GetDebugFATagControl ruft eine IDebugFAEntryTags-Schnittstelle ab.

Fehleranalyseeinträge, Tags und Datentypen

Die Analyse-Engine erstellt ein DebugFailureAnalysis-Objekt , um die Daten im Zusammenhang mit einem bestimmten Codefehler zu organisieren. Ein DebugFailureAnalysis-Objekt verfügt über eine Auflistung von Fehleranalyseeinträgen (FA-Einträge), die jeweils durch eine FA_ENTRY-Struktur dargestellt werden. Ein Analyseerweiterungs-Plug-In verwendet die IDebugFailureAnalysis2-Schnittstelle , um Zugriff auf diese Sammlung von FA-Einträgen zu erhalten. Jeder FA-Eintrag verfügt über ein Tag, das die Art von Informationen identifiziert, die der Eintrag enthält. Beispielsweise kann ein FA-Eintrag das Tag DEBUG_FLR_BUGCHECK_CODE aufweisen, das uns mitteilt, dass der Eintrag einen Fehlerüberprüfungscode enthält. Tags sind Werte in der DEBUG_FLR_PARAM_TYPE Enumeration (definiert in extsfns.h), die auch als FA_TAG-Enumeration bezeichnet wird.

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;

Die meisten FA-Einträge verfügen über einen zugeordneten Datenblock. Das DataSize-Element der FA_ENTRY-Struktur enthält die Größe des Datenblocks. Einige FA-Einträge verfügen nicht über einen zugeordneten Datenblock. alle Informationen werden durch das Tag übermittelt. In diesen Fällen weist das DataSize-Element den Wert 0 auf.

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

Jedes Tag verfügt über eine Reihe von Eigenschaften: z. B. Name, Beschreibung und Datentyp. Ein DebugFailureAnalysis-Objekt ist einem DebugFailureAnalysisTags-Objekt zugeordnet, das eine Auflistung von Tageigenschaften enthält. Das folgende Diagramm veranschaulicht diese Zuordnung.

Diagramm mit der Analyse-Engine, dem DebugFailureAnalysis-Objekt und dem DebugFailureAnalysisTags-Objekt.

Ein DebugFailureAnalysis-Objekt verfügt über eine Auflistung von FA-Einträgen , die zu einer bestimmten Analysesitzung gehören. Das zugeordnete DebugFailureAnalysisTags-Objekt verfügt über eine Auflistung von Tageigenschaften, die nur die tags enthält, die von derselben Analysesitzung verwendet werden. Wie das obige Diagramm zeigt, verfügt die Analyse-Engine über eine globale Tagtabelle, die begrenzte Informationen zu einer großen Gruppe von Tags enthält, die allgemein für die Verwendung durch Analysesitzungen verfügbar sind.

In der Regel sind die meisten von einer Analysesitzung verwendeten Tags Standardtags. Das heißt, die Tags sind Werte in der FA_TAG Enumeration. Ein Analyseerweiterungs-Plug-In kann jedoch benutzerdefinierte Tags erstellen. Ein Analyseerweiterungs-Plug-In kann einem DebugFailureAnalysis-Objekt einen FA-Eintrag hinzufügen und ein benutzerdefiniertes Tag für den Eintrag angeben. In diesem Fall werden eigenschaften für das benutzerdefinierte Tag der Auflistung der Tageigenschaften im zugeordneten DebugFailureAnalysisTags-Objekt hinzugefügt.

Sie können über eine IDebugFAEntry-Tags-Schnittstelle auf DebugFailureAnalysisTags zugreifen. Um einen Zeiger auf eine IDebugFAEntry-Schnittstelle abzurufen, rufen Sie die GetDebugFATagControl-Methode der IDebugFailureAnalysis2-Schnittstelle auf.

Jedes Tag verfügt über eine Datentypeigenschaft, die Sie überprüfen können, um den Datentyp der Daten in einem Fehleranalyseeintrag zu bestimmen. Ein Datentyp wird durch einen Wert in der FA_ENTRY_TYPE-Enumeration dargestellt.

Die folgende Codezeile ruft den Datentyp des DEBUG_FLR_BUILD_VERSION_STRING-Tags ab. In diesem Fall ist der Datentyp DEBUG_FA_ENTRY_ANSI_STRING. Im Code pAnalysis ist ein Zeiger auf eine IDebugFailureAnalysis2-Schnittstelle .

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

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

Wenn ein Fehleranalyseeintrag keinen Datenblock aufweist, wird der Datentyp des zugeordneten Tags DEBUG_FA_ENTRY_NO_TYPE.

Denken Sie daran, dass ein DebugFailureAnalysis-Objekt über eine Auflistung von FA-Einträgen verfügt. Verwenden Sie die NextEntry-Methode , um alle FA-Einträge in der Auflistung zu überprüfen. Das folgende Beispiel zeigt, wie die gesamte Auflistung von FA-Einträgen durchlaufen wird. Angenommen , pAnalysis ist ein Zeiger auf eine IDebugFailureAnalysis2-Schnittstelle . Beachten Sie, dass wir den ersten Eintrag erhalten, indem WIR NULL an NextEntry übergeben.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

Ein Tag kann einen Namen und eine Beschreibung haben. Im folgenden Code ist pAnalysis ein Zeiger auf eine IDebugFailureAnalysis-Schnittstelle , pControl ist ein Zeiger auf eine IDebugControl-Schnittstelle und pTags ein Zeiger auf eine IDebugFAEntryTags-Schnittstelle . Der Code zeigt, wie Sie die GetProperties-Methode verwenden, um den Namen und die Beschreibung des Tags abzurufen, das einem FA-Eintrag zugeordnet ist.

#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);

Weitere Informationen

Schreiben benutzerdefinierter Analysedebuggererweiterungen

_EFN_Analyze

Metadatendateien für Analyseerweiterungs-Plug-Ins

IDebugFailureAnalysis2

IDebugFAEntryTags