Написание расширяющего плагина анализа для расширения !analyze

Вы можете расширить возможности команды отладчика !analysis, написав подключаемый модуль расширения анализа. Предоставляя подключаемый модуль расширения анализа, вы можете участвовать в анализе проверки ошибок или исключения таким образом, который зависит от собственного компонента или приложения.

При написании подключаемого модуля расширения анализа также создается файл метаданных, описывающий ситуации, для которых требуется вызвать подключаемый модуль. При выполнении !analyze он находит, загружает и запускает соответствующие плагины расширения анализа.

Чтобы написать подключаемый модуль расширения анализа и сделать его доступным для !analysis, выполните следующие действия.

  • Создайте библиотеку DLL, которая экспортирует функцию _EFN_Analyze .
  • Создайте файл метаданных с тем же именем, что и ваша библиотека DLL и расширением .alz. Например, если библиотека DLL называется MyAnalyzer.dll, файл метаданных должен называться MyAnalyzer.alz. Сведения о создании файла метаданных см. в разделе "Файлы метаданных" для расширений анализа. Поместите файл метаданных в тот же каталог, что и библиотека DLL.
  • В отладчике используйте команду EXtpath , чтобы добавить каталог в путь к файлу расширения. Например, если файл DLL и метаданных находятся в папке c:\ MyAnalyzer, введите команду .extpath+ c:\MyAnalyzer.

При выполнении команды !analyze в отладчике анализирующая система проверяет путь к файлам расширений на наличие файлов метаданных с расширением .alz. Модуль анализа считывает файлы метаданных, чтобы определить, какие подключаемые модули для анализа должны быть загружены. Например, предположим, что подсистема анализа выполняется в ответ на проверку ошибок 0xA IRQL_NOT_LESS_OR_EQUAL, и она считывает файл метаданных с именем MyAnalyzer.alz, содержащий следующие записи.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

Запись BugCheckCode 0x0A указывает, что этот подключаемый модуль хочет участвовать в анализе проверки ошибок 0xA, поэтому модуль анализа загружает MyAnalyzer.dll (который должен находиться в том же каталоге, что и MyAnalyzer.alz) и вызывает его функцию _EFN_Analyze.

Заметка Последняя строка файла метаданных должна заканчиваться символом новой строки.

Пример скелета

Ниже приведен пример скелета, который можно использовать в качестве отправной точки.

  1. Создайте библиотеку DLL с именем MyAnalyzer.dll, которая экспортирует функцию _EFN_Analyze , показанную здесь.

    #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. Создайте файл метаданных с именем MyAnalyzer.alz, имеющий следующие записи.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    Заметка Последняя строка файла метаданных должна заканчиваться символом новой строки.

  3. Установите сеанс отладки в режиме ядра между узлом и целевым компьютером.

  4. На хост-компьютере поместите MyAnalyzer.dll и MyAnalyzer.alz в папку c:\MyAnalyzer.

  5. На хост-компьютере в отладчике введите эти команды.

    .extpath+ c:\MyAnalyzer

    .авария

  6. Команда .crash вызывает сбой с кодом 0xE2 MANUALLY_INITIATED_CRASH на целевом компьютере, что приводит к прерыванию отладки на хост-компьютере. Модуль анализа ошибок (работающий в отладчике на хост-компьютере) считывает MyAnalyzer.alz и видит, что MyAnalyzer.dll может участвовать в анализе проверки ошибок 0xE2. Поэтому подсистема анализа загружает MyAnalyzer.dll и вызывает ее функцию _EFN_Analyze .

    Убедитесь, что в отладчике отображаются выходные данные, аналогичные приведенным ниже.

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

Предыдущие выходные данные отладчика показывают, что подсистема анализа вызвала функцию _EFN_Analyze четыре раза: один раз для каждого этапа анализа. Подсистема анализа передает функции _EFN_Analyze два указателя интерфейса. Клиент — это интерфейс IDebugClient4, а pAnalysis — это интерфейс IDebugFailureAnalysis2. В приведенном выше примере скелета кода показано, как получить еще два указателя интерфейса. Client->QueryInterface получает интерфейс IDebugControl и pAnalysis->GetDebugFATagControl получает интерфейс IDebugFAEntryTags .

