Debugger Data Model C++ Overview

This topic provides an overview of how to use Debugger Data Model C++ Interfaces to extend and customize the capabilities of the debugger.

This topic is part of a series which describes the interfaces accessible from C++, how to use them to build a C++ based debugger extension, and how to make use of other data model constructs (e.g.: JavaScript or NatVis) from a C++ data model extension.

Debugger Data Model C++ Overview

Debugger Data Model C++ Interfaces

Debugger Data Model C++ Objects

Debugger Data Model C++ Additional Interfaces

Debugger Data Model C++ Concepts

Debugger Data Model C++ Scripting


Overview of the Debugger Data Model C++ Interface

The debugger data model is an extensible object model that is central to the way in which new debugger extensions (including those in JavaScript, NatVis, and C++) both consume information from the debugger and produce information that can be accessed from the debugger as well as other extensions. Constructs which are written to the data model APIs are available in the debugger's newer (dx) expression evaluator as well as from JavaScript extensions or C++ extensions.

To illustrate the goals of the debugger data model, consider this traditional debugger command.

0: kd> !process 0 0 
PROCESS ffffe0007e6a7780
    SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
    DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
    Image: echoapp.exe
...

The debugger command is using a binary mask and it provides text only output in non-standard ways. The text output is difficult to consume, format, or extend and the layout is specific to this command.

Contrast this to the debugger data model dx (Display Debugger Object Model Expression) command.

dx @$cursession.Processes.Where(p => p.Threads.Count() > 5)

This command uses a standard data model that is discoverable, extensible and composable in uniform ways.

Logically name spacing things and extending on specific objects allows for the discovery of debugger extension functionality.

Tip

Because the Data Model C++ Object interfaces can be very verbose to implement a full C++ helper library for the data model which uses a full C++ exception and template programming paradigm is recommended. For more information, see Using the DbgModelClientEx Library later in this topic.

The data model is the way that WinDbg, shows most things. Many elements in the new UI can be queried, extended, or scripted, because they are powered by the data model. For more information, see WinDbg - Data Model.

Screenshot of data model explore window displaying process and threads.

Data Model Architectural View

The following diagram summarizes the major elements of the debugger data model architecture.

  • To the left side, UI elements are shown that provide access to the objects and support such functionality as LINQ queries.
  • On the right side of the diagram are components that provide data to debugger data model. This includes custom NatVis, JavaScript and C++ debugger data model extensions.

Diagram that shows data model architecture with common object model in the center and providers on the right.

Object Model

At the center of the Debugger Data Model is a uniform object representation in which everything is an instance of the IModelObject interface. While such an object may represent an intrinsic (e.g.: an integer value) or another data model interface, it often represents a dynamic object – a dictionary of key/value/metadata tuples and a set of concepts which describe abstract behaviors.

This diagram shows how the IModelObject uses Key Stores to contain values that a provider can create, register and manipulate.

  • It shows a provider, that provides information to the object model
  • On the left it shows the IModelObject, that is the common object model that is used to manipulate objects.
  • In the center is the Key Store that is used to store and access values.
  • At the bottom it shows Concepts that support objects with functionality such as the ability to convert to a displayable string or be indexed.

Diagram that shows data model architecture with IModelObject as input and a tuples key store.

The Data Model: A Consumer View

The next diagram shows a consumer view of the data model. In the example the dx (Display Debugger Object Model Expression) command is being used to query information.

  • The Dx command communicates through a serializer to the object enumeration interface.
  • IDebugHost* objects are used to gather information from the debugger engine.
  • Expression and semantic evaluators are used to send the request to the debugger engine.

Diagram that shows data model architecture with UI feeding into evaluators that connect to IDebugHost.

The Data Model: A Producer View

This diagram shows a producer view of the data model.

  • A NatVis provider is shown on the left that consumes XML that defines additional functionality.
  • A JavaScript provider can take advantage of Dynamic Provider Concepts to manipulate information in real time.
  • The bottom shows a native code provider that can also define additional functionality.

Diagram that shows data model architecture with IModelObject connected to NatVis, JavaScript, and Native code consumers.

Data Model Manager

This diagram shows the central role that the data model manager plays in the management of objects.

  • The Data Model Manager acts as a central registrar for all objects.
  • On the left it shows how standard debugger elements such as sessions and process are registered.
  • The namespace block shows the central registration list.
  • The right side of the diagram shows two providers, one for NatVis on the top, and a C/C++ extension on the bottom.

Diagram that shows data model architecture with registered names being accessed by the data model manager.

Summary of Debugger Data Model Interfaces

There are a multitude of C++ interfaces which comprise different pieces of the data model. In order to approach these interfaces in a consistent and easy manner, they are broken down by general category. The main areas here:

The General Object Model

