在 KMDF 和 UMDF 2 驱动程序中使用即时跟踪记录器 (IFR)
从 Windows 10 开始,你可以生成 KMDF 或 UMDF 驱动程序,以便它通过 Windows 软件跟踪预处理获取额外的驱动程序调试信息。 从 KMDF 版本 1.15 和 UMDF 版本 2.15 开始,此功能称为 Inflight 跟踪记录器(IFR)。
飞行跟踪记录器是 WPP 软件跟踪的扩展。 与 WPP 跟踪不同,Inflight 跟踪记录器在不使用附加跟踪使用者的情况下继续工作。 框架将消息写入循环缓冲区,驱动程序还可以添加自己的消息。 每个驱动程序都有自己的日志,因此与驱动程序关联的多个设备共享单个日志。
如果在驱动程序二进制文件中启用 IFR,则在驱动程序的生命周期内,IFR 会始终存在并处于运行状态。 不需启动显式跟踪收集会话。
日志存储在不可分页的内存中,因此在系统崩溃后可恢复这些日志。 此外,在小型转储文件中包括 Inflight Trace Recorder 日志,除非责任驱动程序不确定或崩溃是否为主机超时。
如何启用 Inflight 跟踪记录器并从驱动程序发送消息
在 Microsoft Visual Studio 中,执行以下步骤:
打开驱动程序项目的属性页。 在“解决方案资源管理器”中右键单击驱动程序项目,并选择“属性”。 在驱动程序的属性页中,选择“配置属性”,然后选择“Wpp 跟踪”。 在“常规”菜单上,将“运行 WPP 跟踪”设置为“是”。
导航到 Properties-Wpp 跟踪函数和宏选项,然后选择“启用 WPP 记录器”。>>
在同一菜单上,将扫描配置数据设置为包含跟踪信息的文件,例如 Trace.h。
在每个调用 WPP 宏的源文件中,添加一个标识跟踪消息标头(TMH)文件的 #include 指令。 文件名必须具有 driver-source-file-name.tmh> 的格式。<
例如,如果驱动程序包含两个名为 MyDriver1.c 和 MyDriver2.c 的源文件,则 MyDriver1.c 必须包含:
#include“MyDriver1.tmh”
和 MyDriver2.c 必须包含:
#include“MyDriver2.tmh”
在 Visual Studio 中生成驱动程序时,WPP 预处理器将生成 .tmh 文件。
在头文件中定义WPP_CONTROL_GUIDS宏。 此宏定义驱动程序跟踪消息的 GUID 和 跟踪标志 。
Osrusbfx2 驱动程序示例定义 Trace.h 头文件中的单个控件 GUID 和 7 个跟踪标志,如以下示例所示:
#define WPP_CONTROL_GUIDS \ WPP_DEFINE_CONTROL_GUID(OsrUsbFxTraceGuid, \ (d23a0c5a,d307,4f0e,ae8e,E2A355AD5DAB), \ WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ WPP_DEFINE_BIT(DBG_IOCTL) /* bit 5 = 0x00000020 */ \ WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ )
在此示例中:
- OsrUsbFxTraceGuid 是 {d23a0c5a-d307-4f0e-ae8e-E2A355AD5DAB} GUID 的友好名称。
- 跟踪标志用于区分在驱动程序处理不同类型的 I/O 请求时生成的跟踪消息。
驱动程序(KMDF 和 UMDF 2)必须使用驱动程序对象和注册表路径(通常来自 DriverEntry)为内核模式驱动程序调用WPP_INIT_TRACING:
WPP_INIT_TRACING( DriverObject, RegistryPath );
若要停用跟踪,KMDF 和 UMDF 2 驱动程序都从 EvtCleanupCallback 或 EvtDriverUnload 调用内核模式驱动程序WPP_CLEANUP:
WPP_CLEANUP( WdfDriverWdmGetDriverObject( Driver ));
WPP_CLEANUP宏采用PDRIVER_OBJECT类型的参数,因此,如果驱动程序的 DriverEntry 失败,则可以跳过调用 WdfDriverWdmGetDriverObject,而是使用指向 WDM 驱动程序对象的指针调用WPP_CLEANUP。
由于 UMDF 驱动程序使用这些宏的内核模式签名来初始化和清理跟踪,因此调用看起来与 KMDF 和 UMDF 完全相同。
在驱动程序中使用 DoTraceMessage 宏或自定义版本的宏来创建跟踪消息。
以下示例演示 Osrusbfx2 驱动程序如何在专用于处理读取请求的代码的一部分中使用其 TraceEvents 函数:
if (Length > TEST_BOARD_TRANSFER_BUFFER_SIZE) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Transfer exceeds %d\n", TEST_BOARD_TRANSFER_BUFFER_SIZE); status = STATUS_INVALID_PARAMETER; }
如果跟踪控制器启用TRACE_LEVEL_ERROR级别和DBG_READ跟踪标志,则对 TraceEvents 的调用将生成跟踪消息。 该消息包括驱动程序定义的常量 TEST_BOARD_TRANSFER_BUFFER_SIZE的值。
若要更改驱动程序日志使用的循环缓冲区的大小,请修改 以下注册表位置中的 LogPages 注册表值:
SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\<YourDriver>\Parameters\Wdf
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\<YourDriver>\Parameters\Wdf
这是一个类型 为REG_DWORD 的值,其中包含在页面中分配的日志缓冲区的大小。 有效值介于 0x1 和 0x10 之间。
对于 KMDF 驱动程序
- 通过在调试器中键入 .load rcdrkd.dll 来加载 RCDRKD 命令。
- 使用 !wdfkd.wdfldr 扩展显示有关当前动态绑定到 Windows 驱动程序框架(WDF)的驱动程序的信息。
- 使用 !rcdrkd.rcdrlogdump 和 !rcdrkd.rcdrcrashdump 查看驱动程序提供的消息。
- 使用 !wdfkd.wdflogdump 或 !wdfkd.wdfcrashdump 查看框架提供的消息。
UMDF 驱动程序的实时调试
使用 !wdfkd.wdfldr 扩展显示有关当前动态绑定到 WDF 的驱动程序的信息。 查找用户模式驱动程序。 输入关联的主机进程。
键入 !wdfkd.wdflogdump <YourDriverName.dll><Flag,其中 <Flag>> 为:
- 0x1 – 合并框架和驱动程序日志
- 0x2 – 驱动程序日志
- 0x3 – 框架日志
如果没有指定驱动程序的驱动程序日志,则扩展仅显示框架日志。
在 UMDF 驱动程序崩溃后查看登录跟踪记录器日志
在 WinDbg 中,选择 “文件>打开故障转储”,并指定要调试的小型转储文件。
键入 !wdfkd.wdfcrashdump <YourDriverName.dll><驱动程序主机<>选项的进程 ID,其中 <Option>> 为:
- 0x1 – 合并框架和驱动程序日志
- 0x2 – 驱动程序日志
- 0x3 – 框架日志
如果未指定驱动程序, !wdfcrashdump 将显示所有驱动程序的信息。 如果未指定主机进程,并且只有一个进程,则扩展将使用单个主机进程。 如果未指定主机进程且有多个进程,则扩展会列出活动主机进程。
如果存储在小型转储中的日志信息与输入的名称不匹配,则小型转储不包含驱动程序的日志。
如果没有连接调试器,仍可访问驱动程序和框架日志。 若要了解如何操作,请参阅 视频:在没有调试器的情况下访问驱动程序 IFR 日志。
有关将跟踪消息添加到驱动程序的详细信息,请参阅 向驱动程序添加 WPP 宏。