正在写入分析扩展插件!分析Writing an Analysis Extension Plugin to Extend !analyze

可以通过编写分析扩展插件来扩展 !分析调试器命令的功能。You can extend the capabilities of the !analyze debugger command by writing an analysis extension plugin. 通过提供分析扩展插件,您可以以特定于您自己的组件或应用程序的方式参与对 bug 检查或异常的分析。By providing an analysis extension plugin, you can participate in the analysis of a bug check or an exception in a way that is specific to your own component or application.

编写分析扩展插件时,还需要编写一个元数据文件,用于描述要为其调用插件的情况。When you write an analysis extension plugin, you also write a metadata file that describes the situations for which you want your plugin to be called. !分析运行时,它会查找、加载和运行相应的分析扩展插件。When !analyze runs, it locates, loads, and runs the appropriate analysis extension plugins.

若要写入分析扩展插件并使其可用于 !分析,请执行以下步骤。To write an analysis extension plugin and make it available to !analyze, follow these steps.

  • 创建一个 DLL,该 DLL 导出 _EFN_分析函数。Create a DLL that exports an _EFN_Analyze function.
  • 创建与您的 DLL 同名的元数据文件,并创建 alz 扩展名。Create a metadata file that has the same name as your DLL and an extension of .alz. 例如,如果您的 DLL 名为 MyAnalyzer,则元数据文件必须命名为 MyAnalyzer. alz。For example, if your DLL is named MyAnalyzer.dll, your metadata file must be named MyAnalyzer.alz. 有关如何创建元数据文件的信息,请参阅Analysis extension 的元数据文件For information about how to create a metadata file, see Metadata Files for Analysis Extensions. 将元数据文件放在与 DLL 相同的目录中。Place the metadata file in the same directory as your DLL.
  • 在调试器中,使用extpath命令将目录添加到扩展文件路径。In the debugger, use the .extpath command to add your directory to the extension file path. 例如,如果 DLL 和元数据文件位于名为 c:\MyAnalyzer 的文件夹中,请输入extpath + c:\MyAnalyzerFor example, if your DLL and metadata file are in the folder named c:\MyAnalyzer, enter the command .extpath+ c:\MyAnalyzer.

当 "分析" 命令在调试器中运行时,分析引擎会在扩展文件路径中查找扩展名为 alz 的元数据文件。When the !analyze command runs in the debugger, the analysis engine looks in the extension file path for metadata files that have the .alz extension. 分析引擎读取元数据文件,以确定应加载哪些分析扩展插件。The analysis engine reads the metadata files to determine which analysis extension plugins should be loaded. 例如,假设分析引擎正在运行,以响应错误检查,0xA IRQL_不__或_相等,并且读取名为 MyAnalyzer alz 的元数据文件,该文件包含以下条目。For example, suppose the analysis engine is running in response to Bug Check 0xA IRQL_NOT_LESS_OR_EQUAL, and it reads a metadata file named MyAnalyzer.alz that contains the following entries.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

