Interfaces de C++ del modelo de datos del depurador
En este tema se proporciona información general sobre cómo usar interfaces de C++ del modelo de datos del depurador para ampliar y personalizar las funcionalidades del depurador.
Interfaces de host de C++ del modelo de datos del depurador
Host del modelo de datos del depurador
El modelo de datos del depurador está diseñado para ser un sistema componente que se puede hospedar en una variedad de contextos diferentes. Normalmente, el modelo de datos se hospeda en el contexto de una aplicación del depurador. Para ser un host del modelo de datos, es necesario implementar una serie de interfaces para exponer aspectos básicos del depurador: su destino, sus espacios de memoria, su evaluador, su sistema simbólico y de tipos, etc. Aunque estas interfaces se implementan mediante cualquier aplicación que quiera hospedar el modelo de datos, tanto el modelo de datos principal como cualquier extensión que interopera con el modelo de datos.
El conjunto de interfaces principales son:
Nombre de la interfaz | Descripción |
---|---|
IDebugHost | Interfaz principal del host de depuración. |
IDebugHostStatus | Interfaz que permite a un cliente consultar el estado del host. |
IDebugHostContext | Una abstracción de un contexto dentro del host (por ejemplo: un destino determinado, un proceso determinado, un espacio de direcciones determinado, etc....) |
IDebugHostErrorSink | Interfaz implementada por los autores de llamadas para recibir errores de determinadas partes del modelo de datos y host |
IDebugHostEvaluator / IDebugHostEvaluator2 | Evaluador de expresiones del host de depuración. |
IDebugHostExtensibility | Interfaz para ampliar las funcionalidades del host o partes de él (como el evaluador de expresiones). |
El sistema de tipos y las interfaces simbólicas son:
InterfaceName | Descripción |
---|---|
IDebugHostSymbols | Interfaz principal que proporciona acceso y resolución de símbolos |
IDebugHostSymbol / IDebugHostSymbol2 | Representa un único símbolo de cualquier tipo. El símbolo concreto es una derivación de esta interfaz. |
IDebugHostModule | Representa un módulo cargado dentro de un proceso. Se trata de un tipo de símbolo. |
IDebugHostType / IDebugHostType2 | Representa un tipo de idioma o nativo. |
IDebugHostConstant | Representa una constante dentro de la información simbólica (por ejemplo: un argumento de plantilla que no es de tipo en C++) |
IDebugHostField | Representa un campo dentro de una estructura o clase. |
IDebugHostData | Representa los datos de un módulo (si se tratase de una estructura o clase, sería un IDebugHostField) |
IDebugHostBaseClass | Representa una clase base. |
IDebugHostPublic | Representa un símbolo dentro de la tabla publics de una PDB. Esto no tiene información de tipo asociada. Es un nombre y una dirección. |
IDebugHostModuleSignature | Representa una firma de módulo: una definición que coincidirá con un conjunto de módulos por nombre o versión. |
IDebugHostTypeSignature | Representa una firma de tipo: una definición que coincidirá con un conjunto de tipos por módulo o nombre. |
Interfaz de host principal: IDebugHost
La interfaz IDebugHost es la interfaz principal de cualquier host de modelo de datos. Se define de la manera siguiente:
DECLARE_INTERFACE_(IDebugHost, IUnknown)
{
STDMETHOD(GetHostDefinedInterface)(_COM_Outptr_ IUnknown** hostUnk) PURE;
STDMETHOD(GetCurrentContext)(_COM_Outptr_ IDebugHostContext** context) PURE;
STDMETHOD(GetDefaultMetadata)(_COM_Outptr_ IKeyStore** defaultMetadataStore) PURE;
}
El método GetHostDefinedInterface devuelve la interfaz privada principal del host, si existe para el host determinado. En herramientas de depuración para Windows, la interfaz devuelta aquí es IDebugClient (conversión a IUnknown).
El método GetCurrentContext devuelve una interfaz que representa el estado actual del host del depurador. El significado exacto de esto se deja en el host, pero normalmente incluye elementos como la sesión, el proceso y el espacio de direcciones que está activo en la interfaz de usuario del host de depuración. El objeto de contexto devuelto es en gran medida opaco para el autor de la llamada, pero es un objeto importante pasar entre llamadas al host de depuración. Cuando un llamador es, por ejemplo, leer la memoria, es importante saber desde qué proceso y espacio de direcciones se lee la memoria. Esa noción se encapsula en la noción del objeto de contexto que se devuelve de este método.
El método GetDefaultMetadata devuelve un almacén de metadatos predeterminado que se puede usar para determinadas operaciones (por ejemplo: conversión de cadena) cuando no se han pasado metadatos explícitos. Esto permite que el host de depuración tenga algún control sobre la forma en que se presentan algunos datos. Por ejemplo, los metadatos predeterminados pueden incluir una clave PreferredRadix, lo que permite al host indicar si los ordinales deben mostrarse en decimal o hexadecimal si no se especifica de otro modo.
Tenga en cuenta que los valores de propiedad del almacén de metadatos predeterminados deben resolverse manualmente y deben pasar el objeto para el que se consultan los metadatos predeterminados. El método GetKey debe usarse en lugar de GetKeyValue.
Interfaz de estado: IDebugHostStatus
La interfaz IDebugHostStatus permite que un cliente del modelo de datos o el host de depuración pregunten sobre ciertos aspectos del estado del host de depuración. La interfaz se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostStatus, IUnknown)
{
STDMETHOD(PollUserInterrupt)(_Out_ bool* interruptRequested) PURE;
}
El método PollUserInterrupt se usa para preguntar si el usuario del host de depuración ha solicitado una interrupción de la operación actual. Un descriptor de acceso de propiedad en el modelo de datos puede, por ejemplo, llamar a código arbitrario (por ejemplo: un método de JavaScript). Ese código puede tardar un tiempo arbitrario. Para mantener la capacidad de respuesta del host de depuración, cualquier código que pueda tardar un tiempo arbitrario debe comprobar si hay una solicitud de interrupción mediante una llamada a este método. Si el valor interruptRequested vuelve como true, el autor de la llamada debe anular inmediatamente y devolver un resultado de E_ABORT.
Interfaz de contexto: IDebugHostContext
El contexto es uno de los aspectos más importantes del modelo de datos y el host de depuración subyacente. Al contener un objeto, es importante poder saber de dónde procede un objeto, en qué proceso se encuentra, con qué espacio de direcciones está asociado. Conocer esta información permite la interpretación correcta de cosas como los valores de puntero. Un objeto del tipo IDebugHostContext debe pasarse a muchos métodos en el host de depuración. Esta interfaz se puede adquirir de varias maneras:
- Obteniendo el contexto actual del depurador: llamando al método GetCurrentContext de IDebugHost
- Obteniendo el contexto de un objeto: llamando al método GetContext de IModelObject
- Obteniendo el contexto de un símbolo: llamando al método GetContext de IDebugHostSymbol
Además, hay dos valores que tienen un significado especial en el contexto de una interfaz IDebugHostContext que se devuelve o se pasa a un modelo de datos o a un método host de depuración:
nullptr: indica que no hay ningún contexto. Es perfectamente válido para que algunos objetos no tengan contexto. El objeto Debugger del espacio de nombres raíz del modelo de datos no hace referencia a nada dentro de un proceso o espacio de direcciones específico. No tiene contexto.
USE_CURRENT_HOST_CONTEXT: un valor centinela que indica que debe usar el contexto de interfaz de usuario actual del host de depuración. Este valor nunca se devolverá desde el host de depuración. Sin embargo, puede pasarse a cualquier método host de depuración que tome una entrada IDebugHostContext en lugar de llamar explícitamente al método GetCurrentContext de IDebugHost. Tenga en cuenta que pasar explícitamente USE_CURRENT_HOST_CONTEXT suele ser más eficaz que obtener explícitamente el contexto actual.
Los contextos de un contexto de host son en gran medida opacos para el autor de la llamada. La única operación que un autor de la llamada fuera del host de depuración principal puede hacer con un contexto de host es compararlo con otro contexto de host.
La interfaz IDebugHostContext se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostContext, IUnknown)
{
STDMETHOD(IsEqualTo)(_In_ IDebugHostContext *pContext, _Out_ bool *pIsEqual) PURE;
}
El método IsEqualTo compara un contexto de host con otro contexto de host. Si los dos contextos son equivalentes, se devuelve una indicación de esto. Tenga en cuenta que esta comparación no es equivalencia de interfaz. Esto compara el contenido opaco subyacente del propio contexto.
El receptor de errores: IDebugHostErrorSink
IDebugHostErrorSink es un medio por el que un cliente puede recibir notificaciones de errores que se producen durante determinadas operaciones y enrutar esos errores cuando sea necesario. La interfaz se define de la siguiente manera:
enum ErrorClass
{
ErrorClassWarning,
ErrorClassError
}
DECLARE_INTERFACE_(IDebugHostErrorSink, IUnknown)
{
STDMETHOD(ReportError)(_In_ ErrorClass errClass, _In_ HRESULT hrError, _In_ PCWSTR message) PURE;
}
El método ReportError es una devolución de llamada en el receptor de errores para notificarle que se ha producido un error y permitir que el receptor enrute el error a cualquier interfaz de usuario o mecanismo que sea adecuado.
Evaluador de host: IDebugHostEvaluator / IDebugHostEvaluator2
Una de las partes más importantes de la funcionalidad que proporciona el host de depuración a los clientes es el acceso a su evaluador de expresiones basadas en lenguaje. Las interfaces IDebugHostEvaluator e IDebugHostEvaluator2 son los medios para acceder a esa funcionalidad desde el host de depuración.
Las interfaces se definen de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostEvaluator2, IDebugHostEvaluator)
{
//
// IDebugHostEvaluator:
//
STDMETHOD(EvaluateExpression)(_In_ IDebugHostContext* context, _In_ PCWSTR expression, _In_opt_ IModelObject* bindingContext, _COM_Errorptr_ IModelObject** result, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(EvaluateExtendedExpression)(_In_ IDebugHostContext* context, _In_ PCWSTR expression, _In_opt_ IModelObject* bindingContext, _COM_Errorptr_ IModelObject** result, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
//
// IDebugHostEvaluator2:
//
STDMETHOD(AssignTo)(_In_ IModelObject* assignmentReference, _In_ IModelObject* assignmentValue, _COM_Errorptr_ IModelObject** assignmentResult, _COM_Outptr_opt_result_maybenull_ IKeyStore** assignmentMetadata) PURE;
}
El método EvaluateExpression permite que el host de depuración evalúe una expresión de lenguaje (por ejemplo, C++) y devuelva el valor resultante de esa evaluación de expresión boxing como IModelObject. Esta variante concreta del método solo permite construcciones de lenguaje. Cualquier funcionalidad adicional que se presente en el evaluador de expresiones del host de depuración que no esté presente en el lenguaje (por ejemplo: métodos de consulta LINQ) está desactivada para la evaluación.
El método EvaluateExtendedExpression es similar al método EvaluateExpression, salvo que vuelve a activar la funcionalidad adicional que no es de lenguaje que un host de depuración determinado elige agregar a su evaluador de expresiones. En herramientas de depuración para Windows, por ejemplo, esto habilita tipos anónimos, consultas LINQ, calificadores de módulo, especificadores de formato y otras funciones que no son de C/C++.
IDebugHostEvaluator2
El método AssignTo realiza la asignación según la semántica del lenguaje que se está depurando.
Interfaz de extensibilidad de host: IDebugHostExtensibility
Cierta funcionalidad del host de depuración está opcionalmente sujeta a extensibilidad. Esto puede incluir, por ejemplo, el evaluador de expresiones. La interfaz IDebugHostExtensibility es el medio por el que se accede a estos puntos de extensibilidad. La interfaz se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostExtensibility, IUnknown)
{
STDMETHOD(CreateFunctionAlias)(_In_ PCWSTR aliasName, _In_ IModelObject *functionObject) PURE;
STDMETHOD(DestroyFunctionAlias)(_In_ PCWSTR aliasName) PURE;
}
El método CreateFunctionAlias crea un "alias de función", un "alias rápido" para un método implementado en alguna extensión. El significado de este alias es específico del host. Puede extender el evaluador de expresiones del host con la función o puede hacer algo completamente diferente.
El método DestroyFunctionAlias deshace una llamada anterior al método CreateFunctionAlias. La función ya no estará disponible en el nombre de alias rápido.
Acceso al modelo de datos
En primer lugar, las API de extensibilidad del modelo de datos están diseñadas para ser neutrales para la aplicación (normalmente un depurador) que actúa como host del modelo de datos. En teoría, cualquier aplicación puede hospedar el modelo de datos proporcionando un conjunto de API de host que exponen el sistema de tipos de los destinos de depuración de la aplicación y un conjunto de objetos proyectados en el espacio de nombres del modelo de datos sobre qué destinos, procesos, subprocesos, etc. están en esos destinos de depuración.
Aunque las API del modelo de datos (las que comienzan IDataModel, IDebugHost y las salidas de IModelObject) están diseñadas para ser portátiles, no definen lo que es una "extensión del depurador". En la actualidad, un componente que desea ampliar las herramientas de depuración para Windows y el motor que proporciona debe escribir una extensión de motor para obtener acceso al modelo de datos. Esa extensión del motor solo debe ser una extensión de motor tanto como ese es el mecanismo de carga y arranque de la extensión. Por lo tanto, una implementación mínima proporcionaría:
- DebugExtensionInitialize: un método que utiliza un IDebugClient creado para obtener acceso al modelo de datos y configurar manipulaciones del modelo de objetos.
- DebugExtensionUninitialize: método que deshace las manipulaciones del modelo de objetos que se realizaron en DebugExtensionInitialize.
- DebugExtensionCanUnload: método que devuelve si la extensión puede descargarse. Si todavía hay objetos COM activos en la extensión, debe indicarlo. Este es el equivalente del depurador de DllCanUnloadNow de COM. Si devuelve el S_FALSE indicación de incapacidad de descargar, el depurador puede consultarlo más adelante para ver si una descarga es segura o puede reinicializar la extensión llamando de nuevo a DebugExtensionInitialize. La extensión debe estar preparada para controlar ambas rutas de acceso.
- DebugExtensionUnload: un método que realiza cualquier limpieza final necesaria justo antes de que se descargue la DLL.
Interfaz bridge: IHostDataModelAccess
Como se mencionó, cuando se llama a DebugExtensionInitialize, crea un cliente de depuración y obtiene acceso al modelo de datos. Este acceso se proporciona mediante una interfaz de puente entre las interfaces IDebug* heredadas de Herramientas de depuración para Windows y el modelo de datos. Esta interfaz de puente es "IHostDataModelAccess" y se define de la siguiente manera:
DECLARE_INTERFACE_(IHostDataModelAccess, IUnknown)
{
STDMETHOD(GetDataModel)(_COM_Outptr_ IDataModelManager** manager, _COM_Outptr_ IDebugHost** host) PURE;
}
El método GetDataModel es el método de la interfaz bridge que proporciona acceso a ambos lados del modelo de datos: el host de depuración (el borde inferior del depurador) se expresa mediante la interfaz IDebugHost devuelta El componente principal del modelo de datos: el administrador de modelos de datos se expresa mediante la interfaz IDataModelManager devuelta.
Interfaces del sistema del modelo de datos del depurador
Host del modelo de datos
El modelo de datos del depurador está diseñado para ser un sistema componente que se puede hospedar en una variedad de contextos diferentes. Normalmente, el modelo de datos se hospeda en el contexto de una aplicación del depurador. Para ser un host del modelo de datos, es necesario implementar varias interfaces para exponer aspectos básicos del depurador: su destino, sus espacios de memoria, su evaluador, su sistema simbólico y de tipos, etc. Aunque cualquier aplicación que desee hospedar el modelo de datos implementa estas interfaces, tanto el modelo de datos principal como cualquier extensión que interopera con el modelo de datos.
El sistema de tipos y las interfaces simbólicas son:
Nombre de la interfaz | Descripción |
---|---|
IDebugHostSymbols | Interfaz principal que proporciona acceso y resolución de símbolos |
IDebugHostSymbol/ IDebugHostSymbol2 | Representa un único símbolo de cualquier tipo. El símbolo concreto es una derivación de esta interfaz. |
IDebugHostModule | Representa un módulo cargado dentro de un proceso. Se trata de un tipo de símbolo. |
IDebugHostType/IDebugHostType2 | Representa un tipo de idioma o nativo. |
IDebugHostConstant | Representa una constante dentro de la información simbólica (por ejemplo: un argumento de plantilla que no es de tipo en C++) |
IDebugHostField | Representa un campo dentro de una estructura o clase. |
IDebugHostData | Representa los datos de un módulo (si se trata de una estructura o clase, sería un IDebugHostField) |
IDebugHostBaseClass | Representa una clase base. |
IDebugHostPublic | Representa un símbolo dentro de la tabla publics de una PDB. Esto no tiene información de tipo asociada. Es un nombre y una dirección. |
IDebugHostModuleSignature | Representa una firma de módulo: una definición que coincidirá con un conjunto de módulos por nombre o versión. |
IDebugHostTypeSignature | Representa una firma de tipo: una definición que coincidirá con un conjunto de tipos por módulo o nombre. |
Las otras interfaces principales son:
Nombre de la interfaz | Descripción |
---|---|
IDebugHost | Interfaz principal del host de depuración. |
IDebugHostStatus | Interfaz que permite a un cliente consultar el estado del host. |
IDebugHostContext | Abstracción de un contexto dentro del host (por ejemplo: un destino determinado, un proceso determinado, un espacio de direcciones determinado, etc....) |
IDebugHostErrorSink | Una interfaz implementada por los autores de llamadas para recibir errores de determinadas partes del host y el modelo de datos |
IDebugHostEvaluator / IDebugHostEvaluator2 | Evaluador de expresiones del host de depuración. |
IDebugHostExtensibility | Interfaz para ampliar las funcionalidades del host o partes de él (como el evaluador de expresiones). |
La interfaz simbólica principal: IDebugHostSymbols
La interfaz IDebugHostSymbols es el punto de partida principal para acceder a los símbolos del destino de depuración. Esta interfaz se puede consultar desde una instancia de IDebugHost y se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostSymbols, IUnknown)
{
STDMETHOD(CreateModuleSignature)(_In_z_ PCWSTR pwszModuleName, _In_opt_z_ PCWSTR pwszMinVersion, _In_opt_z_ PCWSTR pwszMaxVersion, _Out_ IDebugHostModuleSignature** ppModuleSignature) PURE;
STDMETHOD(CreateTypeSignature)(_In_z_ PCWSTR signatureSpecification, _In_opt_ IDebugHostModule* module, _Out_ IDebugHostTypeSignature** typeSignature) PURE;
STDMETHOD(CreateTypeSignatureForModuleRange)(_In_z_ PCWSTR signatureSpecification, _In_z_ PCWSTR moduleName, _In_opt_z_ PCWSTR minVersion, _In_opt_z_ PCWSTR maxVersion, _Out_ IDebugHostTypeSignature** typeSignature) PURE;
STDMETHOD(EnumerateModules)(_In_ IDebugHostContext* context, _COM_Outptr_ IDebugHostSymbolEnumerator** moduleEnum) PURE;
STDMETHOD(FindModuleByName)(_In_ IDebugHostContext* context, _In_z_ PCWSTR moduleName, _COM_Outptr_ IDebugHostModule **module) PURE;
STDMETHOD(FindModuleByLocation)(_In_ IDebugHostContext* context, _In_ Location moduleLocation, _COM_Outptr_ IDebugHostModule **module) PURE;
STDMETHOD(GetMostDerivedObject)(_In_opt_ IDebugHostContext *pContext, _In_ Location location, _In_ IDebugHostType* objectType, _Out_ Location* derivedLocation, _Out_ IDebugHostType** derivedType) PURE;
}
El método CreateModuleSignature crea una firma que se puede usar para que coincida con un conjunto de módulos específicos por nombre y, opcionalmente, por versión. Hay tres componentes en una firma de módulo:
- Un nombre: un módulo coincidente debe tener un nombre que sea una coincidencia exacta que no distingue mayúsculas de minúsculas con el nombre de la firma.
- Una versión mínima: si se especifica, un módulo coincidente debe tener una versión mínima que sea al menos tan alta como esta versión. Las versiones se especifican en formato "A.B.C.D" y cada parte posterior es menos importante que la anterior. Solo el primer segmento es obligatorio.
- Una versión máxima: si se especifica, un módulo coincidente debe tener una versión máxima que no sea superior a esta versión. Las versiones se especifican en formato "A.B.C.D" y cada parte posterior es menos importante que la anterior. Solo el primer segmento es obligatorio.
El método CreateTypeSignature crea una firma que se puede usar para buscar coincidencias con un conjunto de tipos concretos mediante el uso de un módulo y un nombre de tipo. El formato de la cadena de firma de nombre de tipo es específico del lenguaje que se está depurando (y del host de depuración). Para C/C++, la cadena de firma es equivalente a una especificación de tipo NatVis. Es decir, la cadena de firma es un nombre de tipo donde se permiten caracteres comodín (especificados como *) para argumentos de plantilla.
CreateTypeSignatureForModuleRange
El método CreateTypeSignatureForModuleRange crea una firma que se puede usar para hacer coincidir un conjunto de tipos concretos mediante la firma del módulo y el nombre de tipo. Esto es similar al método CreateTypeSignature, excepto que, en lugar de pasar un módulo específico para que coincida con la firma, el autor de la llamada pasa los argumentos necesarios para crear una firma de módulo (como si la firma del módulo se creara con el método CreateModuleSignature).
El método EnumerateModules crea un enumerador que enumerará todos los módulos disponibles en un contexto de host determinado. Ese contexto de host podría encapsular un contexto de proceso o podría encapsular algo parecido al kernel de Windows.
El método FindModuleByName buscará en el contexto de host especificado y buscará un módulo que tenga el nombre especificado y devolverá una interfaz a él. Es legal buscar el módulo por nombre con o sin la extensión de archivo.
El método FindModuleByLocation examinará el contexto de host especificado y determinará qué módulo contiene la dirección especificada por la ubicación especificada. A continuación, devolverá una interfaz a este módulo.
GetMostDerivedObject usará el sistema de tipos del depurador para determinar el tipo en tiempo de ejecución de un objeto a partir de su tipo estático. Este método solo usará información simbólica y heurística disponibles en la capa del sistema de tipos para realizar este análisis. Esta información puede incluir RTTI de C++ (información de tipo de tiempo de ejecución) o análisis de la forma de las tablas de funciones virtuales del objeto. No incluye elementos como el concepto de tipo en tiempo de ejecución preferido en un IModelObject. Si el análisis no encuentra un tipo en tiempo de ejecución o no encuentra un tipo en tiempo de ejecución diferente del tipo estático pasado al método , se puede pasar la ubicación de entrada y el tipo. No se producirá un error en el método por estos motivos.
Interfaz de símbolo individual principal: IDebugHostSymbol
Todos los símbolos que se pueden devolver desde el host del modelo de datos se derivarán de alguna manera de IDebugHostSymbol. Esta es la interfaz principal que cada símbolo implementa independientemente del tipo de símbolo. En función del tipo de símbolo, un símbolo determinado puede implementar un conjunto de otras interfaces que devuelvan atributos más únicos para el tipo de símbolo determinado representado por esta interfaz. La interfaz IDebugHostSymbol2 / IDebugHostSymbol se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostSymbol2, IDebugHostSymbol)
{
//
// IDebugHostSymbol:
//
STDMETHOD(GetContext)(_COM_Outptr_ IDebugHostContext** context) PURE;
STDMETHOD(EnumerateChildren)(_In_ SymbolKind kind, _In_opt_z_ PCWSTR name, _Out_ IDebugHostSymbolEnumerator **ppEnum) PURE;
STDMETHOD(GetSymbolKind)(_Out_ SymbolKind *kind) PURE;
STDMETHOD(GetName)(_Out_ BSTR* symbolName) PURE;
STDMETHOD(GetType)(_Out_ IDebugHostType** type) PURE;
STDMETHOD(GetContainingModule)(_Out_ IDebugHostModule **containingModule) PURE;
STDMETHOD(CompareAgainst)(_In_ IDebugHostSymbol *pComparisonSymbol, _In_ ULONG comparisonFlags, _Out_ bool *pMatches) PURE;
//
// IDebugHostSymbol2
//
STDMETHOD(EnumerateChildrenEx)(_In_ SymbolKind kind, _In_opt_z_ PCWSTR name, _In_opt_ SymbolSearchInfo* searchInfo, _Out_ IDebugHostSymbolEnumerator **ppEnum) PURE;
}
Es muy importante tener en cuenta que esta interfaz representa muchos tipos de símbolos, delineados por la enumeración SymbolKind, que tiene valores como se indica a continuación:
Enumarant | Significado |
---|---|
Símbolo | Tipo de símbolo no especificado |
SymbolModule | El símbolo es un módulo y se puede consultar para IDebugHostModule. |
SymbolType | El símbolo es un tipo y se puede consultar para IDebugHostType. |
SymbolField | El símbolo es un campo (un miembro de datos dentro de una estructura o clase) y se puede consultar para IDebugHostField. |
SymbolConstant | El símbolo es un valor constante y se puede consultar para IDebugHostConstant. |
SymbolData | El símbolo es datos que no son miembros de una estructura o clase y son consultables para IDebugHostData. |
SymbolBaseClass | El símbolo es una clase base y es consultable para IDebugHostBaseClass |
SymbolPublic | El símbolo es una entrada en la tabla publics de un módulo (sin información de tipo) y es consultable para IDebugHostPublic. |
SymbolFunction | El símbolo es una función y es consultable para IDebugHostData |
El método GetContext devuelve el contexto donde el símbolo es válido. Aunque esto representará cosas como el destino de depuración y el espacio de direcciones o proceso en el que existe el símbolo, puede que no sea tan específico como un contexto recuperado de otros medios (por ejemplo: de un IModelObject).
El método EnumerateChildren devuelve un enumerador que enumerará todos los elementos secundarios de un símbolo determinado. Para un tipo de C++, por ejemplo, las clases base, los campos, las funciones miembro y el tipo se consideran elementos secundarios del símbolo de tipo.
Interfaz del módulo: IDebugHostModule
La noción del depurador de un módulo que se carga dentro de algún espacio de direcciones se representa de dos maneras distintas en el modelo de datos: en el nivel de sistema de tipo a través de la interfaz IDebugHostModule. En este caso, un módulo es un símbolo y los atributos principales del módulo son llamadas a métodos de interfaz proyectados en el nivel de modelo de datos a través del modelo de datos Debugger.Models.Module. Se trata de una encapsulación extensible del sistema de tipos IDebugHostModule representación de un módulo.
La interfaz IDebugHostModule se define de la siguiente manera (omitiendo los métodos genéricos de IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostModule, IDebugHostSymbol)
{
//
// IDebugHostModule:
//
STDMETHOD(GetImageName)(_In_ bool allowPath, _Out_ BSTR* imageName) PURE;
STDMETHOD(GetBaseLocation)(_Out_ Location* moduleBaseLocation) PURE;
STDMETHOD(GetVersion)(_Out_opt_ ULONG64* fileVersion, _Out_opt_ ULONG64* productVersion) PURE;
STDMETHOD(FindTypeByName)(_In_z_ PCWSTR typeName, _Out_ IDebugHostType** type) PURE;
STDMETHOD(FindSymbolByRVA)(_In_ ULONG64 rva, _Out_ IDebugHostSymbol** symbol) PURE;
STDMETHOD(FindSymbolByName)(_In_z_ PCWSTR symbolName, _Out_ IDebugHostSymbol** symbol) PURE;
}
El método GetImageName devuelve el nombre de la imagen del módulo. Según el valor del argumento allowPath, el nombre de imagen devuelto puede incluir o no la ruta de acceso completa a la imagen.
El método GetBaseLocation devuelve la dirección de carga base del módulo como una estructura de ubicación. La estructura de ubicación devuelta para un módulo normalmente hará referencia a una dirección virtual.
El método GetVersion devuelve información de versión sobre el módulo (suponiendo que dicha información se pueda leer correctamente fuera de los encabezados). Si se solicita una versión determinada (a través de un puntero de salida que no es nullptr) y no se puede leer, se devolverá un código de error adecuado desde la llamada al método.
El método FindTypeByName busca un tipo definido en el módulo por el nombre de tipo y devuelve un símbolo de tipo para él. Este método puede devolver un IDebugHostType válido que nunca se devolvería a través de la recursividad explícita de los elementos secundarios del módulo. El host de depuración puede permitir la creación de tipos derivados: tipos que no se usan nunca dentro del propio módulo, sino derivados de tipos que son. Por ejemplo, si la estructura MyStruct se define en los símbolos del módulo, pero el tipo MyStruct ** nunca se usa, el método FindTypeByName puede devolver legítimamente un símbolo de tipo para MyStruct ** a pesar de que ese nombre de tipo nunca aparece explícitamente en los símbolos del módulo.
El método FindSymbolByRVA encontrará un único símbolo coincidente en la dirección virtual relativa especificada dentro del módulo. Si no hay un solo símbolo en la RVA proporcionada (por ejemplo, hay varias coincidencias), este método devolverá un error. Tenga en cuenta que este método prefiere devolver un símbolo privado sobre un símbolo de la tabla pública.
El método FindSymbolByName encontrará un único símbolo global del nombre especificado en el módulo. Si no hay un único símbolo que coincida con el nombre especificado, este método devolverá un error. Tenga en cuenta que este método prefiere devolver un símbolo privado sobre un símbolo de la tabla pública.
Acceso al sistema de tipos: IDebugHostType2 / IDebugHostType
Un idioma o tipo nativo determinado se describe mediante las interfaces IDebugHostType2 o IDebugHostType. Tenga en cuenta que algunos de los métodos de estas interfaces solo se aplican a tipos específicos de tipos. Un símbolo de tipo determinado puede hacer referencia a uno de los siguientes tipos, tal como se describe en la enumeración TypeKind:
Tipo | Descripción |
---|---|
TypeUDT | Un tipo definido por el usuario (una estructura, clase, unión, etc.). Objeto de modelo que tiene un tipo nativo cuyo tipo es TypeUDT tiene una representación canónica de ObjectTargetObject donde el tipo siempre se mantiene dentro del IModelObject correspondiente. |
TypePointer | Puntero. Objeto de modelo que tiene un tipo nativo cuyo tipo es TypePointer tiene una representación canónica de ObjectIntrinsic donde el valor del puntero es cero se extiende a VT_UI8 y se mantiene como datos intrínsecos en este formulario de 64 bits. Cualquier símbolo de tipo de TypePointer tiene un tipo base (tal como lo devuelve el método GetBaseType) del tipo al que apunta el puntero. |
TypeMemberPointer | Puntero al miembro de clase. Objeto de modelo que tiene un tipo nativo cuyo tipo es TypeMemberPointer tiene una representación canónica que es intrínseca (el valor es el mismo que el valor de puntero). El significado exacto de este valor es específico del host de compilación o depuración. |
TypeArray | Matriz . Objeto de modelo que tiene un tipo nativo cuyo tipo es TypeArray tiene una representación canónica de ObjectTargetObject. La dirección base de la matriz es la ubicación del objeto (recuperada a través del método GetLocation) y el tipo de la matriz siempre se mantiene. Cualquier símbolo de tipo de TypeArray tiene un tipo base (tal como lo devuelve el método GetBaseType) del tipo del que la matriz es una matriz de . |
TypeFunction | Función. |
TypeTypedef | Definición de tipo. Un objeto de modelo que tiene un tipo nativo cuyo tipo sería TypeTypedef tiene una representación canónica idéntica a la representación canónica del tipo final subyacente a la definición de tipo. Esto aparece completamente transparente para el usuario final del objeto y la información de tipo a menos que los métodos typedef explícitos de IDebugHostType2 se utilicen para consultar información de typedef o hay un modelo de datos explícito registrado en la definición de tipo. Tenga en cuenta que el método GetTypeKind nunca devolverá TypeTypedef. Cada método devolverá lo que devolvería el tipo final subyacente a la definición de tipo. Hay métodos específicos typedef en IDebugHostType2 que se pueden usar para obtener la información específica de typedef. |
TypeEnum | Una enumeración. Objeto de modelo que tiene un tipo nativo cuyo tipo es TypeEnum tiene una representación canónica de ObjectIntrinsic donde el valor y el tipo del intrínseco son idénticos al valor de enumeración. |
TypeIntrinsic | Intrínseco (tipo base). Objeto de modelo que tiene un tipo nativo cuyo tipo es TypeIntrinsic tiene una representación canónica de ObjectIntrinsic. La información de tipo puede o no mantenerse, especialmente si el tipo subyacente está totalmente descrito por el tipo de datos variant (VT_*) de los datos intrínsecos almacenados en IModelObject |
La interfaz IDebugHostType2 / IDebugHostType general se define como se indica a continuación (excepto los métodos IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostType2, IDebugHostType)
{
//
// IDebugHostType:
//
STDMETHOD(GetTypeKind)(_Out_ TypeKind *kind) PURE;
STDMETHOD(GetSize)(_Out_ ULONG64* size) PURE;
STDMETHOD(GetBaseType)(_Out_ IDebugHostType** baseType) PURE;
STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;
STDMETHOD(GetIntrinsicType)(_Out_opt_ IntrinsicKind *intrinsicKind, _Out_opt_ VARTYPE *carrierType) PURE;
STDMETHOD(GetBitField)(_Out_ ULONG* lsbOfField, _Out_ ULONG* lengthOfField) PURE;
STDMETHOD(GetPointerKind)(_Out_ PointerKind* pointerKind) PURE;
STDMETHOD(GetMemberType)(_Out_ IDebugHostType** memberType) PURE;
STDMETHOD(CreatePointerTo)(_In_ PointerKind kind, _COM_Outptr_ IDebugHostType** newType) PURE;
STDMETHOD(GetArrayDimensionality)(_Out_ ULONG64* arrayDimensionality) PURE;
STDMETHOD(GetArrayDimensions)(_In_ ULONG64 dimensions, _Out_writes_(dimensions) ArrayDimension *pDimensions) PURE;
STDMETHOD(CreateArrayOf)(_In_ ULONG64 dimensions, _In_reads_(dimensions) ArrayDimension *pDimensions, _COM_Outptr_ IDebugHostType** newType) PURE;
STDMETHOD(GetFunctionCallingConvention)(_Out_ CallingConventionKind* conventionKind) PURE;
STDMETHOD(GetFunctionReturnType)(_COM_Outptr_ IDebugHostType** returnType) PURE;
STDMETHOD(GetFunctionParameterTypeCount)(_Out_ ULONG64* count) PURE;
STDMETHOD(GetFunctionParameterTypeAt)(_In_ ULONG64 i, _Out_ IDebugHostType** parameterType) PURE;
STDMETHOD(IsGeneric)(_Out_ bool* isGeneric) PURE;
STDMETHOD(GetGenericArgumentCount)(_Out_ ULONG64* argCount) PURE;
STDMETHOD(GetGenericArgumentAt)(_In_ ULONG64 i, _Out_ IDebugHostSymbol** argument) PURE;
//
// IDebugHostType2:
//
STDMETHOD(IsTypedef)(_Out_ bool* isTypedef) PURE;
STDMETHOD(GetTypedefBaseType)(_Out_ IDebugHostType2** baseType) PURE;
STDMETHOD(GetTypedefFinalBaseType)(_Out_ IDebugHostType2** finalBaseType) PURE;
STDMETHOD(GetFunctionVarArgsKind)(_Out_ VarArgsKind* varArgsKind) PURE;
}
Métodos generales IDebugHostType2/IDebugHostType
Los métodos IDebugHostType siguientes son generales para cualquier tipo, independientemente de qué tipo se devuelva desde el método GetTypeKind:
STDMETHOD(GetTypeKind)(_Out_ TypeKind *kind) PURE;
STDMETHOD(GetSize)(_Out_ ULONG64* size) PURE;
STDMETHOD(GetBaseType)(_Out_ IDebugHostType** baseType) PURE;
STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;
El método GetTypeKind devuelve a qué tipo de tipo (puntero, matriz, intrínseco, etc.) se refiere el símbolo.
El método GetSize devuelve el tamaño del tipo (como si hubiera hecho sizeof(type) en C++).
Si el tipo es un derivado de otro tipo único (por ejemplo: como MyStruct * se deriva de MyStruct'), el método GetBaseType devuelve el tipo base de la derivación. En el caso de los punteros, devuelve el tipo al que apunta. En el caso de las matrices, esto devuelve lo que la matriz es una matriz de . Si el tipo no es de este tipo derivado, se devuelve un error.
El método GetHashCode devuelve un código hash de 32 bits para el tipo. Con la excepción de una coincidencia global (por ejemplo, una firma de tipo equivalente a * que coincide con todo si el host lo permite), cualquier instancia de tipo que pueda coincidir con una firma de tipo determinada debe devolver el mismo código hash. Este método se usa junto con las firmas de tipo para hacer coincidir las firmas de tipo con las instancias de tipo.
Métodos intrínsecos IDebugHostType2/IDebugHostType
Los métodos IDebugHostType siguientes son específicos de los tipos intrínsecos (o tipos que contienen datos intrínsecos como enumeraciones):
STDMETHOD(GetIntrinsicType)(_Out_opt_ IntrinsicKind *intrinsicKind, _Out_opt_ VARTYPE *carrierType) PURE;
El método GetIntrinsicType devuelve información sobre qué tipo de intrínseco es el tipo. Se devuelven dos valores fuera de este método:
- El tipo intrínseco indica el tipo general (por ejemplo: entero, sin signo, punto flotante), pero no el tamaño del tipo (por ejemplo: 8 bits, 16 bits, 32 bits, 64 bits)
- El tipo portador indica cómo el tipo intrínseco se empaqueta en una estructura VARIANT. Se trata de una constante VT_*.
La combinación de los dos valores proporciona el conjunto completo de información sobre el intrínseco.
Métodos bitfield de IDebugHostType2/IDebugHostType
Los siguientes métodos IDebugHostType son específicos de los tipos que almacenan datos en campos de bits. La información sobre la ubicación del campo de bits dentro de un intrínseco se almacena como parte del símbolo de tipo en el modelo de datos en lugar de ser un atributo de la ubicación.
STDMETHOD(GetBitField)(_Out_ ULONG* lsbOfField, _Out_ ULONG* lengthOfField) PURE;
Si un miembro determinado de una estructura de datos es un campo de bits (por ejemplo: ULONG MyBits:8), la información de tipo del campo lleva información sobre la ubicación del campo de bits. El método GetBitField se puede usar para recuperar esa información. Este método producirá un error en cualquier tipo que no sea un campo de bits. Esta es la única razón por la que se producirá un error en el método. Simplemente llamar a este método y examinar el éxito o el error es suficiente para distinguir un campo de bits de un campo que no es de bits. Si un tipo determinado es un campo de bits, las posiciones de campo se definen mediante el conjunto de apertura medio (lsbOfField + lengthOfField : lsbOfField]
Métodos relacionados con el puntero IDebugHostType2/IDebugHostType
Los siguientes métodos IDebugHostType son específicos de los tipos de puntero. Estos son los tipos en los que GetTypeKind devuelve TypePointer o TypeMemberPointer':
STDMETHOD(GetPointerKind)(_Out_ PointerKind* pointerKind) PURE;
STDMETHOD(GetMemberType)(_Out_ IDebugHostType** memberType) PURE;
Para los tipos que son punteros, el método GetPointerKind devuelve el tipo de puntero. Esto se define mediante la enumeración PointerKind.
Para los tipos que son de puntero a miembro (como se indica en un tipo de TypeMemberPointer), el método GetMemberType devuelve la clase de la que el puntero es un puntero a miembro.
Métodos relacionados con la matriz IDebugHostType2/IDebugHostType
Las matrices son tipos donde GetTypeKind devuelve TypeArray. Tenga en cuenta que las matrices definidas por el sistema de tipos del host de depuración no son las mismas que las matrices unidimensionales, basadas en índice cero, agrupadas matrices unidimensionales lineales que C utiliza. Las matrices de estilo C encajan en la definición, pero el ámbito general de una matriz es más amplio en IDebugHostType. Una matriz del host de depuración puede ser multidimensional y cada dimensión de la matriz se define mediante un descriptor conocido como ArrayDimensionThis que tiene los siguientes campos:
Campo | Significado |
---|---|
LowerBound | Índice base de la matriz como un valor de 64 bits con signo. Para una matriz de estilo C, siempre será cero. No es necesario. Se puede considerar que una dimensión individual de una matriz se inicia en cualquier índice de 64 bits, incluso en un negativo. |
Length | Longitud de la dimensión de matriz como un valor de 64 bits sin signo. Las indicciones de la matriz abarcan el conjunto medio abierto [LowerBound, LowerBound + Length). |
Intervalo | Define el intervalo de la dimensión de matriz. Para un aumento de uno (de N a N + 1) en el índice de esta dimensión, esto indica cuántos bytes se van a avanzar en la memoria. Para una matriz de estilo C, este sería el tamaño de cada elemento de la matriz. No es necesario. El relleno entre elementos se puede expresar como un paso mayor que el tamaño de cada elemento individual. En el caso de las matrices multidimensionales, este valor indicaría cómo mover una dimensión completa hacia delante. Considere una matriz M x N. Esto puede describirse en forma principal de fila como dos dimensiones: |
{ [LowerBound: 0, Length: M, Stride: N \* sizeof(element)], [LowerBound: 0, Length: N, Stride: sizeof(element)]}
o bien, también se puede describir en forma principal de columna como dos dimensiones:
{ [LowerBound: 0, Length: M, Stride: sizeof(element)], [LowerBound: 0, Length: N, Stride: M \* sizeof(element)]}
El concepto ArrayDimension permite este grado de flexibilidad.
Los métodos IDebugHostType siguientes son específicos de los tipos de matriz.
STDMETHOD(GetArrayDimensionality)(\_Out_ ULONG64\* arrayDimensionality) PURE;
STDMETHOD(GetArrayDimensions)(\_In_ ULONG64 dimensions, \_Out_writes_(dimensions) ArrayDimension \*pDimensions) PURE;
El método GetArrayDimensionality devuelve el número de dimensiones en las que se indiza la matriz. Para las matrices de estilo C, el valor devuelto aquí siempre será 1.
El método GetArrayDimensions devuelve un conjunto de descriptores, uno para cada dimensión de la matriz, como se indica en el método GetArrayDimensionality. Cada descriptor es una estructura ArrayDimension que describe el índice inicial, la longitud y el paso hacia delante de cada dimensión de matriz. Esto permite descripciones de construcciones de matriz significativamente más eficaces de las permitidas en el sistema de tipos de C.
Para las matrices de estilo C, se devuelve una sola dimensión de matriz aquí con valores que siempre son:
- LowerBound = 0
- Length = ARRAYSIZE(array)
- Stride = sizeof(elementType)
Métodos relacionados con la función IDebugHostType2/IDebugHostType
Los tipos que indican que son tipos de función a través de un tipo de TypeFunction admiten los métodos siguientes en IDebugHostType e IDebugHostType2.
//
// IDebugHostType:
//
STDMETHOD(GetFunctionCallingConvention)(_Out_ CallingConventionKind* conventionKind) PURE;
STDMETHOD(GetFunctionReturnType)(_COM_Outptr_ IDebugHostType** returnType) PURE;
STDMETHOD(GetFunctionParameterTypeCount)(_Out_ ULONG64* count) PURE;
STDMETHOD(GetFunctionParameterTypeAt)(_In_ ULONG64 i, _Out_ IDebugHostType** parameterType) PURE;
//
// IDebugHostType2:
//
STDMETHOD(GetFunctionVarArgsKind)(_Out_ VarArgsKind* varArgsKind) PURE;
El método GetFunctionCallingConvention devuelve la convención de llamada de la función. Se devuelve como miembro de la enumeración CallingConventionKind.
El método GetFunctionReturnType devuelve el tipo de valor devuelto de la función.
El método GetFunctionParameterTypeCount devuelve el número de argumentos que toma la función. Tenga en cuenta que el marcador de argumento de variable basado en puntos suspensivos de C/C++ no se considera en este recuento. La presencia de este tipo debe detectarse a través del método GetFunctionVarArgsKind. Esto solo incluirá argumentos antes de los puntos suspensivos.
El método GetFunctionParameterTypeAt devuelve el tipo del argumento i-th a la función.
El método GetFunctionVarArgsKind devuelve si una función determinada utiliza una lista de argumentos de variable y, si es así, qué estilo de argumentos de variable utiliza. Tal se define mediante un miembro de la enumeración VarArgsKind definida como se indica a continuación:
Enumerant | Significado |
---|---|
VarArgsNone | La función no toma ningún argumento de variable. |
VarArgsCStyle | La función es una función varargs de estilo C (returnType(arg1, arg2, ...)). El número de argumentos notificados por la función no incluye el argumento de puntos suspensivos. Cualquier paso de argumentos de variable se produce después del número de argumentos devueltos por el método GetFunctionParameterTypeCount. |
IDebugHostType2 GetFunctionVarArgsKind
El método GetFunctionVarArgsKind devuelve si una función determinada utiliza una lista de argumentos de variable y, si es así, qué estilo de argumentos de variable utiliza. Tal se define mediante un miembro de la enumeración VarArgsKind definida como se indica a continuación:
Métodos relacionados con la definición de tipo IDebugHostType2/IDebugHostType
Cualquier tipo que sea una definición de tipo se comportará como si el tipo fuera el tipo final subyacente a la definición de tipo. Esto significa que los métodos como GetTypeKind no indicarán que el tipo es una definición de tipo. Del mismo modo, GetBaseType no devolverá el tipo al que hace referencia la definición. En su lugar, indicarán que se comportan como si se llamaran en la definición final subyacente a la definición de tipo. Por ejemplo:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
Un IDebugHostType para "PMYSTRUCT o PTRMYSTRUCT notificará la siguiente información:
- El método GetTypeKind devolverá TypePointer. El tipo subyacente final MYSTRUCT * es realmente un puntero.
- El método 'GetBaseType devolverá un tipo para MYSTRUCT. El tipo subyacente de MYSTRUCT * es MYSTRUCT.
La única diferencia aquí es cómo se comportan los métodos específicos typedef en IDebugHostType2. Estos métodos son:
STDMETHOD(IsTypedef)(_Out_ bool* isTypedef) PURE;
STDMETHOD(GetTypedefBaseType)(_Out_ IDebugHostType2** baseType) PURE;
STDMETHOD(GetTypedefFinalBaseType)(_Out_ IDebugHostType2** finalBaseType) PURE;
En este ejemplo:
- El método IsTypedef devolverá true para PMYSTRUCT y PTRMYSTRUCT.
- El método GetTypedefBaseType devolverá MYSTRUCT * para PMYSTRUCT y PMYSTRUCT para PTRMYSTRUCT.
- El método GetTypedefFinalBaseType devolverá MYSTRUCT * para ambos tipos.
El método IsTypedef es el único método capaz de ver si un tipo es una definición de tipo. El método GetTypeKind se comportará como si se llamara en el tipo subyacente.
El método GetTypedefBaseType devolverá la definición inmediata de la definición typedef. En los ejemplos descritos en la documentación:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
este método devolverá MYSTRUCT * para PMYSTRUCT y PMYSTRUCT para PTRMYSTRUCT.
El método GetTypedefFinalBaseType devolverá el tipo final para el que la definición de tipo es una definición. Si typedef es una definición de otra definición de typedef, seguirá seguido la cadena de definición hasta que llegue a un tipo que no sea una definición de tipo y ese tipo se devolverá. En los ejemplos descritos en la documentación:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
este método devolverá MYSTRUCT * cuando se llame a en PMYSTRUCT o PTRMYSTRUCT.
Métodos de creación de tipos IDebugHostType2/IDebugHostType
STDMETHOD(CreatePointerTo)(_In_ PointerKind kind, _COM_Outptr_ IDebugHostType** newType) PURE;
STDMETHOD(CreateArrayOf)(_In_ ULONG64 dimensions, _In_reads_(dimensions) ArrayDimension *pDimensions, _COM_Outptr_ IDebugHostType** newType) PURE;
Valores de símbolos constantes: IDebugHostConstant
En el caso de las ubicaciones en las que los valores constantes están presentes en información simbólica (donde un valor determinado es un símbolo que puede o no ser un valor constante), la interfaz IDebugHostConstant expresa la noción de dicha constante. Esto se usa normalmente en lugares como argumentos de plantilla en los que un argumento determinado suele ser un tipo, pero en su lugar puede ser un argumento de plantilla que no sea de tipo (por ejemplo, una constante).
La interfaz IDebugHostConstant se define de la siguiente manera (omitiendo los métodos genéricos implementados por IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostConstant, IDebugHostSymbol)
{
STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}
El método GetValue devuelve el valor de la constante empaquetada en un VARIANT. Es importante tener en cuenta que el método GetType en IDebugHostSymbol puede devolver un símbolo de tipo específico para la constante. En tales casos, no hay ninguna garantía de que el empaquetado del valor constante definido por el símbolo de tipo sea el mismo que el empaquetado devuelto por el método GetValue aquí.
Acceso a miembros de datos: IDebugHostField
La clase IDebugHostField representa un símbolo que es un miembro de datos de una clase, estructura, unión u otra construcción de tipo. No representa datos gratuitos (por ejemplo, datos globales). La interfaz se define de la siguiente manera (omitiendo los métodos genéricos a IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostField, IDebugHostSymbol)
{
STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
STDMETHOD(GetOffset)(_Out_ ULONG64* offset) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}
El método GetLocationKind devuelve el tipo de ubicación en la que se encuentra el símbolo según la enumeración LocationKind. Esta enumeración puede ser uno de los siguientes valores:
Enumerant | Significado |
---|---|
LocationMember | El campo es un miembro de datos normal de una clase, estructura, unión u otra construcción de tipo. Tiene un desplazamiento que es relativo a la dirección base de la construcción de tipo contenedor. Esta dirección base se representa normalmente mediante el puntero this. El desplazamiento del campo se puede recuperar a través del método GetOffset. Los métodos GetLocation y GetValue producirán un error en un campo que sea LocationMember. |
LocationStatic | El campo es estático y tiene su propia dirección. El método GetLocation devolverá la ubicación abstracta (por ejemplo: dirección) del campo estático. Los métodos GetOffset y GetValue producirán un error en un campo que sea LocationStatic. |
LocationConstant | El campo es una constante y tiene un valor. El método GetValue devolverá el valor de la constante. Los métodos GetOffset y GetLocation producirán un error en un campo que sea LocationConstant. |
LocationNone | El campo no tiene ninguna ubicación. Es posible que el compilador lo haya optimizado o puede ser un campo estático que se declara pero nunca se define. Independientemente de cómo llegó a ser este campo, no tiene presencia física ni valor. Solo está en los símbolos. Todos los métodos de adquisición (GetOffset, GetLocation y GetValue) producirán un error en un campo que sea LocationNone. |
Para los campos que tienen un desplazamiento (por ejemplo, campos cuyo tipo de ubicación indica LocationMember), el método GetOffset devolverá el desplazamiento de la dirección base del tipo contenedor (el puntero este) a los datos del propio campo. Estos desplazamientos siempre se expresan como valores de 64 bits sin signo. Si el campo especificado no tiene una ubicación que sea un desplazamiento de la dirección base del tipo contenedor, se producirá un error en el método GetOffset.
Para los campos que tienen una dirección independientemente de la instancia de tipo concreta (por ejemplo, los campos cuyo tipo de ubicación indica LocationStatic), el método GetLocation devolverá la ubicación abstracta (dirección) del campo. Si el campo especificado no tiene una ubicación estática, se producirá un error en el método GetLocation.
Para los campos que tienen un valor constante definido dentro de la información simbólica (por ejemplo, los campos cuyo tipo de ubicación indica LocationConstant), el método GetValue devolverá el valor constante del campo. Si el campo especificado no tiene un valor constante, se producirá un error en el método GetValue.
Acceso gratuito a datos: IDebugHostData
Los datos de los módulos que no son miembros de otro tipo se representan mediante la interfaz IDebugHostData. Esa interfaz se define de la siguiente manera (ignorando los métodos genéricos de IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostData, IDebugHostSymbol)
{
STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}
Todos estos métodos son semánticamente equivalentes a sus homólogos en IDebugHostField. La única diferencia es que el método GetLocationKind nunca devolverá LocationMember para obtener datos gratuitos.
El método GetLocationKind devuelve el tipo de ubicación en la que se encuentra el símbolo según la enumeración LocationKind. La descripción de esta enumeración se puede encontrar en la documentación de IDebugHostField.
Para los datos que tienen una dirección, el método GetLocation devolverá la ubicación abstracta (dirección) del campo. Si los datos especificados no tienen una ubicación estática, se producirá un error en el método GetLocation.
Para los datos que tienen un valor constante definido dentro de la información simbólica (por ejemplo, datos cuyo tipo de ubicación indica LocationConstant), el método GetValue devolverá el valor constante del campo. Si los datos especificados no tienen un valor constante, se producirá un error en el método GetValue.
Clases base: IDebugHostBaseClass
La jerarquía de herencia de un tipo determinado se expresa a través de elementos secundarios de un símbolo de tipo. Si un tipo determinado deriva (herencia) de uno o varios tipos, habrá uno o varios elementos secundarios SymbolBaseClass del símbolo de tipo para el tipo. Cada uno de esos símbolos SymbolBaseClass representa la herencia inmediata de un tipo determinado. El nombre de la clase base es el nombre del símbolo SymbolBaseClass, así como el del símbolo de tipo para la clase base. El método GetType del símbolo SymbolBaseClass se puede usar para obtener el símbolo de tipo para la propia clase base. La jerarquía de herencia completa se puede recorrer explorando de forma recursiva símbolos secundarios SymbolBaseClass. Cada uno de estos símbolos de clase base se expresa mediante la interfaz IDebugHostBaseClass que se define de la siguiente manera (ignorando los métodos genéricos de IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostBaseClass, IDebugHostSymbol)
{
STDMETHOD(GetOffset)(_Out_ ULONG64* offset) PURE;
}
El método GetOffset devuelve el desplazamiento de la clase base desde la dirección base de la clase derivada. Este desplazamiento puede ser cero o puede ser un valor positivo sin signo de 64 bits.
Símbolos públicos: IDebugHostPublic
Los símbolos públicos representan elementos de la tabla pública dentro de un archivo de símbolos. Son, en efecto, direcciones de exportación. No hay información de tipo asociada a un símbolo público: solo una dirección. A menos que el autor de la llamada solicite explícitamente un símbolo público, el host de depuración prefiere devolver símbolos privados para cada consulta. Un símbolo público se expresa mediante la interfaz IDebugHostPublic que se define de la siguiente manera (omitir los métodos genéricos de IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostPublic, IDebugHostSymbol)
{
STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
}
Todos estos métodos son semánticamente equivalentes a sus homólogos en IDebugHostField. La única diferencia es que el método GetLocationKind nunca devolverá LocationMember o LocationConstant para dichos símbolos.
El método GetLocationKind devuelve el tipo de ubicación en la que se encuentra el símbolo según la enumeración LocationKind. La descripción de esta enumeración se puede encontrar en la documentación de IDebugHostField.
Para los datos que tienen una dirección, el método GetLocation devolverá la ubicación abstracta (dirección) del campo. Si el público especificado no tiene una ubicación estática, se producirá un error en el método GetLocation.
Firmas de módulo y coincidencia de versiones: IDebugHostModuleSignature
Las firmas de módulo representan un medio para comprobar si un módulo determinado cumple un conjunto de criterios relacionados con la nomenclatura y el control de versiones. Se crea una firma de módulo mediante el método CreateModuleSignature en IDebugHostSymbols. Puede coincidir con el nombre del módulo y un intervalo opcional de números de versión para el módulo. Una vez creada dicha firma, el cliente recibe una interfaz IDebugHostModuleSignature que se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostModuleSignature, IUnknown)
{
STDMETHOD(IsMatch)(_In_ IDebugHostModule* pModule, _Out_ bool* isMatch) PURE;
}
El método IsMatch compara un módulo determinado (dado por un símbolo IDebugHostModule) con una firma, comparando el nombre y la versión del módulo con el nombre y el intervalo de versiones indicados en la firma. Indicación de si el símbolo del módulo especificado coincide con la firma.
Firmas de tipo y coincidencia de tipos: IDebugHostTypeSignature
Las firmas de tipo representan un medio para comprobar si una instancia de tipo determinada cumple un conjunto de criterios sobre el nombre del tipo, los argumentos genéricos para el tipo y el módulo en el que se encuentra el tipo. Se crea una firma de tipo a través del método CreateTypeSignature en IDebugHostSymbols. Una vez creada dicha firma, el cliente recibe una interfaz IDebugHostTypeSignature que se define de la siguiente manera:
DECLARE_INTERFACE_(IDebugHostTypeSignature, IUnknown)
{
STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;
STDMETHOD(IsMatch)(_In_ IDebugHostType* type, _Out_ bool* isMatch, _COM_Outptr_opt_ IDebugHostSymbolEnumerator** wildcardMatches) PURE;
STDMETHOD(CompareAgainst)(_In_ IDebugHostTypeSignature* typeSignature, _Out_ SignatureComparison* result) PURE;
}
El método GetHashCode devuelve un código hash de 32 bits para la firma de tipo. El host de depuración garantiza que hay sincronización en la implementación entre el código hash devuelto para las instancias de tipo y el código hash devuelto para las firmas de tipo. Con la excepción de una coincidencia global, si una instancia de tipo es capaz de hacer coincidir una firma de tipo, ambos tendrán el mismo código hash de 32 bits. Esto permite una comparación rápida inicial y una coincidencia entre una instancia de tipo y una gran cantidad de firmas de tipo registradas con el administrador de modelos de datos.
El método IsMatch devuelve una indicación de si una instancia de tipo determinada coincide con los criterios especificados en la firma de tipo. Si lo hace, se devuelve una indicación de esto, así como un enumerador que indicará todas las partes específicas de la instancia de tipo (como símbolos) que coinciden con caracteres comodín en la firma de tipo.
El método CompareAgainst compara la firma de tipo con otra firma de tipo y devuelve cómo se comparan las dos firmas. El resultado de la comparación que se devuelve es un miembro de la enumeración SignatureComparison, que se define de la siguiente manera:
Enumerant | Significado |
---|---|
Unrelated | No hay ninguna relación entre las dos firmas o tipos que se comparan. |
Ambigua | Una firma o tipo se compara ambiguamente con la otra. En el caso de dos firmas de tipo, esto significa que hay instancias de tipo potenciales que podrían coincidir con cualquier firma igual de bien. Por ejemplo, las dos firmas de tipo que se muestran a continuación son ambiguas. Firma 1: std::pair<*, int> Firma 2: std::pair<int,*> porque la instancia std::pair<int, int> de tipo coincide con una igual de bien (ambas tienen una coincidencia concreta y una de caracteres comodín). |
LessSpecific | Una firma o tipo es menos específica que la otra. A menudo, esto significa que la firma menos específica tiene un carácter comodín donde el más específico tiene un tipo concreto. Por ejemplo, la primera firma siguiente es menos específica que la segunda. Firma 1: std::pair<*, int> Firma 2: std::pair<int, int> porque tiene un carácter comodín (el * ) donde el segundo tiene un tipo concreto (int). |
MoreSpecific | Una firma o tipo es más específica que la otra. A menudo, esto significa que la firma más específica tiene un tipo concreto donde el menos específico tiene un carácter comodín. Por ejemplo, la primera firma siguiente es más específica que la segunda. Firma 1: std::pair<int, int> Firma 2: std::pair<*, int> porque tiene un tipo concreto (int) donde el segundo tiene un carácter comodín ().* |
Idéntico | Las dos firmas o tipos son idénticas. |
Vea también
Este tema forma parte de una serie que describe las interfaces accesibles desde C++, cómo usarlas para crear una extensión de depurador basada en C++ y cómo usar otras construcciones de modelo de datos (por ejemplo: JavaScript o NatVis) desde una extensión de modelo de datos de C++.
Información general sobre el modelo de datos del depurador de C++
Interfaces de C++ del modelo de datos del depurador
Objetos C++ del modelo de datos del depurador
Interfaces adicionales del modelo de datos del depurador de C++