调试器数据模型 C++ 概述
本主题概述如何使用调试器数据模型 C++ 接口来扩展和自定义调试器的功能。
本主题是一系列文章的一部分,该系列介绍了可从 C++ 访问的接口、如何使用这些接口生成基于 C++ 的调试器扩展,以及如何利用其他数据模型构造 (例如:JavaScript 或 NatVis) 从 C++ 数据模型扩展。
调试器数据模型 C++ 接口概述
调试器数据模型是一种可扩展的对象模型,它能够让新调试器扩展(包括 JavaScript、NatVis 和 C++ 中的扩展)使用来自调试器的信息并生成可从调试器及其他扩展访问的信息。 写入数据模型 API 的构造在调试器的较新 (dx) 表达式计算器以及 JavaScript 扩展或 C++ 扩展中提供。
为了说明调试器数据模型的目标,请考虑此传统调试器命令。
0: kd> !process 0 0
PROCESS ffffe0007e6a7780
SessionId: 1 Cid: 0f68 Peb: 7ff7cfe7a000 ParentCid: 0f34
DirBase: 1f7fb9000 ObjectTable: ffffc001cec82780 HandleCount: 34.
Image: echoapp.exe
...
调试器命令使用二进制掩码,并且它仅以非标准方式提供文本输出。 文本输出难以使用、格式化或扩展,并且布局特定于此命令。
将此与调试器数据模型 dx (显示调试器对象模型表达式) 命令进行对比。
dx @$cursession.Processes.Where(p => p.Threads.Count() > 5)
此命令使用可发现、可扩展且可组合的统一方式的标准数据模型。
从逻辑上讲,名称间距和扩展特定对象允许发现调试器扩展功能。
提示
因为数据模型 C++ 对象接口可以非常详细,以便为使用完整 C++ 异常的数据模型实现完整的 C++ 帮助程序库,建议使用模板编程范例。 有关详细信息,请参阅本主题后面的 使用 DbgModelClientEx 库 。
数据模型是 WinDbg 显示大多数内容的方式。 新 UI 中的许多元素可以查询、扩展或编写脚本,因为它们由数据模型提供支持。 有关详细信息,请参阅 WinDbg - 数据模型。
数据模型体系结构视图
下图汇总了调试器数据模型体系结构的主要元素。
- 左侧显示了 UI 元素,这些元素提供对对象的访问并支持 LINQ 查询等功能。
- 关系图右侧是向调试器数据模型提供数据的组件。 这包括自定义 NatVis、JavaScript 和 C++ 调试器数据模型扩展。
对象模型
调试器数据模型的中心是一个统一的对象表示形式,其中所有内容都是 IModelObject 接口的实例。 虽然此类对象可能表示内部 (例如:整数值) 或其他数据模型接口,但它通常表示一个动态对象 - 一个键/值/元数据元组字典和一组描述抽象行为的概念。
此图显示了 IModelObject 如何使用密钥存储来包含提供程序可以创建、注册和操作的值。
- 它显示了一个提供程序,该 提供程序向对象模型提供信息
- 左侧显示 IModelObject,即用于操作对象的通用对象模型。
- 中心是用于存储和访问值的 密钥存储 。
- 底部显示支持具有功能(例如转换为可显示字符串或编制索引)的对象 的概念 。
数据模型:使用者视图
下图显示了数据模型的使用者视图。 在此示例中, dx (Display Debugger Object Model Expression) 命令用于查询信息。
- Dx 命令通过序列化程序与对象枚举接口通信。
- IDebugHost* 对象用于从调试器引擎收集信息。
- 表达式和语义计算器用于将请求发送到调试器引擎。
数据模型:生成者视图
此图显示了数据模型的生成者视图。
- 左侧显示了一个 NatVis 提供程序,该提供程序使用定义其他功能的 XML。
- JavaScript 提供程序可以利用 动态提供程序概念 来实时操作信息。
- 底部显示了本机代码提供程序,该提供程序还可以定义其他功能。
数据模型管理器
此图显示了数据模型管理器在对象管理中的核心作用。
- 数据模型管理器充当所有对象的中心注册器。
- 左侧显示了会话和进程等标准调试器元素的注册方式。
- 命名空间块显示中心注册列表。
- 图的右侧显示了两个提供程序,一个提供程序用于顶部的 NatVis,底部为 C/C++ 扩展。
调试器数据模型接口摘要
有许多 C++ 接口构成数据模型的不同部分。 为了以一致且简单的方式处理这些接口,它们按常规类别进行细分。 此处main区域:
常规对象模型
第一组也是最重要的接口定义如何访问核心数据模型以及如何访问和操作对象。 IModelObject 是表示数据模型中每个对象的接口, (非常类似于 C# 的对象) 。 这是数据模型的使用者和生成者感兴趣的main接口。 其他接口是用于访问对象不同方面的机制。 为此类别定义了以下接口:
DbgEng 和数据模型之间的桥梁
主接口
IModelKeyReference / IModelKeyReference2
概念接口
IDynamicConceptProviderConcept
管理数据模型和扩展性
数据模型管理器是管理所有扩展性发生方式的核心组件。 它是一组表的中心存储库,用于将本机类型映射到扩展点,并将合成构造映射到扩展点。 此外,它是一个实体,负责对象的装箱 (序号值或字符串转换为 IModelObject 的) 。
为此类别定义了以下接口:
常规数据模型管理器访问权限
IDataModelManager / IDataModelManager2
脚本管理
IDataModelScriptProviderEnumerator
访问调试器的类型系统和内存空间
详细公开了调试器的基础类型系统和内存空间,以供扩展使用。 为此类别定义了以下接口:
常规主机 (调试器) 接口
IDebugHostMemory / IDebugHostMemory2
IDebugHostEvaluator / IDebugHostEvaluator2
主机 (调试器) 类型系统接口
IDebugHostSymbol / IDebugHostSymbol2
IDebugHostType / IDebugHostType2
IDebugHostBaseClassIDebugHostPublic
主机 (调试器) 脚本支持
创作和使用脚本
数据模型还对什么是脚本以及如何调试脚本有一个常规概念。 调试器扩展完全有可能在数据模型和另一种动态语言之间定义一个通用桥, (通常是脚本环境) 。 这组接口是实现的,也是调试器 UI 利用此类脚本的方式。
为此类别定义了以下接口:
常规脚本接口
IDataModelScriptTemplateEnumerator
脚本调试器接口
IDataModelScriptDebugStackFrame
IDataModelScriptDebugVariableSetEnumerator
IDataModelScriptDebugBreakpoint
IDataModelScriptDebugBreakpointEnumerator
使用 DbgModelClientEx 库
概述
数据模型 C++ 对象接口可以非常详细地实现。 虽然它们允许对数据模型进行完全操作,但它们需要实现多个小接口来扩展数据模型 (例如:每个动态可提取属性的 IModelPropertyAccessor 实现) 。 除此之外,基于 HRESULT 的编程模型增加了大量用于错误检查的锅炉板代码。
为了最大程度地减少其中的某些工作,有一个完整的 C++ 帮助程序库用于数据模型,该库使用完整的 C++ 异常和模板编程范例。 使用此库可以在使用或扩展数据模型时提供更简洁的代码,建议使用此库。
帮助程序库中有两个重要的命名空间:
Debugger::D ataModel::ClientEx - 使用数据模型的帮助程序
Debugger::D ataModel::P roviderEx - 数据模型扩展的帮助程序
有关使用 DbgModelClientEx 库的其他信息,请参阅此 github 站点上的自述文件:
https://github.com/Microsoft/WinDbg-Libraries/tree/master/DbgModelCppLib
HelloWorld C++ 示例
若要查看 DbgModelClientEx 库的使用方式,请查看此处的数据模型 HelloWorld C++ 示例。
https://github.com/Microsoft/WinDbg-Samples/tree/master/DataModelHelloWorld
该示例包括:
HelloProvider.cpp - 这是提供程序类的实现,该提供程序类将新的示例属性“Hello”添加到调试器的进程概念中。
SimpleIntroExtension.cpp - 这是一个简单的调试器扩展,它将新的示例属性“Hello”添加到调试器的进程概念中。 此扩展是针对数据模型 C++17 帮助程序库编写的。 更可取的是针对此库而不是原始 COM ABI 编写扩展,因为需要粘附代码的体积 (和复杂性) 。
JavaScript 和 COM 示例
为了更好地了解使用数据模型编写调试器扩展的不同方法,此处提供了三个版本的数据模型 HelloWorld 扩展:
https://github.com/Microsoft/WinDbg-Samples/tree/master/DataModelHelloWorld
JavaScript - 用 JavaScript 编写的版本
C++17 - 针对数据模型 C++17 客户端库编写的版本
COM - 针对原始 COM ABI 编写的版本 (仅使用 WRL for COM 帮助程序)