条目 BugCheckCode 0x0A 指定此插件要参与 Bug 检查0xA 分析,以便分析引擎加载 MyAnalyzer (它必须位于与 MyAnalyzer 相同的目录中,并调用其 _EFN_分析函数。The entry BugCheckCode 0x0A specifies that this plugin wants to participate in the analysis of Bug Check 0xA, so the analysis engine loads MyAnalyzer.dll (which must be in the same directory as MyAnalyzer.alz) and calls its _EFN_Analyze function.

请注意  元数据文件的最后一行必须以换行符结尾。Note  The last line of the metadata file must end with a newline character.

框架示例Skeleton Example

下面是一个框架示例,可以将其用作起始点。Here is a skeleton example that you can use as a starting point.

  1. 生成一个名为 MyAnalyzer 的 DLL,该 DLL 将导出此处显示的 _EFN_分析函数。Build a DLL named MyAnalyzer.dll that exports the _EFN_Analyze function shown here.

    #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 的元数据文件,该文件包含以下条目。Create a metadata file named MyAnalyzer.alz that has the following entries.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    请注意  元数据文件的最后一行必须以换行符结尾。Note  The last line of the metadata file must end with a newline character.

  3. 建立主机和目标计算机之间的内核模式调试会话。Establish a kernel-mode debugging session between a host and target computer.

  4. 在主计算机上,将 MyAnalyzer 和 MyAnalyzer 放在文件夹 c:\MyAnalyzer 中。On the host computer, put MyAnalyzer.dll and MyAnalyzer.alz in the folder c:\MyAnalyzer.

  5. 在主计算机上的调试器中,输入以下命令。On the host computer, in the debugger, enter these commands.

    . extpath + c:\MyAnalyzer.extpath+ c:\MyAnalyzer

    。崩溃.crash

  6. 崩溃命令手动生成 Bug 检查 0xE2_在目标计算机上启动_崩溃,这会导致主计算机上的调试器中断。The .crash command generates Bug Check 0xE2 MANUALLY_INITIATED_CRASH on the target computer, which causes a break in to the debugger on the host computer. Bug 检查分析引擎(在主计算机上的调试器中运行)读取 MyAnalyzer,并发现 MyAnalyzer 能够参与分析 bug 检查0xE2。The bug check analysis engine (running in the debugger on the host computer) reads MyAnalyzer.alz and sees that MyAnalyzer.dll is able to participate in analyzing bug check 0xE2. 因此,分析引擎加载 MyAnalyzer 并调用其 _EFN_分析函数。So the analysis engine loads MyAnalyzer.dll and calls its _EFN_Analyze function.

    验证是否在调试器中看到类似于下面的输出。Verify that you see output similar to the following in the 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.
    

以上调试器输出显示,分析引擎调用 _EFN_分析函数四次:一次针对分析的每个阶段。The preceding debugger output shows that the analysis engine called the _EFN_Analyze function four times: once for each phase of the analysis. 分析引擎传递 _EFN_分析函数两个接口指针。The analysis engine passes the _EFN_Analyze function two interface pointers. 客户端是一个IDebugClient4接口, pAnalysis是一个IDebugFailureAnalysis2接口。Client is an IDebugClient4 interface, and pAnalysis is an IDebugFailureAnalysis2 interface. 上述框架示例中的代码演示了如何获取另外两个接口指针。The code in the preceding skeleton example shows how to obtain two more interface pointers. Client->QueryInterface 获取IDebugControl接口,pAnalysis->GetDebugFATagControl 获取IDebugFAEntryTags接口。Client->QueryInterface gets an IDebugControl interface, and pAnalysis->GetDebugFATagControl gets an IDebugFAEntryTags interface.

故障分析条目、标记和数据类型Failure Analysis Entries, Tags, and Data Types

分析引擎将创建一个DebugFailureAnalysis对象,以组织与特定代码失败有关的数据。The analysis engine creates a DebugFailureAnalysis object to organize the data related to a particular code failure. DebugFailureAnalysis对象具有一系列失败分析条目(fa 条目),其中每个条目都由一个FA_条目结构表示。A DebugFailureAnalysis object has a collection of failure analysis entries (FA entries), each of which is represented by an FA_ENTRY structure. 分析扩展插件使用IDebugFailureAnalysis2接口来访问此 FA 项集合。An analysis extension plugin uses the IDebugFailureAnalysis2 interface to get access to this collection of FA entries. 每个 FA 项都有一个标记,用于标识该项包含的信息的类型。Each FA entry has a tag that identifies the kind of information that the entry contains. 例如,FA 条目可能包含标记DEBUG_FLR_错误检测_代码,这表明该条目包含 bug 检查代码。For example, an FA entry might have the tag DEBUG_FLR_BUGCHECK_CODE, which tells us that the entry contains a bug check code. 标记是DEBUG_FLR_PARAM_类型枚举中的值(在 extsfns 中定义),也称为FA_标记枚举。Tags are values in the DEBUG_FLR_PARAM_TYPE enumeration (defined in extsfns.h), which is also called the FA_TAG enumeration.

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 条目都具有关联的数据块。Most FA entries have an associated data block. FA_条目结构的DataSize成员保存数据块的大小。The DataSize member of the FA_ENTRY structure holds the size of the data block. 有些 FA 条目没有关联的数据块;所有信息都由标记传达。Some FA entries do not have an associated data block; all the information is conveyed by the tag. 在这些情况下, DataSize成员的值为0。In those cases, the DataSize member has a value of 0.

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

每个标记都有一组属性:例如,名称、说明和数据类型。Each tag has a set of properties: for example, name, description, and data type. DebugFailureAnalysis对象与DebugFailureAnalysisTags对象关联,后者包含标记属性的集合。A DebugFailureAnalysis object is associated with a DebugFailureAnalysisTags object, which contains a collection of tag properties. 下图说明了此关联。The following diagram illustrates this association.

显示分析引擎、debugfailureanalysis 对象和 debugfailureanalysistags 对象的关系图

DebugFailureAnalysis对象具有属于特定分析会话的FA 条目的集合。A DebugFailureAnalysis object has a collection of FA entries that belong to a particular analysis session. 关联的DebugFailureAnalysisTags对象具有标记属性的集合,这些属性仅包括该相同分析会话所使用的标记。The associated DebugFailureAnalysisTags object has a collection of tag properties that includes only the tags used by that same analysis session. 如前面的关系图所示,分析引擎具有一个全局标记表,其中包含有关分析会话通常可以使用的大量标记的信息。As the preceding diagram shows, the analysis engine has a global tag table that holds limited information about a large set of tags that are generally available for use by analysis sessions.

分析会话使用的大多数标记通常是标准标记;也就是说,标记是FA_标记枚举中的值。Typically most of the tags used by an analysis session are standard tags; that is, the tags are values in the FA_TAG enumeration. 不过,分析扩展插件可以创建自定义标记。However, an analysis extension plug-in can create custom tags. 分析扩展插件可以将FA 条目添加到DebugFailureAnalysis对象,并为该条目指定自定义标记。An analysis extension plug-in can add an FA entry to a DebugFailureAnalysis object and specify a custom tag for the entry. 在这种情况下,自定义标记的属性将添加到关联的DebugFailureAnalysisTags对象中的标记属性集合。In that case, properties for the custom tag are added to the collection of tag properties in the associated DebugFailureAnalysisTags object.

可以通过 IDebugFAEntry 标记界面访问DebugFailureAnalysisTagsYou can access a DebugFailureAnalysisTags through an IDebugFAEntry tags interface. 若要获取指向 IDebugFAEntry 接口的指针,请调用IDebugFailureAnalysis2接口的GetDebugFATagControl方法。To get a pointer to an IDebugFAEntry interface, call the GetDebugFATagControl method of the IDebugFailureAnalysis2 interface.

每个标记都有一个数据类型属性,您可以通过检查该属性来确定失败分析条目中的数据的数据类型。Each tag has a data type property that you can inspect to determine the data type of the data in a failure analysis entry. 数据类型由FA_条目中的值表示_类型枚举。A data type is represented by a value in the FA_ENTRY_TYPE enumeration.

下面的代码行获取调试_FLR_生成_版本_字符串标记的数据类型。The following line of code gets the data type of the DEBUG_FLR_BUILD_VERSION_STRING tag. 在这种情况下,数据类型为DEBUG_FA_条目_ANSI_字符串In this case, the data type is DEBUG_FA_ENTRY_ANSI_STRING. 在代码中,pAnalysis 是指向IDebugFailureAnalysis2接口的指针。In the code, pAnalysis is a pointer to an IDebugFailureAnalysis2 interface.

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

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

如果失败分析条目没有数据块,则关联标记的数据类型为DEBUG_FA_条目_不_类型If a failure analysis entry has no data block, the data type of the associated tag is DEBUG_FA_ENTRY_NO_TYPE.

回忆一下, DebugFailureAnalysis对象具有FA 条目的集合。Recall that a DebugFailureAnalysis object has a collection of FA entries. 若要检查集合中的所有 FA 条目,请使用NextEntry方法。To inspect all the FA entries in the collection, use the NextEntry method. 下面的示例演示如何循环访问 FA 条目的整个集合。The following example shows how to iterate through the entire collection of FA entries. 假设pAnalysis是指向IDebugFailureAnalysis2接口的指针。Assume that pAnalysis is a pointer to an IDebugFailureAnalysis2 interface. 请注意,我们通过将NULL传递到NextEntry获取第一个条目。Notice that we get the first entry by passing NULL to NextEntry.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

标记可以有名称和说明。A tag can have a name and a description. 在下面的代码中, pAnalysis是指向IDebugFailureAnalysis接口的指针, pControl是指向IDebugControl接口的指针,pTags 是指向IDebugFAEntryTags接口的指针。In the following code, pAnalysis is a pointer to an IDebugFailureAnalysis interface, pControl is a pointer to an IDebugControl interface, and pTags is a pointer to an IDebugFAEntryTags interface. 此代码演示如何使用GetProperties方法获取与FA 条目关联的标记的名称和说明。The code shows how to use the GetProperties method to get the name and description of the tag associated with an FA entry.

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

相关主题Related topics

编写自定义分析调试器扩展Writing Custom Analysis Debugger Extensions

_EFN_分析_EFN_Analyze

分析扩展插件的元数据文件Metadata Files for Analysis Extension Plug-ins

IDebugFailureAnalysis2IDebugFailureAnalysis2

IDebugFAEntryTagsIDebugFAEntryTags