Compartir a través de


Escribir un complemento de extensión de análisis para extender !analyze

Puede ampliar las funcionalidades del comando !analyze debugger escribiendo un complemento de extensión de análisis. Al proporcionar un complemento de extensión de análisis, puede participar en el análisis de una comprobación de errores o una excepción de una manera específica de su propio componente o aplicación.

Al escribir un complemento de extensión de análisis, también se escribe un archivo de metadatos que describe las situaciones en las que desea que se llame al complemento. Cuando se ejecuta !analyze , busca, carga y ejecuta los complementos de extensión de análisis adecuados.

Para escribir un complemento de extensión de análisis y hacer que esté disponible para !analyze, siga estos pasos.

  • Cree un archivo DLL que exporte una función de _EFN_Analyze .
  • Cree un archivo de metadatos que tenga el mismo nombre que el archivo DLL y una extensión de .alz. Por ejemplo, si el archivo DLL se denomina MyAnalyzer.dll, el archivo de metadatos debe denominarse MyAnalyzer.alz. Para obtener información sobre cómo crear un archivo de metadatos, vea Archivos de metadatos para extensiones de análisis. Coloque el archivo de metadatos en el mismo directorio que el archivo DLL.
  • En el depurador, use el comando .extpath para agregar el directorio a la ruta de acceso del archivo de extensión. Por ejemplo, si el archivo DLL y el archivo de metadatos están en la carpeta denominada c:\MyAnalyzer, escriba el comando .extpath+ c:\MyAnalyzer.

Cuando el comando !analyze se ejecuta en el depurador, el motor de análisis busca en la ruta de acceso del archivo de extensión los archivos de metadatos que tienen la extensión .alz. El motor de análisis lee los archivos de metadatos para determinar qué complementos de extensión de análisis se deben cargar. Por ejemplo, supongamos que el motor de análisis se está ejecutando en respuesta a la comprobación de errores 0xA IRQL_NOT_LESS_OR_EQUAL y lee un archivo de metadatos denominado MyAnalyzer.alz que contiene las siguientes entradas.

PluginId       MyPlugin
DebuggeeClass  Kernel
BugCheckCode   0xA
BugCheckCode   0xE2

La entrada BugCheckCode 0x0A especifica que este complemento quiere participar en el análisis de la 0xA comprobación de errores, por lo que el motor de análisis carga MyAnalyzer.dll (que debe estar en el mismo directorio que MyAnalyzer.alz) y llama a su función _EFN_Analyze .

Nota La última línea del archivo de metadatos debe terminar con un carácter de nueva línea.

Ejemplo de esqueleto

Este es un ejemplo de esqueleto que puede usar como punto de partida.

  1. Cree un archivo DLL denominado MyAnalyzer.dll que exporte la función _EFN_Analyze que se muestra aquí.

    #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. Cree un archivo de metadatos denominado MyAnalyzer.alz que tenga las siguientes entradas.

    PluginId      MyPlugin
    DebuggeeClass Kernel
    BugCheckCode  0xE2
    

    Nota La última línea del archivo de metadatos debe terminar con un carácter de nueva línea.

  3. Establezca una sesión de depuración en modo kernel entre un equipo host y de destino.

  4. En el equipo host, coloque MyAnalyzer.dll y MyAnalyzer.alz en la carpeta c:\MyAnalyzer.

  5. En el equipo host, en el depurador, escriba estos comandos.

    .extpath+ c:\MyAnalyzer

    .estruendo

  6. El comando .crash genera la comprobación de errores 0xE2 MANUALLY_INITIATED_CRASH en el equipo de destino, lo que provoca una interrupción en el depurador en el equipo host. El motor de análisis de comprobación de errores (que se ejecuta en el depurador en el equipo host) lee MyAnalyzer.alz y ve que MyAnalyzer.dll puede participar en el análisis de la comprobación de errores 0xE2. Por lo tanto, el motor de análisis carga MyAnalyzer.dll y llama a su función _EFN_Analyze .

    Compruebe que ve una salida similar a la siguiente en el depurador.

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

La salida del depurador anterior muestra que el motor de análisis llamó a la función _EFN_Analyze cuatro veces: una vez para cada fase del análisis. El motor de análisis pasa el _EFN_Analyze función dos punteros de interfaz. El cliente es una interfaz IDebugClient4 y pAnalysis es una interfaz IDebugFailureAnalysis2 . El código del ejemplo de esqueleto anterior muestra cómo obtener dos punteros de interfaz más. Client->QueryInterface obtiene una interfaz IDebugControl y pAnalysis->GetDebugFATagControl obtiene una interfaz IDebugFAEntryTags .

Entradas, etiquetas y tipos de datos de análisis de errores

