Share via


撰寫分析延伸模組外掛程式以擴充 !analyze

您可以藉由撰寫分析延伸模組外掛程式來擴充 !analyze 調試程式命令的功能。 藉由提供分析延伸模組外掛程式,您可以參與錯誤檢查或例外狀況的分析,其方式是您自己的元件或應用程式專屬。

當您撰寫分析延伸模組外掛程式時,您也會撰寫元數據檔案,描述您想要呼叫外掛程式的情況。 當 !analyze 執行時,它會找出、載入和執行適當的分析延伸模組外掛程式。

若要撰寫分析延伸模組外掛程式,並讓它可供 !analyze 使用,請遵循下列步驟。

  • 建立導出 _EFN_Analyze 函式的 DLL。
  • 建立元數據檔案,其名稱與您的 DLL 相同,且擴展名為 .alz。 例如,如果您的 DLL 名為 MyAnalyzer.dll,您的元數據檔案必須命名為 MyAnalyzer.alz。 如需如何建立元數據檔案的詳細資訊,請參閱 Analysis Extensions 的元數據檔案。 將元數據檔案放在與 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. 建置名為 MyAnalyzer.dll 的 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 介面, pAnalysisIDebugFailureAnalysis2 介面。 上述基本架構範例中的程式代碼示範如何取得兩個以上的介面指標。 Client->QueryInterface 會取得 IDebugControl 介面,並 pAnalysis->GetDebugFATagControl 取得 IDebugFAEntryTags 介面。

失敗分析專案、標記和數據類型

分析引擎會建立 DebugFailureAnalysis 物件,以組織與特定程式代碼失敗相關的數據。 DebugFailureAnalysis 物件具有失敗分析專案的集合, (FA專案) ,每個專案都以FA_ENTRY結構表示。 分析延伸模組外掛程式會使用 IDebugFailureAnalysis2 介面來存取此FA專案集合。 每個FA專案都有一個標記,可識別專案所包含的資訊種類。 例如,FA 專案可能會有 標籤DEBUG_FLR_BUGCHECK_CODE,告知我們專案包含錯誤檢查碼。 卷標是在 extsfns.h) 中定義的 DEBUG_FLR_PARAM_TYPE 列舉 (值,也稱為 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專案 都有相關聯的數據區塊。 FA_ENTRY 結構的 DataSize 成員會保存數據區塊的大小。 某些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 物件中的標記屬性集合。

您可以透過 IDebugFAEntry 標記介面來存取 DebugFailureAnalysisTags 。 若要取得 IDebugFAEntry 介面的指標,請呼叫 IDebugFailureAnalysis2 介面的 GetDebugFATagControl 方法。

每個標記都有數據類型屬性,您可以檢查以判斷失敗分析項目中數據的數據類型。 數據類型是以 FA_ENTRY_TYPE 列舉中的值表示。

下列程式代碼行會取得 DEBUG_FLR_BUILD_VERSION_STRING 標記的數據類型。 在此情況下,數據類型 會DEBUG_FA_ENTRY_ANSI_STRING。 在程序代碼中, pAnalysisIDebugFailureAnalysis2 介面的指標。

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專案集合。 假設 pAnalysisIDebugFailureAnalysis2 介面的指標。 請注意,我們會將 NULL 傳遞至 NextEntry 來取得第一個專案。

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

標籤可以有名稱和描述。 在下列程式代碼中, pAnalysisIDebugFailureAnalysis 介面的指標, pControlIDebugControl 介面的指標,而且 pTagsIDebugFAEntryTags 介面的指標。 此程式代碼示範如何使用 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