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.
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; }
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.
Establezca una sesión de depuración en modo kernel entre un equipo host y de destino.
En el equipo host, coloque MyAnalyzer.dll y MyAnalyzer.alz en la carpeta c:\MyAnalyzer.
En el equipo host, en el depurador, escriba estos comandos.
.extpath+ c:\MyAnalyzer
.estruendo
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.
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
Archivos de metadatos para complementos de extensión de análisis