El motor de análisis crea un objeto DebugFailureAnalysis para organizar los datos relacionados con un error de código determinado. Un objeto DebugFailureAnalysis tiene una colección de entradas de análisis de errores (entradas fa), cada una de las cuales se representa mediante una estructura de FA_ENTRY . Un complemento de extensión de análisis usa la interfaz IDebugFailureAnalysis2 para obtener acceso a esta colección de entradas fa. Cada entrada de FA tiene una etiqueta que identifica el tipo de información que contiene la entrada. Por ejemplo, una entrada de FA podría tener la etiqueta DEBUG_FLR_BUGCHECK_CODE, que nos indica que la entrada contiene un código de comprobación de errores. Las etiquetas son valores de la enumeración DEBUG_FLR_PARAM_TYPE (definida en extsfns.h), que también se denomina enumeración 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 mayoría de las entradas de FA tienen un bloque de datos asociado. El miembro DataSize de la estructura FA_ENTRY contiene el tamaño del bloque de datos. Algunas entradas de FA no tienen un bloque de datos asociado; toda la información se transmite mediante la etiqueta . En esos casos, el miembro DataSize tiene un valor de 0.

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

Cada etiqueta tiene un conjunto de propiedades: por ejemplo, nombre, descripción y tipo de datos. Un objeto DebugFailureAnalysis está asociado a un objeto DebugFailureAnalysisTags , que contiene una colección de propiedades de etiqueta. En el diagrama siguiente se muestra esta asociación.

Diagrama que muestra el motor de análisis, el objeto DebugFailureAnalysis y el objeto DebugFailureAnalysisTags.

Un objeto DebugFailureAnalysis tiene una colección de entradas fa que pertenecen a una sesión de análisis determinada. El objeto DebugFailureAnalysisTags asociado tiene una colección de propiedades de etiqueta que incluye solo las etiquetas usadas por esa misma sesión de análisis. Como se muestra en el diagrama anterior, el motor de análisis tiene una tabla de etiquetas global que contiene información limitada sobre un gran conjunto de etiquetas que están disponibles con carácter general para su uso en sesiones de análisis.

Normalmente, la mayoría de las etiquetas usadas por una sesión de análisis son etiquetas estándar; es decir, las etiquetas son valores de la enumeración FA_TAG . Sin embargo, un complemento de extensión de análisis puede crear etiquetas personalizadas. Un complemento de extensión de análisis puede agregar una entrada fa a un objeto DebugFailureAnalysis y especificar una etiqueta personalizada para la entrada. En ese caso, las propiedades de la etiqueta personalizada se agregan a la colección de propiedades de etiqueta en el objeto DebugFailureAnalysisTags asociado.

Puede acceder a debugFailureAnalysisTags a través de una interfaz de etiquetas IDebugFAEntry. Para obtener un puntero a una interfaz IDebugFAEntry, llame al método GetDebugFATagControl de la interfaz IDebugFailureAnalysis2 .

Cada etiqueta tiene una propiedad de tipo de datos que puede inspeccionar para determinar el tipo de datos de los datos en una entrada de análisis de errores. Un tipo de datos se representa mediante un valor de la enumeración FA_ENTRY_TYPE .

La siguiente línea de código obtiene el tipo de datos de la etiqueta DEBUG_FLR_BUILD_VERSION_STRING . En este caso, el tipo de datos es DEBUG_FA_ENTRY_ANSI_STRING. En el código, pAnalysis es un puntero a una interfaz IDebugFailureAnalysis2 .

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

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

Si una entrada de análisis de errores no tiene ningún bloque de datos, el tipo de datos de la etiqueta asociada se DEBUG_FA_ENTRY_NO_TYPE.

Recuerde que un objeto DebugFailureAnalysis tiene una colección de entradas fa. Para inspeccionar todas las entradas de FA de la colección, use el método NextEntry . En el ejemplo siguiente se muestra cómo recorrer en iteración toda la colección de entradas fa. Supongamos que pAnalysis es un puntero a una interfaz IDebugFailureAnalysis2 . Observe que obtenemos la primera entrada pasando NULL a NextEntry.

PFA_ENTRY entry = pAnalysis->NextEntry(NULL);

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

   entry = pAnalysis->NextEntry(entry);
}

Una etiqueta puede tener un nombre y una descripción. En el código siguiente, pAnalysis es un puntero a una interfaz IDebugFailureAnalysis , pControl es un puntero a una interfaz IDebugControl y pTags es un puntero a una interfaz IDebugFAEntryTags . El código muestra cómo usar el método GetProperties para obtener el nombre y la descripción de la etiqueta asociada a una entrada 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);

Consulte también

Escritura de extensiones del depurador de análisis personalizado

_EFN_Analyze

Archivos de metadatos para complementos de extensión de análisis

IDebugFailureAnalysis2

IDebugFAEntryTags