在 WDF 中调试电源参考漏孔

当 Windows 驱动程序框架 (WDF) 驱动程序调用 WdfDeviceStopIdle 时,框架会递增设备的电源引用计数。 每次成功调用 WdfDeviceStopIdle 都必须通过调用 WdfDeviceResumeIdle 进行匹配,以递减电源引用计数。

从 Kernel-Mode Driver Framework (KMDF) 1.15 和 User-Mode Driver Framework (UMDF) 2.15 开始,可以使用 !wdfkd.wdfdevice!wdfkd.wdftagtracker 调试器 扩展监视电源参考使用情况。 默认情况下,由于性能原因,此功能处于禁用状态,因此你需要使用 WdfVerifier 应用程序或通过手动编辑驱动程序的服务密钥将其打开。

WdfVerifier

打开驱动程序的设置列表,然后右键单击 TrackPower 设置。 选择适合你的方案的选项。

提示 避免在性能关键代码路径中捕获堆栈跟踪。

在 WdfVerifier 中设置跟踪电源引用的屏幕截图。

编辑注册表

还可以通过编辑驱动程序的服务密钥来启用验证程序支持和电源参考跟踪。

对于 KMDF 驱动程序:

HKLM\SYSTEM\ControlSet001\Services\<Driver Service Name>\Parameters\Wdf

对于 UMDF 驱动程序:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\WUDF\Services\<Driver Service Name>\Parameters\Wdf

(REG_DWORD) VerifierOn = 0x1
(REG_DWORD) TrackPower = 0x0 (disabled)
                       = 0x1 (capture tick count, file name, line number)
                       = 0x2 (capture tick count, file name, line number, and stack traces)

驱动程序代码

驱动程序调用 WdfDeviceStopIdleWdfDeviceResumeIdle 来管理设备的工作电源状态,如下所示:

//
// Take power reference
//
status = WdfDeviceStopIdle(device, FALSE);
if (NT_SUCCESS(status)) {
    //
    // Release power reference
    //
    WdfDeviceResumeIdle(device);
}

使用 WdfKd 进行调试

若要显示设备上采用的电源引用,以及显示引用历史记录的标记跟踪器,请使用带有详细标志的 !wdfkd.wdfdevice

kd> !wdfkd.wdfdevice 0x6d939790 ff
Power references: 0 !wdftagtracker 0x9ea030a8

调用 !wdfkd.wdftagtracker 会显示设备的电源参考历史记录:

kd> !wdftagtracker 0x9ea030a8
Reference and Release History:
# (showing most recent first; refcount is approximate in multi-threaded scenarios)

## 3 entries, history depth is 25

(--) 0 ref: Tag '....' at Time 0x1331e ticks
##      path\to\your\driver\code.c @ 374

(++) 1 refs: Tag '....' at Time 0x1331e ticks
##      path\to\your\driver\code.c @ 372

(++) Initial Tag '....' at Time 0x12c9a ticks

指定标记

(可选)指定标记名称,以便于识别特定电源引用。 为此,请使用 WdfDeviceStopIdleWithTagWdfDeviceResumeIdleWithTag

status = WdfDeviceStopIdleWithTag(device, FALSE, (PVOID)'oyeH');
if (NT_SUCCESS(status)) {
    WdfDeviceResumeIdleWithTag(device, (PVOID)'oyeH');
}

相应的 !wdftagtracker 示例输出:

(--) 0 ref: Tag 'Heyo' at Time 0x24e40 ticks
##      path\to\your\driver\code.c @ 374

(++) 1 refs: Tag 'Heyo' at Time 0x24e40 ticks
##      path\to\your\driver\code.c @ 372

(++) Initial Tag '....' at Time 0x12c9a ticks