Записи анализа сбоев, теги и типы данных

Подсистема анализа создает объект DebugFailureAnalysis для упорядочивания данных, связанных с определенным сбоем кода. Объект DebugFailureAnalysis содержит коллекцию записей анализа сбоев (ЗАПИСИ FA), каждый из которых представлен структурой FA_ENTRY . Подключаемый модуль расширения анализа использует интерфейс IDebugFailureAnalysis2 для получения доступа к этой коллекции записей FA. Каждая запись FA содержит тег, определяющий тип сведений, содержащихся в записи. Например, запись FA может иметь тег DEBUG_FLR_BUGCHECK_CODE, который сообщает нам, что запись содержит код проверки ошибок. Теги — это перечисление значений DEBUG_FLR_PARAM_TYPE (определённом в extsfns.h), которое также называется перечислением 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;

Большинство записей FA имеют связанный блок данных. Элемент DataSize структуры FA_ENTRY содержит размер блока данных. Некоторые записи FA не имеют связанного блока данных; все сведения передаются тегом. В таких случаях элемент DataSize имеет значение 0.

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

Каждый тег имеет набор свойств: например, имя, описание и тип данных. Объект DebugFailureAnalysis связан с объектом DebugFailureAnalysisTags, который содержит коллекцию свойств тегов. На следующей схеме показана эта связь.

Схема, на которой показан модуль анализа, объект DebugFailureAnalysis и объект DebugFailureAnalysisTags.

Объект DebugFailureAnalysis содержит коллекцию записей FA , принадлежащих определенному сеансу анализа. Связанный объект DebugFailureAnalysisTags содержит коллекцию свойств тегов, включающих только теги, используемые тем же сеансом анализа. Как показано на приведенной выше схеме, подсистема анализа содержит глобальную таблицу тегов, содержащую ограниченную информацию о большом наборе тегов, которые обычно доступны для использования сеансами анализа.

Как правило, большинство тегов, используемых сеансом анализа, являются стандартными тегами; То есть теги — это значения в перечислении FA_TAG . Однако подключаемый модуль расширения анализа может создавать пользовательские теги. Подключаемый модуль расширения анализа может добавить запись FA в объект DebugFailureAnalysis и указать пользовательский тег для записи. В этом случае свойства настраиваемого тега добавляются в коллекцию свойств тегов в связанном объекте DebugFailureAnalysisTags .

Доступ к DebugFailureAnalysisTags можно получить через интерфейс тегов IDebugFAEntry. Чтобы получить указатель на интерфейс IDebugFAEntry, вызовите метод GetDebugFATagControl интерфейса IDebugFailureAnalysis2 .

Каждый тег имеет свойство типа данных, которое можно проверить, чтобы определить тип данных в записи анализа сбоев. Тип данных представлен значением в перечислении FA_ENTRY_TYPE .

Следующая строка кода получает тип данных тега DEBUG_FLR_BUILD_VERSION_STRING . В этом случае тип данных — DEBUG_FA_ENTRY_ANSI_STRING. В коде pAnalysis является указателем на интерфейс IDebugFailureAnalysis2.

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

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

Если в записи анализа сбоев отсутствует блок данных, то тип данных связанного тега — DEBUG_FA_ENTRY_NO_TYPE.

Помните, что объект DebugFailureAnalysis содержит коллекцию записей FA. Чтобы проверить все записи FA в коллекции, используйте метод NextEntry . В следующем примере показано, как выполнять итерацию по всей коллекции записей FA. Предположим, что pAnalysis — это указатель на интерфейс IDebugFailureAnalysis2 . Обратите внимание, что мы получаем первую запись, передав значение NULL в NextEntry.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

Тег может иметь имя и описание. В следующем коде pAnalysis — это указатель на интерфейс IDebugFailureAnalysis , pControl — это указатель на интерфейс IDebugControl , а pTags также указатель на интерфейс IDebugFAEntryTags . В коде показано, как использовать метод GetProperties для получения имени и описания тега, связанного с записью 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);

См. также

Написание расширений отладчика пользовательского анализа

_EFN_Analyze

Файлы метаданных для подключаемых модулей расширения анализа

IDebugFailureAnalysis2

IDebugFAEntryTags