The first and most important set of interfaces define how to get access to the core data model and how to access and manipulate objects. IModelObject is the interface which represents every object in the data model (much like C#'s object). This is the main interface of interest for both consumers of and producers to the data model. The other interfaces are mechanisms for accessing different aspects of objects. The following interfaces are defined for this category:

Bridges Between DbgEng and the Data Model

IHostDataModelAccess

Main Interfaces

IModelObject

IKeyStore

IModelIterator

IModelPropertyAccessor

IModelMethod

IKeyEnumerator

IRawEnumerator

IModelKeyReference / IModelKeyReference2

Concept Interfaces

IStringDisplayableConcept

IIterableConcept

IIndexableConcept

IPreferredRuntimeTypeConcept

IDataModelConcept

IDynamicKeyProviderConcept

IDynamicConceptProviderConcept

Management of Data Models and Extensibility

The Data Model Manager is the core component which manages how all extensibility occurs. It is the central repository of a set of tables which map both native types to extension points as well as synthetic constructs to extension points. In addition, it is the entity which is responsible for the boxing of objects (conversion of ordinal values or strings into IModelObject's).

The following interfaces are defined for this category:

General Data Model Manager Access

IDataModelManager / IDataModelManager2

Script Management

IDataModelScriptManager

IDataModelScriptProviderEnumerator

Access to the Debugger's Type System and Memory Spaces

The underlying type system and memory spaces of the debugger are exposed in detail for extensions to make use of. The following interfaces are defined for this category:

General Host (Debugger) Interfaces

IDebugHost

IDebugHostStatus

IDebugHostContext

IDebugHostMemory / IDebugHostMemory2

IDebugHostErrorSink

IDebugHostEvaluator / IDebugHostEvaluator2

IDebugHostExtensibility

Host (Debugger) Type System Interfaces

IDebugHostSymbols

IDebugHostSymbol / IDebugHostSymbol2

IDebugHostModule

IDebugHostType / IDebugHostType2

IDebugHostConstant

IDebugHostField

IDebugHostData

IDebugHostBaseClass IDebugHostPublic

IDebugHostModuleSignature

IDebugHostTypeSignature

Host (Debugger) Support for Scripting

IDebugHostScriptHost

Authoring and Consuming Scripts

The Data Model also has a general notion of what a script is and how to debug one. It is entirely possible for a debugger extension to come along and define a general bridge between the data model and another dynamic language (usually a scripting environment). This set of interfaces is how that is accomplished as well as how a debugger UI can make use of such scripts.

The following interfaces are defined for this category:

General Script Interfaces

IDataModelScriptProvider

IDataModelScript

IDataModelScriptClient

IDataModelScriptHostContext

IDataModelScriptTemplate

IDataModelScriptTemplateEnumerator

IDataModelNameBinder

Script Debugger Interfaces

IDataModelScriptDebug

IDataModelScriptDebugClient

IDataModelScriptDebugStack

IDataModelScriptDebugStackFrame

IDataModelScriptDebugVariableSetEnumerator

IDataModelScriptDebugBreakpoint

IDataModelScriptDebugBreakpointEnumerator

Using the DbgModelClientEx Library

Overview

The Data Model C++ Object Interfaces to the data model can be very verbose to implement. While they allow for full manipulation of the data model, they require implementation of a number of small interfaces to extend the data model (e.g.: an IModelPropertyAccessor implementation for each dynamic fetchable property which is added). In addition to this, the HRESULT based programming model adds a significant amount of boiler plate code that is used for error checking.

In order to minimize some of this work, there is a full C++ helper library for the data model which uses a full C++ exception and template programming paradigm. Use of this library allows for more concise code when consuming or extending the data model and is recommended.

There are two important namespaces in the helper library:

Debugger::DataModel::ClientEx - helpers for consumption of the data model

Debugger::DataModel::ProviderEx - helpers for extension of the data model

For additional information on using the DbgModelClientEx library, see the readme file at this github site:

https://github.com/Microsoft/WinDbg-Libraries/tree/master/DbgModelCppLib

HelloWorld C++ Sample

To see how the DbgModelClientEx library can be used, review the Data Model HelloWorld C++ sample here.

https://github.com/Microsoft/WinDbg-Samples/tree/master/DataModelHelloWorld

The sample includes:

  • HelloProvider.cpp - This is an implementation of a provider class which adds a new example property "Hello" to the debugger's notion of a process.

  • SimpleIntroExtension.cpp - This is a simple debugger extension which adds a new example property "Hello" to the debugger's notion of a process. This extension is written against the Data Model C++17 Helper Library. It is far preferable to write extensions against this library rather than the raw COM ABI due to the volume (and complexity) of glue code which is required.

JavaScript and COM Samples

In order to better understand the varying ways to write a debugger extension with the data model, there are three versions of the data model HelloWorld extension available here:

https://github.com/Microsoft/WinDbg-Samples/tree/master/DataModelHelloWorld

  • JavaScript - A version written in JavaScript

  • C++17 - A version written against the Data Model C++17 Client Library

  • COM - A version written against the raw COM ABI (only using WRL for COM helpers)


See also

Debugger Data Model C++ Interfaces

Debugger Data Model C++ Objects

Debugger Data Model C++ Additional Interfaces

Debugger Data Model C++ Concepts

Debugger Data Model C++ Scripting