Interfacce C++ del modello di dati del debugger
In questo argomento viene fornita una panoramica dell'uso delle interfacce C++ del modello di dati del debugger per estendere e personalizzare le funzionalità del debugger.
Interfacce host C++ del modello di dati del debugger
Host del modello di dati del debugger
Il modello di dati del debugger è progettato per essere un sistema componentizzato che può essere ospitato in un'ampia gamma di contesti diversi. In genere, il modello di dati è ospitato nel contesto di un'applicazione debugger. Per poter essere un host del modello di dati, è necessario implementare diverse interfacce per esporre gli aspetti principali del debugger: destinazione, spazi di memoria, analizzatore, sistema simbolico e di tipo e così via... Anche se queste interfacce vengono implementate da qualsiasi applicazione che desidera ospitare il modello di dati, vengono utilizzate sia dal modello di dati principale che da qualsiasi estensione che interagisce con il modello di dati.
Il set di interfacce principali è:
Interface Name (Nome interfaccia) | Descrizione |
---|---|
IDebugHost | Interfaccia principale per l'host di debug. |
IDebugHostStatus | Interfaccia che consente a un client di eseguire una query sullo stato dell'host. |
IDebugHostContext | Astrazione di un contesto all'interno dell'host (ad esempio, una destinazione specifica, un particolare processo, uno spazio indirizzi specifico e così via...) |
IDebugHostErrorSink | Interfaccia implementata dai chiamanti per ricevere errori da determinate parti dell'host e del modello di dati |
IDebugHostEvaluator /IDebugHostEvaluator2 | Analizzatore di espressioni dell'host di debug. |
IDebugHostExtensibility | Interfaccia per estendere le funzionalità dell'host o delle parti di esso, ad esempio l'analizzatore di espressioni. |
Il sistema dei tipi e le interfacce simboliche sono:
InterfaceName | Descrizione |
---|---|
IDebugHostSymbols | Interfaccia di base che fornisce l'accesso e la risoluzione dei simboli |
IDebugHostSymbol / IDebugHostSymbol2 | Rappresenta un singolo simbolo di qualsiasi tipo. Il simbolo specifico è una derivazione di questa interfaccia. |
IDebugHostModule | Rappresenta un modulo caricato all'interno di un processo. Questo è un tipo di simbolo. |
IDebugHostType/IDebugHostType2 | Rappresenta un tipo nativo/linguistico. |
IDebugHostConstant | Rappresenta una costante all'interno di informazioni simboliche (ad esempio, un argomento di modello non di tipo in C++) |
IDebugHostField | Rappresenta un campo all'interno di una struttura o di una classe. |
IDebugHostData | Rappresenta i dati all'interno di un modulo (che si trovavano all'interno di una struttura o di una classe che sarebbe un IDebugHostField) |
IDebugHostBaseClass | Rappresenta una classe di base. |
IDebugHostPublic | Rappresenta un simbolo all'interno della tabella publics di un PDB. Queste informazioni sul tipo non sono associate. Si tratta di un nome e di un indirizzo. |
IDebugHostModuleSignature | Rappresenta una firma del modulo: una definizione che corrisponde a un set di moduli in base al nome e/o alla versione |
IDebugHostTypeSignature | Rappresenta una firma di tipo: una definizione che corrisponde a un set di tipi in base al modulo e/o al nome |
Interfaccia host principale: IDebugHost
L'interfaccia IDebugHost è l'interfaccia principale di qualsiasi host del modello di dati. Viene definita come segue:
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;
}
Il metodo GetHostDefinedInterface restituisce l'interfaccia privata principale dell'host, se presente per l'host specificato. Per Gli strumenti di debug per Windows, l'interfaccia restituita qui è un IDebugClient (cast su IUnknown).
Il metodo GetCurrentContext restituisce un'interfaccia che rappresenta lo stato corrente dell'host del debugger. Il significato esatto di questa operazione viene lasciato all'host, ma in genere include elementi come la sessione, il processo e lo spazio indirizzi attivo nell'interfaccia utente dell'host di debug. L'oggetto contesto restituito è in gran parte opaco al chiamante, ma è un oggetto importante da passare tra le chiamate all'host di debug. Quando un chiamante è, ad esempio, la lettura della memoria, è importante conoscere il processo e lo spazio di indirizzi da cui viene letta la memoria. Tale nozione viene incapsulata nella nozione dell'oggetto contesto restituito da questo metodo.
Il metodo GetDefaultMetadata restituisce un archivio metadati predefinito che può essere usato per determinate operazioni (ad esempio: conversione di stringhe) quando non sono stati passati metadati espliciti. Ciò consente all'host di debug di avere un controllo sul modo in cui vengono presentati alcuni dati. Ad esempio, i metadati predefiniti possono includere una chiave PreferredRadix, consentendo all'host di indicare se i ordinali devono essere visualizzati in formato decimale o esadecimale se non diversamente specificato.
Si noti che i valori delle proprietà nell'archivio metadati predefinito devono essere risolti manualmente e devono passare l'oggetto per il quale vengono sottoposti a query i metadati predefiniti. Il metodo GetKey deve essere usato al posto di GetKeyValue.
Interfaccia di stato: IDebugHostStatus
L'interfaccia IDebugHostStatus consente a un client del modello di dati o all'host di debug di richiedere informazioni su determinati aspetti dello stato dell'host di debug. L'interfaccia viene definita come segue:
DECLARE_INTERFACE_(IDebugHostStatus, IUnknown)
{
STDMETHOD(PollUserInterrupt)(_Out_ bool* interruptRequested) PURE;
}
Il metodo PollUserInterrupt viene usato per verificare se l'utente dell'host di debug ha richiesto un'interruzione dell'operazione corrente. Una funzione di accesso alle proprietà nel modello di dati può, ad esempio, chiamare in codice arbitrario , ad esempio un metodo JavaScript. Tale codice può richiedere una quantità di tempo arbitraria. Per mantenere reattivo l'host di debug, qualsiasi codice di questo tipo che potrebbe richiedere una quantità arbitraria di tempo deve verificare la presenza di una richiesta di interruzione tramite la chiamata a questo metodo. Se il valore interruptRequested viene restituito come true, il chiamante deve interrompere immediatamente e restituire un risultato di E_ABORT.
Interfaccia di contesto: IDebugHostContext
Il contesto è uno degli aspetti più importanti del modello di dati e dell'host di debug sottostante. Quando si contiene un oggetto, è importante essere in grado di sapere da dove proviene un oggetto, ovvero il processo in cui si trova, lo spazio di indirizzi associato. La conoscenza di queste informazioni consente l'interpretazione corretta di elementi come i valori del puntatore. Un oggetto del tipo IDebugHostContext deve essere passato a molti metodi nell'host di debug. Questa interfaccia può essere acquisita in diversi modi:
- Recuperando il contesto corrente del debugger: chiamando il metodo GetCurrentContext di IDebugHost
- Recuperando il contesto di un oggetto: chiamando il metodo GetContext di IModelObject
- Recuperando il contesto di un simbolo: chiamando il metodo GetContext di IDebugHostSymbol
Esistono inoltre due valori che hanno un significato speciale nel contesto di un'interfaccia IDebugHostContext restituita o passata a un modello di dati o a un metodo host di debug:
nullptr: indicazione che non esiste alcun contesto. È perfettamente valido per alcuni oggetti senza contesto. L'oggetto Debugger nello spazio dei nomi radice del modello di dati non fa riferimento a nulla all'interno di un processo o di uno spazio indirizzi specifico. Non ha alcun contesto.
USE_CURRENT_HOST_CONTEXT: valore sentinel che indica che è necessario usare il contesto dell'interfaccia utente corrente dell'host di debug. Questo valore non verrà mai restituito dall'host di debug. Può tuttavia essere passato a qualsiasi metodo host di debug che accetta un input IDebugHostContext anziché chiamare in modo esplicito il metodo GetCurrentContext di IDebugHost. Si noti che il passaggio esplicito di USE_CURRENT_HOST_CONTEXT è spesso più efficiente rispetto a ottenere in modo esplicito il contesto corrente.
I contesti di un contesto host sono in gran parte opachi per il chiamante. L'unica operazione che un chiamante all'esterno dell'host di debug principale può eseguire con un contesto host consiste nel confrontarlo con un altro contesto host.
L'interfaccia IDebugHostContext è definita come segue:
DECLARE_INTERFACE_(IDebugHostContext, IUnknown)
{
STDMETHOD(IsEqualTo)(_In_ IDebugHostContext *pContext, _Out_ bool *pIsEqual) PURE;
}
Il metodo IsEqualTo confronta un contesto host in un altro contesto host. Se i due contesti sono equivalenti, viene restituita un'indicazione di questo valore. Si noti che questo confronto non è l'equivalenza dell'interfaccia. Ciò confronta il contenuto opaco sottostante del contesto stesso.
Sink di errore: IDebugHostErrorSink
IDebugHostErrorSink è un mezzo per cui un client può ricevere notifiche di errori che si verificano durante determinate operazioni e instradare tali errori in caso di necessità. L'interfaccia viene definita come segue:
enum ErrorClass
{
ErrorClassWarning,
ErrorClassError
}
DECLARE_INTERFACE_(IDebugHostErrorSink, IUnknown)
{
STDMETHOD(ReportError)(_In_ ErrorClass errClass, _In_ HRESULT hrError, _In_ PCWSTR message) PURE;
}
Il metodo ReportError è un callback nel sink di errore per notificarlo che si è verificato un errore e consentire al sink di instradare l'errore a qualsiasi interfaccia utente o meccanismo appropriato.
L'analizzatore host: IDebugHostEvaluator/IDebugHostEvaluator2
Una delle parti più importanti della funzionalità fornita dall'host di debug ai client è l'accesso al relativo analizzatore di espressioni basate sul linguaggio. Le interfacce IDebugHostEvaluator e IDebugHostEvaluator2 sono i mezzi per accedere a tale funzionalità dall'host di debug.
Le interfacce sono definite come segue:
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;
}
Il metodo EvaluateExpression consente all'host di debug di valutare un linguaggio (ad esempio: espressione C++) e restituire il valore risultante di tale valutazione dell'espressione casellata come IModelObject. Questa particolare variante del metodo consente solo costrutti del linguaggio. Tutte le funzionalità aggiuntive presentate all'interno dell'analizzatore di espressioni dell'host di debug che non sono presenti nel linguaggio (ad esempio, i metodi di query LINQ) vengono disattivati per la valutazione.
Il metodo EvaluateExtendedExpression è simile al metodo EvaluateExpression, ad eccezione del fatto che restituisce funzionalità aggiuntive di non linguaggio che un determinato host di debug sceglie di aggiungere al relativo analizzatore di espressioni. Per Gli strumenti di debug per Windows, ad esempio, consente tipi anonimi, query LINQ, qualificatori di moduli, identificatori di formato e altre funzionalità non C/C++.
IDebugHostEvaluator2
Il metodo AssignTo esegue l'assegnazione in base alla semantica del linguaggio sottoposto a debug.
Interfaccia di estendibilità host: IDebugHostExtensibility
Alcune funzionalità dell'host di debug sono facoltativamente soggette all'estendibilità. Può, ad esempio, includere l'analizzatore di espressioni. L'interfaccia IDebugHostExtensibility è il mezzo a cui si accede a questi punti di estendibilità. L'interfaccia viene definita come segue:
DECLARE_INTERFACE_(IDebugHostExtensibility, IUnknown)
{
STDMETHOD(CreateFunctionAlias)(_In_ PCWSTR aliasName, _In_ IModelObject *functionObject) PURE;
STDMETHOD(DestroyFunctionAlias)(_In_ PCWSTR aliasName) PURE;
}
Il metodo CreateFunctionAlias crea un "alias di funzione", un "alias rapido" per un metodo implementato in un'estensione. Il significato di questo alias è specifico dell'host. Può estendere l'analizzatore di espressioni dell'host con la funzione o può eseguire operazioni completamente diverse.
Il metodo DestroyFunctionAlias annulla una chiamata precedente al metodo CreateFunctionAlias. La funzione non sarà più disponibile sotto il nome alias rapido.
Accesso al modello di dati
Innanzitutto, le API di estendibilità del modello di dati sono progettate per essere neutrali per l'applicazione (in genere un debugger) che funge da host del modello di dati. In teoria, qualsiasi applicazione può ospitare il modello di dati fornendo un set di API host che espongono il sistema di tipi delle destinazioni di debug dell'applicazione e un set di oggetti proiettati nello spazio dei nomi del modello di dati su quali destinazioni, elabora, thread e così via... sono presenti in tali target di debug.
Anche se le API del modello di dati , quelle che iniziano IDataModel, IDebugHost e le derivazioni di IModelObject, sono progettate per essere portatili, non definiscono l'estensione del "debugger". Oggi, un componente che desidera estendere gli strumenti di debug per Windows e il motore che fornisce deve scrivere un'estensione del motore per ottenere l'accesso al modello di dati. L'estensione del motore deve essere solo un'estensione del motore in quanto è il meccanismo di caricamento e avvio automatico per l'estensione. Di conseguenza, un'implementazione minima fornirebbe:
- DebugExtensionInitialize: metodo che usa un oggetto IDebugClient creato per ottenere l'accesso al modello di dati e configurare le manipolazioni del modello a oggetti.
- DebugExtensionUninitialize: metodo che annulla le manipolazioni del modello a oggetti eseguite in DebugExtensionInitialize.
- DebugExtensionCanUnload: metodo che restituisce se l'estensione può scaricare. Se nell'estensione sono ancora presenti oggetti COM in tempo reale, deve indicare questo. Si tratta dell'equivalente del debugger di DllCanUnloadNow di COM. Se restituisce l'indicazione S_FALSE di incapacità di scaricare, il debugger può eseguire una query in un secondo momento per verificare se un caricamento è sicuro o può reinizializzare l'estensione chiamando di nuovo DebugExtensionInitialize. L'estensione deve essere preparata per gestire entrambi i percorsi.
- DebugExtensionUnload: metodo che esegue una pulizia finale necessaria prima che la DLL venga scaricata
Interfaccia bridge: IHostDataModelAccess
Come accennato, quando viene chiamato DebugExtensionInitialize, crea un client di debug e ottiene l'accesso al modello di dati. Tale accesso viene fornito da un'interfaccia bridge tra le interfacce IDebug* legacy di Strumenti di debug per Windows e il modello di dati. Questa interfaccia bridge è 'IHostDataModelAccess e viene definita come segue:
DECLARE_INTERFACE_(IHostDataModelAccess, IUnknown)
{
STDMETHOD(GetDataModel)(_COM_Outptr_ IDataModelManager** manager, _COM_Outptr_ IDebugHost** host) PURE;
}
Il metodo GetDataModel è il metodo sull'interfaccia bridge che fornisce l'accesso a entrambi i lati del modello di dati: l'host di debug (il bordo inferiore del debugger) viene espresso dall'interfaccia IDebugHost restituita Il componente principale del modello di dati - il gestore dei modelli di dati viene espresso dall'interfaccia IDataModelManager restituita
Interfacce del sistema del modello di dati debugger
Host modello di dati
Il modello di dati debugger è progettato per essere un sistema componentizzato che può essere ospitato in un'ampia gamma di contesti diversi. In genere, il modello di dati è ospitato nel contesto di un'applicazione debugger. Per essere un host del modello di dati, è necessario implementare diverse interfacce per esporre gli aspetti principali del debugger: la destinazione, i relativi spazi di memoria, il relativo analizzatore, il relativo sistema simbolico e di tipo e così via... Anche se queste interfacce vengono implementate da qualsiasi applicazione che desidera ospitare il modello di dati, vengono usate dal modello di dati di base e da qualsiasi estensione che interopera con il modello di dati.
Il sistema di tipi e le interfacce simboliche sono:
Interface Name (Nome interfaccia) | Descrizione |
---|---|
IDebugHostSymbols | Interfaccia di base che fornisce l'accesso ai simboli e la risoluzione dei simboli |
IDebugHostSymbol / IDebugHostSymbol2 | Rappresenta un singolo simbolo di qualsiasi tipo. Il simbolo specifico è una derivazione di questa interfaccia. |
IDebugHostModule | Rappresenta un modulo caricato all'interno di un processo. Questo è un tipo di simbolo. |
IDebugHostType/ IDebugHostType2 | Rappresenta un tipo nativo/linguistico. |
IDebugHostConstant | Rappresenta una costante all'interno di informazioni simboliche, ad esempio un argomento modello non di tipo in C++) |
IDebugHostField | Rappresenta un campo all'interno di una struttura o di una classe. |
IDebugHostData | Rappresenta i dati all'interno di un modulo ,ovvero all'interno di una struttura o di una classe, sarebbe un IDebugHostField. |
IDebugHostBaseClass | Rappresenta una classe di base. |
IDebugHostPublic | Rappresenta un simbolo all'interno della tabella publics di un database PDB. Non dispone di informazioni sul tipo associate. È un nome e un indirizzo. |
IDebugHostModuleSignature | Rappresenta una firma del modulo : una definizione che corrisponde a un set di moduli in base al nome e/o alla versione |
IDebugHostTypeSignature | Rappresenta una firma di tipo : una definizione che corrisponde a un set di tipi in base al modulo e/o al nome |
Le altre interfacce di base sono:
Interface Name (Nome interfaccia) | Descrizione |
---|---|
IDebugHost | Interfaccia principale dell'host di debug. |
IDebugHostStatus | Interfaccia che consente a un client di eseguire una query sullo stato dell'host. |
IDebugHostContext | Astrazione di un contesto all'interno dell'host (ad esempio, una determinata destinazione, un processo specifico, uno spazio indirizzi specifico e così via...) |
IDebugHostErrorSink | Interfaccia implementata dai chiamanti per ricevere errori da determinate parti dell'host e del modello di dati |
IDebugHostEvaluator/ IDebugHostEvaluator2 | Analizzatore dell'espressione dell'host di debug. |
IDebugHostExtensibility | Interfaccia per estendere le funzionalità dell'host o delle parti di esso , ad esempio l'analizzatore di espressioni. |
Interfaccia simbolica principale: IDebugHostSymbols
L'interfaccia IDebugHostSymbols è il punto di partenza principale per accedere ai simboli nella destinazione di debug. Questa interfaccia può essere eseguita una query da un'istanza di IDebugHost e viene definita come segue:
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;
}
Il metodo CreateModuleSignature crea una firma che può essere usata per corrispondere a un set di moduli specifici in base al nome e facoltativamente, in base alla versione. Sono disponibili tre componenti per una firma del modulo:
- Nome: un modulo corrispondente deve avere un nome che corrisponde a una corrispondenza senza distinzione tra maiuscole e minuscole rispetto al nome nella firma
- Versione minima: se specificata, un modulo corrispondente deve avere una versione minima che sia almeno alta come questa versione. Le versioni vengono specificate in formato "A.B.C.D" con ogni parte successiva meno importante rispetto alla precedente. Solo il primo segmento è obbligatorio.
- Versione massima: se specificata, un modulo corrispondente deve avere una versione massima che non è superiore a quella di questa versione. Le versioni vengono specificate in formato "A.B.C.D" con ogni parte successiva meno importante rispetto alla precedente. Solo il primo segmento è obbligatorio.
Il metodo CreateTypeSignature crea una firma che può essere usata per corrispondere a un set di tipi di cemento contenente il nome del modulo e del tipo. Il formato della stringa di firma del nome di tipo è specifico del linguaggio in fase di debug (e dell'host di debug). Per C/C++, la stringa di firma equivale a una specifica del tipo NatVis. Ovvero, la stringa di firma è un nome di tipo in cui i caratteri jolly (specificati come *) sono consentiti per gli argomenti del modello.
CreateTypeSignatureForModuleRange
Il metodo CreateTypeSignatureForModuleRange crea una firma che può essere usata per corrispondere a un set di tipi concreti in base alla firma del modulo e al nome del tipo. È simile al metodo CreateTypeSignature, ad eccezione del fatto che invece di passare un modulo specifico alla corrispondenza per la firma, il chiamante passa gli argomenti necessari per creare una firma del modulo , come se la firma del modulo fosse stata creata con il metodo CreateModuleSignature.
Il metodo EnumerateModules crea un enumeratore che enumera ogni modulo disponibile in un determinato contesto host. Tale contesto host potrebbe incapsulare un contesto di processo o incapsulare qualcosa come il kernel di Windows.
Il metodo FindModuleByName esaminerà il contesto host specificato e individua un modulo con il nome specificato e restituirà un'interfaccia. È legale cercare il modulo in base al nome o senza l'estensione del file.
Il metodo FindModuleByLocation esaminerà il contesto host specificato e determinerà quale modulo contiene l'indirizzo specificato dalla posizione specificata. Restituirà quindi un'interfaccia a tale modulo.
GetMostDerivedObject userà il sistema di tipo del debugger per determinare il tipo di runtime di un oggetto dal tipo statico. Questo metodo userà solo informazioni simboliche e euristica disponibili nel livello di sistema dei tipi per eseguire questa analisi. Tali informazioni possono includere RTTI C++ (informazioni sul tipo di runtime) o l'analisi della forma delle tabelle delle funzioni virtuali dell'oggetto. Non include elementi come il concetto di tipo di runtime preferito in un IModelObject. Se l'analisi non riesce a trovare un tipo di runtime o non riesce a trovare un tipo di runtime diverso dal tipo statico passato al metodo, il percorso di input e il tipo possono essere passati. Il metodo non avrà esito negativo per questi motivi.
Interfaccia del simbolo singolo di base: IDebugHostSymbol
Ogni simbolo che può essere restituito dall'host del modello di dati deriva in qualche modo da IDebugHostSymbol. Si tratta dell'interfaccia principale che ogni simbolo implementa indipendentemente dal tipo di simbolo. A seconda del tipo di simbolo, un determinato simbolo può implementare un set di altre interfacce che restituiscono attributi più univoci al particolare tipo di simbolo rappresentato da questa interfaccia. L'interfaccia IDebugHostSymbol2/IDebugHostSymbol è definita come segue:
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;
}
È molto importante notare che questa interfaccia rappresenta molti tipi di simboli, delineati dall'enumerazione SymbolKind con valori come indicato di seguito:
Enumarant | Significato |
---|---|
Simbolo | Tipo di simbolo non specificato |
SymbolModule | Il simbolo è un modulo e può essere sottoposto a query per IDebugHostModule |
SymbolType | Il simbolo è un tipo e può essere sottoposto a query per IDebugHostType |
SymbolField | Il simbolo è un campo (un membro dati all'interno di una struttura o una classe) e può essere sottoposto a query per IDebugHostField |
SymbolConstant | Il simbolo è un valore costante e può essere eseguito una query per IDebugHostConstant |
SymbolData | Il simbolo è dati che non è un membro di una struttura o di una classe ed è queryabile per IDebugHostData |
SymbolBaseClass | Il simbolo è una classe di base ed è queryabile per IDebugHostBaseClass |
SymbolPublic | Il simbolo è una voce nella tabella publics di un modulo (senza informazioni sul tipo) ed è queryabile per IDebugHostPublic |
SymbolFunction | Il simbolo è una funzione ed è queryabile per IDebugHostData |
Il metodo GetContext restituisce il contesto in cui il simbolo è valido. Anche se questo rappresenta gli elementi come la destinazione di debug e lo spazio degli indirizzi in cui esiste il simbolo, potrebbe non essere specifico come un contesto recuperato da altri mezzi ,ad esempio da un IModelObject.
Il metodo EnumerateChildren restituisce un enumeratore che enumera tutti gli elementi figlio di un determinato simbolo. Per un tipo C++, ad esempio, le classi di base, i campi, le funzioni membro e il tipo sono tutti considerati elementi figlio del simbolo di tipo.
Interfaccia del modulo: IDebugHostModule
La nozione del debugger di un modulo caricato all'interno di uno spazio indirizzi è rappresentato in due modi distinti nel modello di dati: a livello di sistema del tipo tramite l'interfaccia IDebugHostModule. In questo caso, un modulo è un simbolo e gli attributi principali del modulo sono chiamate al metodo di interfaccia chiamate Projected a livello di modello di dati tramite il modello di dati Debugger.Models.Module. Si tratta di un'incapsulazione estendibile della rappresentazione IDebugHostModule del sistema di tipo di un modulo.
L'interfaccia IDebugHostModule è definita come segue (ignorando i metodi generici per 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;
}
Il metodo GetImageName restituisce il nome dell'immagine del modulo. A seconda del valore dell'argomento allowPath, il nome dell'immagine restituito può o meno includere il percorso completo dell'immagine.
Il metodo GetBaseLocation restituisce l'indirizzo di carico di base del modulo come struttura di posizione. La struttura della posizione restituita per un modulo fa in genere riferimento a un indirizzo virtuale.
Il metodo GetVersion restituisce informazioni sulla versione del modulo (presupponendo che tali informazioni possano essere letti correttamente dalle intestazioni). Se viene richiesta una determinata versione (tramite un puntatore di output non nullptr) e non può essere letto, verrà restituito un codice di errore appropriato dalla chiamata al metodo.
Il metodo FindTypeByName trova un tipo definito all'interno del modulo in base al nome del tipo e restituisce un simbolo di tipo per esso. Questo metodo può restituire un IDebugHostType valido che non verrà mai restituito tramite ricorsioni esplicite degli elementi figlio del modulo. L'host di debug può consentire la creazione di tipi derivati, i tipi non mai usati all'interno del modulo stesso, ma derivati dai tipi che sono. Ad esempio, se la struttura MyStruct è definita nei simboli del modulo, ma il tipo MyStruct ** non viene mai usato, il metodo FindTypeByName può restituire legittimamente un simbolo di tipo per MyStruct ** nonostante tale nome di tipo non venga mai visualizzato in modo esplicito nei simboli per il modulo.
Il metodo FindSymbolByRVA troverà un singolo simbolo di corrispondenza all'indirizzo virtuale relativo specificato all'interno del modulo. Se non è presente un singolo simbolo nella RVA fornita (ad esempio, ci sono più corrispondenze), verrà restituito un errore da questo metodo. Si noti che questo metodo preferisce restituire un simbolo privato su un simbolo nella tabella publics.
Il metodo FindSymbolByName troverà un singolo simbolo globale del nome specificato all'interno del modulo. Se non è presente un singolo simbolo corrispondente al nome specificato, verrà restituito un errore da questo metodo. Si noti che questo metodo preferisce restituire un simbolo privato rispetto a un simbolo nella tabella publics.
Accesso al sistema di tipi: IDebugHostType2/IDebugHostType
Un determinato tipo nativo/lingua viene descritto dalle interfacce IDebugHostType2 o IDebugHostType. Si noti che alcuni dei metodi di queste interfacce si applicano solo a tipi specifici di tipi. Un determinato simbolo di tipo può fare riferimento a uno dei tipi seguenti, come descritto dall'enumerazione TypeKind:
Tipo tipo | Descrizione |
---|---|
TypeUDT | Tipo definito dall'utente (struct, classe, unione e così via). Oggetto modello che ha un tipo nativo il cui tipo è TypeUDT ha una rappresentazione canonica di ObjectTargetObject in cui il tipo viene sempre mantenuto all'interno dell'IModelObject corrispondente. |
TypePointer | Puntatore. Oggetto modello con un tipo nativo il cui tipo è TypePointer ha una rappresentazione canonica di ObjectIntrinsic in cui il valore del puntatore è zero esteso a VT_UI8 e mantenuto come dati intrinseci in questo formato a 64 bit. Qualsiasi simbolo di tipo di TypePointer ha un tipo di base (come restituito dal metodo GetBaseType) del tipo a cui punta il puntatore. |
TypeMemberPointer | Puntatore al membro della classe. Oggetto modello che ha un tipo nativo il cui tipo è TypeMemberPointer ha una rappresentazione canonica che è intrinseca (il valore è uguale al valore del puntatore). Il significato esatto di questo valore è specifico dell'host compilatore/di debug. |
TypeArray | Matrice . Oggetto modello che ha un tipo nativo il cui tipo è TypeArray ha una rappresentazione canonica di ObjectTargetObject. L'indirizzo di base della matrice è la posizione dell'oggetto (recuperata tramite il metodo GetLocation) e il tipo della matrice viene sempre mantenuto. Qualsiasi simbolo di tipo di TypeArray ha un tipo di base (come restituito dal metodo GetBaseType) del tipo di cui la matrice è una matrice. |
TypeFunction | Una funzione. |
TypeTypedef | Typedef. Oggetto modello con un tipo nativo il cui tipo sarebbe altrimenti TypeTypedef ha una rappresentazione canonica identica alla rappresentazione canonica del tipo finale sottostante il typedef. Ciò risulta completamente trasparente per l'utente finale dell'oggetto e le informazioni sul tipo, a meno che i metodi typedef espliciti di IDebugHostType2 non vengano utilizzati per eseguire query sulle informazioni typedef o che sia presente un modello di dati esplicito registrato con il typedef. Si noti che il metodo GetTypeKind non restituirà mai TypeTypedef. Ogni metodo restituirà il tipo finale sottostante il typedef restituito. Esistono metodi specifici typedef in IDebugHostType2 che possono essere usati per ottenere le informazioni specifiche del typedef. |
TypeEnum | Enumerazione. Oggetto modello che ha un tipo nativo il cui tipo è TypeEnum ha una rappresentazione canonica di ObjectIntrinsic in cui il valore e il tipo dell'intrinseco sono identici al valore enumerazione. |
TypeIntrinsic | Intrinseco (tipo di base). Oggetto modello che ha un tipo nativo il cui tipo è TypeIntrinsic ha una rappresentazione canonica di ObjectIntrinsic. Le informazioni sul tipo possono o non essere mantenute, in particolare se il tipo sottostante è descritto completamente dal tipo di dati variant (VT_*) dei dati intrinseci archiviati in IModelObject |
L'interfaccia IDebugHostType2/IDebugHostType è definita come segue (esclusi i metodi 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;
}
Metodi generali IDebugHostType2/IDebugHostType
I metodi IDebugHostType seguenti sono generali per qualsiasi tipo indipendentemente dal tipo restituito dal metodo 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;
Il metodo GetTypeKind restituisce il tipo di tipo (puntatore, matrice, intrinseco e così via) a cui fa riferimento il simbolo.
Il metodo GetSize restituisce le dimensioni del tipo , come se fosse stato eseguito sizeof(type) in C++.
Se il tipo è un derivato di un altro tipo singolo(ad esempio, come MyStruct * è derivato da MyStruct'), il metodo GetBaseType restituisce il tipo di base della derivazione. Per i puntatori, restituisce il tipo a cui punta. Per le matrici, restituisce l'elemento di cui la matrice è una matrice. Se il tipo non è un tipo derivato di questo tipo, viene restituito un errore.
Il metodo GetHashCode restituisce un codice hash a 32 bit per il tipo. Ad eccezione di una corrispondenza globale (ad esempio, una firma di tipo equivalente a * che corrisponde a tutto se consentito dall'host), qualsiasi istanza di tipo che può corrispondere a una firma di tipo specifica deve restituire lo stesso codice hash. Questo metodo viene usato insieme alle firme del tipo per trovare la corrispondenza tra firme di tipo e istanze di tipo.
Metodi intrinseci IDebugHostType2/IDebugHostType
I metodi IDebugHostType seguenti sono specifici dei tipi intrinseci (o tipi che contengono dati intrinseci, ad esempio enumerazioni):
STDMETHOD(GetIntrinsicType)(_Out_opt_ IntrinsicKind *intrinsicKind, _Out_opt_ VARTYPE *carrierType) PURE;
Il metodo GetIntrinsicType restituisce informazioni sul tipo intrinseco del tipo. Due valori vengono restituiti da questo metodo:
- Il tipo intrinseco indica il tipo complessivo (ad esempio, integer, senza segno, a virgola mobile) ma non le dimensioni del tipo (ad esempio 8 bit, 16 bit, 32 bit, 64 bit)
- Il tipo di vettore indica il modo in cui il tipo intrinseco viene inserito in una struttura VARIANT. Si tratta di una costante VT_*.
La combinazione dei due valori fornisce il set completo di informazioni sull'intrinseco.
Metodi di bit IDebugHostType2/IDebugHostType
I metodi IDebugHostType seguenti sono specifici dei tipi che archiviano i dati in campi bit. Le informazioni sul posizionamento dei campi di bit all'interno di un oggetto intrinseco vengono archiviate come parte del simbolo di tipo nel modello di dati anziché essere un attributo della posizione.
STDMETHOD(GetBitField)(_Out_ ULONG* lsbOfField, _Out_ ULONG* lengthOfField) PURE;
Se un determinato membro di una struttura di dati è un campo di bit ,ad esempio ULONG MyBits:8, le informazioni sul tipo per il campo contengono informazioni sul posizionamento del campo di bit. Il metodo GetBitField può essere utilizzato per recuperare tali informazioni. Questo metodo avrà esito negativo in qualsiasi tipo che non è un campo di bit. Questo è l'unico motivo per cui il metodo avrà esito negativo. La semplice chiamata a questo metodo e l'analisi dell'esito positivo/negativo è sufficiente per distinguere un campo di bit da un campo non bit. Se un determinato tipo è un campo di bit, le posizioni dei campi vengono definite dal set aperto a metà (lsbOfField + lengthOfField : lsbOfField: lsbOfField]
Metodi correlati al puntatore IDebugHostType2/IDebugHostType
I metodi IDebugHostType seguenti sono specifici dei tipi di puntatore. Questi sono i tipi in cui GetTypeKind restituisce TypePointer o TypeMemberPointer':
STDMETHOD(GetPointerKind)(_Out_ PointerKind* pointerKind) PURE;
STDMETHOD(GetMemberType)(_Out_ IDebugHostType** memberType) PURE;
Per i tipi che sono puntatori, il metodo GetPointerKind restituisce il tipo di puntatore. Questo valore viene definito dall'enumerazione PointerKind.
Per i tipi che sono puntatore a membro (come indicato da un tipo di typeMemberPointer), il metodo GetMemberType restituisce la classe di cui il puntatore è un puntatore a membro.
Metodi correlati alla matrice IDebugHostType2/IDebugHostType
Le matrici sono tipi in cui GetTypeKind restituisce TypeArray. Si noti che le matrici definite dal sistema di tipi dell'host di debug non sono uguali alle matrici monodimensionali, in base all'indice zero, confezionate matrici lineari unidimensionali utilizzate da C. Le matrici di stile C rientrano nella definizione, ma l'ambito complessivo di una matrice è più ampio in IDebugHostType. Una matrice nell'host di debug può essere multidimensionale e ogni dimensione all'interno della matrice è definita da un descrittore noto come descrittore ArrayDimensionThis include i campi seguenti:
Campo | Significato |
---|---|
LowerBound | Indice di base della matrice come valore a 64 bit con segno. Per una matrice di stile C, questo valore sarà sempre zero. Non deve essere. Una singola dimensione di una matrice può essere considerata in corrispondenza di un indice a 64 bit, anche una negativa. |
Length | Lunghezza della dimensione di matrice come valore senza segno a 64 bit. Gli indici della matrice si estendono sulla metà set aperto [LowerBound, LowerBound + Length). |
Stride | Definisce lo stride della dimensione della matrice. Per un aumento di uno (da N a N + 1) nell'indice di questa dimensione, questo indica il numero di byte da spostare in avanti in memoria. Per una matrice di stile C, si tratta della dimensione di ogni elemento della matrice. Non ha bisogno di essere. La spaziatura interna tra gli elementi può essere espressa come stride maggiore della dimensione di ogni singolo elemento. Per le matrici multidimensionali, questo valore indica come spostare un'intera dimensione in avanti. Si consideri una matrice M x N. Questa operazione può essere descritta in forma principale di riga come due dimensioni: |
{ [LowerBound: 0, Length: M, Stride: N \* sizeof(element)], [LowerBound: 0, Length: N, Stride: sizeof(element)]}
oppure potrebbe essere descritto in alternativa in formato colonna-principale come due dimensioni:
{ [LowerBound: 0, Length: M, Stride: sizeof(element)], [LowerBound: 0, Length: N, Stride: M \* sizeof(element)]}
Il concetto di ArrayDimension consente questo grado di flessibilità.
I metodi IDebugHostType seguenti sono specifici dei tipi di matrice.
STDMETHOD(GetArrayDimensionality)(\_Out_ ULONG64\* arrayDimensionality) PURE;
STDMETHOD(GetArrayDimensions)(\_In_ ULONG64 dimensions, \_Out_writes_(dimensions) ArrayDimension \*pDimensions) PURE;
Il metodo GetArrayDimensionality restituisce il numero di dimensioni in cui è indicizzata la matrice. Per le matrici di stile C, il valore restituito qui sarà sempre 1.
Il metodo GetArrayDimensions restituisce un set di descrittori, uno per ogni dimensione della matrice, come indicato dal metodo GetArrayDimensionality. Ogni descrittore è una struttura ArrayDimension che descrive l'indice iniziale, la lunghezza e lo stride forward di ogni dimensione di matrice. Ciò consente descrizioni di costrutti di matrice notevolmente più potenti di quelli consentiti nel sistema di tipi C.
Per le matrici di tipo C, viene restituita una singola dimensione di matrice qui con valori che sono sempre:
- LowerBound = 0
- Length = ARRAYSIZE(array)
- Stride = sizeof(elementType)
Metodi correlati alla funzione IDebugHostType2/IDebugHostType
I tipi che indicano che sono tipi di funzione tramite un tipo di TypeFunction supportano i metodi seguenti sia in IDebugHostType che in 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;
Il metodo GetFunctionCallingConvention restituisce la convenzione di chiamata della funzione. Tale valore viene restituito come membro dell'enumerazione CallingConventionKind.
Il metodo GetFunctionReturnType restituisce il tipo restituito della funzione.
Il metodo GetFunctionParameterTypeCount restituisce il numero di argomenti accettati dalla funzione. Si noti che il marcatore di argomento variabile basato sui puntini di sospensione C/C++ non viene considerato in questo conteggio. La presenza di tali elementi deve essere rilevata tramite il metodo GetFunctionVarArgsKind. Verranno inclusi solo gli argomenti prima dei puntini di sospensione.
Il metodo GetFunctionParameterTypeAt restituisce il tipo dell'argomento i-th alla funzione.
Il metodo GetFunctionVarArgsKind restituisce se una determinata funzione utilizza un elenco di argomenti di variabile e, in tal caso, lo stile degli argomenti di variabile utilizzato. Tale valore viene definito da un membro dell'enumerazione VarArgsKind definita come segue:
Enumerante | Significato |
---|---|
VarArgsNone | La funzione non accetta argomenti di variabile. |
VarArgsCStyle | La funzione è una funzione varargs di tipo C (returnType(arg1, arg2, ...)). Il numero di argomenti segnalati dalla funzione non include l'argomento con i puntini di sospensione. Qualsiasi argomento variabile passato si verifica dopo il numero di argomenti restituiti dal metodo GetFunctionParameterTypeCount. |
IDebugHostType2 GetFunctionVarArgsKind
Il metodo GetFunctionVarArgsKind restituisce se una determinata funzione utilizza un elenco di argomenti di variabile e, in tal caso, lo stile degli argomenti di variabile utilizzato. Tale valore viene definito da un membro dell'enumerazione VarArgsKind definita come segue:
Metodi correlati a IDebugHostType2/IDebugHostType
Qualsiasi tipo che è un typedef si comporta come se il tipo sia il tipo finale sottostante il typedef. Ciò significa che i metodi come GetTypeKind non indicano che il tipo è un typedef. Analogamente, GetBaseType non restituirà il tipo a cui fa riferimento la definizione. Indicano invece il comportamento come se fossero stati chiamati nella definizione finale sottostante il typedef. Ad esempio:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
Un IDebugHostType per 'PMYSTRUCT o PTRMYSTRUCT invierà le informazioni seguenti:
- Il metodo GetTypeKind restituirà TypePointer. Il tipo sottostante finale MYSTRUCT * è effettivamente un puntatore.
- Il metodo 'GetBaseType restituirà un tipo per MYSTRUCT. Il tipo sottostante di MYSTRUCT * è MYSTRUCT.
L'unica differenza è il comportamento dei metodi specifici typedef in IDebugHostType2. Questi metodi sono:
STDMETHOD(IsTypedef)(_Out_ bool* isTypedef) PURE;
STDMETHOD(GetTypedefBaseType)(_Out_ IDebugHostType2** baseType) PURE;
STDMETHOD(GetTypedefFinalBaseType)(_Out_ IDebugHostType2** finalBaseType) PURE;
Esempio:
- Il metodo IsTypedef restituirà true sia per PMYSTRUCT che per PTRMYSTRUCT
- Il metodo GetTypedefBaseType restituirà MYSTRUCT * per PMYSTRUCT e PMYSTRUCT per PTRMYSTRUCT
- Il metodo GetTypedefFinalBaseType restituirà MYSTRUCT * per entrambi i tipi
Il metodo IsTypedef è l'unico metodo in grado di vedere se un tipo è un typedef. Il metodo GetTypeKind si comporterà come se chiamato sul tipo sottostante.
Il metodo GetTypedefBaseType restituirà la definizione immediata del typedef. Negli esempi descritti nella documentazione:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
questo metodo restituirà MYSTRUCT * per PMYSTRUCT e PMYSTRUCT per PTRMYSTRUCT.
Il metodo GetTypedefFinalBaseType restituirà il tipo finale per cui il typedef è una definizione. Se typedef è una definizione di un altro typedef, questo continuerà a seguire la catena di definizioni fino a raggiungere un tipo che non è un typedef e tale tipo verrà restituito. Negli esempi descritti nella documentazione:
typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;
questo metodo restituirà MYSTRUCT * quando viene chiamato su PMYSTRUCT o PTRMYSTRUCT.
Metodi di creazione del tipo 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;
Valori dei simboli costanti: IDebugHostConstant
Per le posizioni in cui i valori costanti sono presenti nelle informazioni simboliche (dove un particolare valore è un simbolo che può o meno essere un valore costante), l'interfaccia IDebugHostConstant esprime il concetto di tale costante. Questa operazione viene in genere usata in posizioni come argomenti modello in cui un determinato argomento è in genere un tipo, ma può essere invece un argomento modello non di tipo , ad esempio una costante.
L'interfaccia IDebugHostConstant è definita come segue (ignorando i metodi generici implementati da IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostConstant, IDebugHostSymbol)
{
STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}
Il metodo GetValue restituisce il valore della costante compressa in un valore VARIANT. È importante notare che il metodo GetType in IDebugHostSymbol può restituire un simbolo di tipo specifico per la costante. In questi casi, non esiste alcuna garanzia che la compressione del valore costante definito dal simbolo di tipo sia uguale alla compressione restituita dal metodo GetValue qui.
Accesso ai membri dati: IDebugHostField
La classe IDebugHostField rappresenta un simbolo che è un membro dati di una classe, una struttura, un'unione o un altro costrutto di tipo. Non rappresenta dati liberi (ad esempio, dati globali). L'interfaccia è definita come segue (ignorando i metodi generici per 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;
}
Il metodo GetLocationKind restituisce il tipo di posizione in cui si trova il simbolo in base all'enumerazione LocationKind. Tale enumerazione può essere uno dei valori seguenti:
Enumerante | Significato |
---|---|
LocationMember | Il campo è un membro dati regolare di una classe, una struttura, un'unione o un altro costrutto di tipo. Ha un offset relativo all'indirizzo di base del costrutto di tipo contenitore. Tale indirizzo di base è in genere rappresentato dal puntatore. L'offset del campo può essere recuperato tramite il metodo GetOffset. I metodi GetLocation e GetValue avranno esito negativo per un campo che è LocationMember. |
LocationStatic | Il campo è statico e ha il proprio indirizzo. Il metodo GetLocation restituirà la posizione astratta (ad esempio: indirizzo) del campo statico. I metodi GetOffset e GetValue avranno esito negativo per un campo che è LocationStatic. |
LocationConstant | Il campo è una costante e ha un valore. Il metodo GetValue restituirà il valore della costante. I metodi GetOffset e GetLocation avranno esito negativo per un campo che è LocationConstant |
LocationNone | Il campo non ha posizione. Potrebbe essere stato ottimizzato dal compilatore o potrebbe essere un campo statico dichiarato ma mai definito. Indipendentemente dal modo in cui tale campo è venuto a essere, non ha alcuna presenza fisica o valore. È solo nei simboli. Tutti i metodi di acquisizione (GetOffset, GetLocation e GetValue) avranno esito negativo per un campo che è LocationNone. |
Per i campi che hanno un offset (ad esempio, campi il cui tipo di posizione indica LocationMember), il metodo GetOffset restituirà l'offset dall'indirizzo di base del tipo contenente (questo puntatore) ai dati per il campo stesso. Tali offset vengono sempre espressi come valori senza segno a 64 bit. Se il campo specificato non ha una posizione che corrisponde a un offset dall'indirizzo di base del tipo contenente, il metodo GetOffset avrà esito negativo.
Per i campi che hanno un indirizzo indipendentemente dall'istanza di tipo specifica (ad esempio, campi il cui tipo di posizione indica LocationStatic), il metodo GetLocation restituirà la posizione astratta (indirizzo) del campo. Se il campo specificato non ha una posizione statica, il metodo GetLocation avrà esito negativo.
Per i campi che hanno un valore costante definito all'interno delle informazioni simbolico (ad esempio i campi il cui tipo di posizione indica LocationConstant), il metodo GetValue restituirà il valore costante del campo. Se il campo specificato non ha un valore costante, il metodo GetValue avrà esito negativo.
Accesso gratuito ai dati: IDebugHostData
I dati nei moduli che non sono membri di un altro tipo sono rappresentati dall'interfaccia IDebugHostData. Questa interfaccia è definita come segue (ignorando i metodi generici per IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostData, IDebugHostSymbol)
{
STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}
Tutti questi metodi sono semanticamente equivalenti alle loro controparti in IDebugHostField. L'unica differenza è che il metodo GetLocationKind non restituirà mai LocationMember per dati gratuiti.
Il metodo GetLocationKind restituisce il tipo di posizione in cui si trova il simbolo in base all'enumerazione LocationKind. La descrizione di questa enumerazione è disponibile nella documentazione di IDebugHostField.
Per i dati con un indirizzo, il metodo GetLocation restituirà la posizione astratta (indirizzo) del campo. Se i dati specificati non hanno una posizione statica, il metodo GetLocation avrà esito negativo.
Per i dati che hanno un valore costante definito all'interno delle informazioni simbolica ,ad esempio i dati il cui tipo di posizione indica LocationConstant, il metodo GetValue restituirà il valore costante del campo. Se i dati specificati non hanno un valore costante, il metodo GetValue avrà esito negativo.
Classi di base: IDebugHostBaseClass
La gerarchia di ereditarietà di un determinato tipo viene espressa tramite elementi figlio di un simbolo di tipo. Se un determinato tipo deriva (ereditarietà a livello di ereditarietà) da uno o più tipi, saranno presenti uno o più elementi figlio symbolBaseClass del simbolo di tipo per il tipo. Ognuno di questi simboli SymbolBaseClass rappresenta l'ereditarietà immediata da un tipo specifico. Il nome della classe di base è sia il nome del simbolo SymbolBaseClass sia quello del simbolo di tipo per la classe di base. Il metodo GetType sul simbolo SymbolBaseClass può essere usato per ottenere il simbolo di tipo per la classe base stessa. La gerarchia di ereditarietà completa può essere attraversata esplorando in modo ricorsivo i simboli figlio SymbolBaseClass. Ognuno di questi simboli di classe di base è espresso dall'interfaccia IDebugHostBaseClass definita come segue (ignorando i metodi generici per IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostBaseClass, IDebugHostSymbol)
{
STDMETHOD(GetOffset)(_Out_ ULONG64* offset) PURE;
}
Il metodo GetOffset restituisce l'offset della classe base dall'indirizzo di base della classe derivata. Tale offset può essere zero o può essere un valore non firmato positivo a 64 bit.
Simboli pubblici: IDebugHostPublic
I simboli pubblici rappresentano gli elementi nella tabella pubblica all'interno di un file di simboli. Sono, in effetti, indirizzi di esportazione. Non sono presenti informazioni di tipo associate a un simbolo pubblico, solo un indirizzo. A meno che un simbolo pubblico non venga richiesto in modo esplicito dal chiamante, l'host di debug preferisce restituire simboli privati per ogni richiesta. Un simbolo pubblico viene espresso dall'interfaccia IDebugHostPublic definita come segue (ignorando i metodi generici per IDebugHostSymbol):
DECLARE_INTERFACE_(IDebugHostPublic, IDebugHostSymbol)
{
STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
}
Tutti questi metodi sono semanticamente equivalenti alle loro controparti in IDebugHostField. L'unica differenza è che il metodo GetLocationKind non restituirà mai LocationMember o LocationConstant per tali simboli.
Il metodo GetLocationKind restituisce il tipo di posizione in cui si trova il simbolo in base all'enumerazione LocationKind. La descrizione di questa enumerazione è disponibile nella documentazione di IDebugHostField.
Per i dati con un indirizzo, il metodo GetLocation restituirà la posizione astratta (indirizzo) del campo. Se il pubblico specificato non ha una posizione statica, il metodo GetLocation avrà esito negativo.
Firme del modulo e corrispondenza delle versioni: IDebugHostModuleSignature
Le firme del modulo rappresentano un mezzo per verificare se un determinato modulo soddisfa un set di criteri relativi alla denominazione e al controllo delle versioni. Viene creata una firma del modulo tramite il metodo CreateModuleSignature in IDebugHostSymbols. Può corrispondere al nome del modulo e a un intervallo facoltativo di numeri di versione per il modulo. Dopo aver creato tale firma, il client riceve un'interfaccia IDebugHostModuleSignature definita come segue:
DECLARE_INTERFACE_(IDebugHostModuleSignature, IUnknown)
{
STDMETHOD(IsMatch)(_In_ IDebugHostModule* pModule, _Out_ bool* isMatch) PURE;
}
Il metodo IsMatch confronta un modulo specifico (come indicato da un simbolo IDebugHostModule) rispetto a una firma, confrontando il nome e la versione con il nome e l'intervallo di versioni indicati nella firma. Indicazione del fatto che il simbolo del modulo specificato corrisponda alla firma.
Firme di tipo e corrispondenza dei tipi: IDebugHostTypeSignature
Le firme di tipo rappresentano un mezzo per verificare se un'istanza di tipo specificata soddisfa un set di criteri relativi al nome del tipo, agli argomenti generici al tipo e al modulo all'interno del tipo. Viene creata una firma di tipo tramite il metodo CreateTypeSignature in IDebugHostSymbols. Dopo aver creato tale firma, il client riceve un'interfaccia IDebugHostTypeSignature definita come segue:
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;
}
Il metodo GetHashCode restituisce un codice hash a 32 bit per la firma del tipo. L'host di debug garantisce che sia presente una sincronizzazione nell'implementazione tra il codice hash restituito per le istanze di tipo e il codice hash restituito per le firme di tipo. Ad eccezione di una corrispondenza globale, se un'istanza di tipo è in grado di corrispondere a una firma di tipo, entrambe avranno lo stesso codice hash a 32 bit. Ciò consente un confronto rapido iniziale e una corrispondenza tra un'istanza di tipo e una pletora di firme di tipo registrate con la gestione modelli di dati.
Il metodo IsMatch restituisce un'indicazione del fatto che un'istanza di tipo specifica corrisponda ai criteri specificati nella firma del tipo. In tal caso, viene restituita un'indicazione di questo oggetto e un enumeratore che indicherà tutte le parti specifiche dell'istanza del tipo (come simboli) corrispondenti ai caratteri jolly nella firma del tipo.
Il metodo CompareAgainst confronta la firma del tipo con un'altra firma di tipo e restituisce il confronto tra le due firme. Il risultato del confronto restituito è un membro dell'enumerazione SignatureComparison definita come segue:
Enumerant | Significato |
---|---|
Unrelated | Non esiste alcuna relazione tra le due firme o i tipi confrontati. |
Ambiguous | Una firma o un tipo confronta in modo ambiguo con l'altra. Per due firme di tipo, ciò significa che esistono istanze di tipo potenziali che potrebbero corrispondere a entrambe le firme altrettanto bene. Ad esempio, le due firme di tipo illustrate di seguito sono ambigue. Firma 1: firma 2: std::pair<*, int> std::pair<int,*> perché l'istanza std::pair<int, int> del tipo corrisponde a una uguale (entrambe hanno una corrispondenza concreta e una corrispondenza con caratteri jolly). |
LessSpecific | Una firma o un tipo è meno specifica dell'altra. Spesso, ciò significa che la firma meno specifica ha un carattere jolly in cui quello più specifico ha un tipo concreto. Ad esempio, la prima firma seguente è meno specifica del secondo. Firma 1: firma 2: std::pair<*, int> std::pair<int, int> perché ha un carattere jolly (il * ) dove il secondo ha un tipo concreto (int). |
MoreSpecific | Una firma o un tipo è più specifico dell'altro. Questo significa spesso che la firma più specifica ha un tipo concreto in cui quello meno specifico ha un carattere jolly. Ad esempio, la prima firma seguente è più specifica del secondo. Firma 1: std::pair<int, int> Firma 2: std::pair<*, int> perché ha un tipo concreto (int) in cui il secondo ha un carattere jolly (il * ). |
Identici | Le due firme o i tipi sono identici. |
Vedere anche
Questo argomento fa parte di una serie che descrive le interfacce accessibili da C++, come usarle per compilare un'estensione del debugger basata su C++ e come usare altri costrutti di modelli di dati (ad esempio JavaScript o NatVis) da un'estensione del modello di dati C++.
Panoramica del modello di dati del debugger C++
Interfacce C++ del modello di dati del debugger
Oggetti C++ del modello di dati del debugger
Interfacce aggiuntive del modello di dati del debugger C++