在Windows 2000下如何使用驱动程序校验器来调试设备驱动程序

摘要

Windows 2000中的驱动程序校验器包可以提升稳定性和可靠性,并且你能够使用这个工具来调试驱动程序问题。在Windows 2000中,内核模式部件能够导致系统崩溃或者系统故障,结果错误的写入驱动程序,例如一个Windows 驱动程序模型(WDM)驱动程序的早期版本。这篇文章阐述了如何使用驱动程序校验器来隔离并调试系统中的一个驱动程序。

你可以通过添加一个注册表项,然后重新启动你的计算机来使用驱动程序校验器。你不需要为了开始分析你的系统的驱动程序而做任何其他的改变。注意:你可以在Windows 2000的零售和已检查两个版本来激活驱动程序校验器。驱动程序校验器提供下面的性能(你可以在注册表中激活或者禁用这些性能)。缓冲池分配尝试从特殊的缓冲池去分配一个驱动程序的全部缓冲池。这个驱动程序的分配被隔离并且受No Access权限的约束,而且不和其它系统共享缓冲池分配。此性能决定一个驱动程序是否能够分配比共享缓冲池更多的资源,从而导致崩溃和系统的不稳定。当你激活这个性能并且目标计算机有足够的物理和虚拟内存的时候,所有驱动程序的分配是自动地重新定向到特殊的缓冲池。

提供Extreme Memory Pressure

Extreme Memory Pressure在一个特定的驱动器上设置,而不会影响其它驱动器(不管系统内存的大小)。你能够通过指示内存管理的方法使所有驱动程序的可调页代码和数据以及系统的可调页缓冲池、代码和数据无效。这让你发现一个驱动器,它错误地保持自旋锁或者提高IRQL然后可以访问可调页的代码或者数据。你能够使用Extreme Memory Pressure来探测间歇性问题并且隔离问题。参数验证所有的自旋锁、IRQL和驱动器所作的缓冲池分配调用自动地接收到参数确认。这就意味着做校验可以确保下面情况的安全:

  • 一个提高的IRQL实际上是一个提高的IRQL(当前的IRQL低于目的IRQL)。
  • 一个较低的IRQL是一个较低的IRQL。
  • 一个自旋锁的加倍释放。

自旋锁的采集/释放以适当执行IRQL。页式缓冲池分配/释放以适当地执行IRQL(APC_LEVEL 及其以下)非页式缓冲池分配/释放以恰当地执行IRQL(DISPATCH_LEVEL及其以下)。对于这些应用程序接口 (API)不会指定随机(未初始化的)值。缓冲池分配注入失败(Pool Allocation Injection Failures)为被驱动程序标记为MUST_SUCCEED缓冲池分配可能会随机地失效,从而不能正确地处理内存较少的情况。

被释放的缓冲池

检查所有被释放的缓冲池可以保证清除缓冲池内部所有未到时的计时器,这些情况将引起非常难跟踪的系统崩溃。

缓冲池泄漏检测

所有的驱动器缓冲池分配被自动跟踪。在驱动器卸载的时候,如果有分配没有被释放,那么将开始一个bug检查。然后你可以使用!verifier 3内核调试器命令来显示所有未被释放的分配。你也可以在卸载之前使用这个命令来及时地查看驱动器所拥有的明显地址分配。

驱动器的卸载检测

执行驱动程序的卸载检测来捕捉卸载的驱动程序,并且清除所用的资源(在驱动程序卸载不久以后,它增加了一个系统bug检测的可能性)。驱动程序没有删除的资源包括后备列表、延迟的过程调用 (DPC)、工作线程、队列、时钟和其它资源。输入输出校验器如果你用校验器工具或者VerifyDriverLevel 注册表键打开输入输出校验器标志,那么一些输入输出管理器验证被打开。这包括以下几项:

  • 所有通过IoAllocateIrp分配的IRPS自特殊的缓冲池分配。
  • 在IoCallDriver,IoCompleteRequest和IoFreeIrp中作检查可以得到驱动程序的错误信息。
  • 利用代码DRIVER_VERIFIER_IOMANAGER_VIOLATION (0xC9)对所有输入输出校验器失效进行检查驱动程序校验器的要求唯一的要求就是你必须安装了Windows 2000。

Enabling Driver Verifier(激活驱动程序校验器)

你可以使用Verifier.exe或者通过编辑注册表来激活驱动程序校验器。使用Verifier.exe这是激活驱动程序校验器的首选方法(Verifier.exe存在于Windows2000的每一个拷贝中,并且可以安装到System32文件夹中)。Verifier.exe有命令行和图形用户界面(GUI)界面,因此你可以指定驱动程序并且适当地认证等级。你也可以注意驱动程序校验器的即时统计表。为了获得其它的信息,请参考本文章的"驱动程序校验管理器"部分。

编辑注册表

警告:错误的使用注册表编辑器能够导致严重的问题,这些问题可能需要你重新安装你的操作系统。微软不能保证来自错误使用注册表编辑器的所有问题都被解决。使用注册表编辑器有一定的冒险性。关于如何编辑注册表的信息,可以查看注册表(Regedit.exe)中的"Changing Keys and Values"帮助主题或者Regedt32.exe 中的"Add and Delete Information in the Registry" 和 "Edit Registry Data"帮助主题。注意你应该在你编辑注册表之前,备份你的注册表。如果你正在运行Windows NT或者 Windows 2000,你也应该升级你的应急修复磁盘 (ERD)。通过编辑注册表来激活驱动程序校验器可以参照以下步骤:

  • 打开注册表编辑器(Regedt32)
  • 找到下面的注册表键: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\VerifyDrivers
    编辑REG_SZ键。设置REG_SZ键为你想测试的驱动程序的大小写敏感的名称。你可以指定多个驱动程序,但是你应该使用一个驱动程序来保证可用的系统资源不被过早的耗尽。太早的耗尽资源不是系统不稳定问题所造成的,但是可以引起一些驱动程序测试被绕过。

下面列表是一个REG_SZ键值的例子:

Ntfs.sys
Win32k.sys ftdisk.sys
*.sys

你可以在下面的注册表键中指定驱动程序验证的等级。HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\Memory Management\VerifyDriverLevel下面列表显示这个键的位类型的域值(这些标志可以相或使用):

  • 0x01:试图满足特殊缓冲池的所有分配。
  • 0x02:关于访问页式代码和数据,把内存压力应用到这个驱动程序来使IRQL使用有效。
  • 0x04:各种缓冲池分配请求随机失败。在系统启动并且到达一个把问题当作合理情况的位点之后,这种行为是可行的。
  • 0x08:激活缓冲池分配跟踪。每一个分配必须在驱动程序卸载或者系统执行一个bug检查之前被释放。
  • 0x10:激活输入输出校验器。

注意:如果此键不存在或者你没有指定一个驱动程序确认的等级,那么默认值是3。调试驱动程序校验器异常情况内核器中的!verifier命令和Verifier.exe工具显示当前的驱动程序校验器配置和即时统计表。所有驱动程序校验器异常将导致bug 检查,最通常的几个(虽然不是所有都是必要的)如下:

IRQL_NOT_LESS_OR_EQUAL 0xA
PAGE_FAULT_IN_NONPAGED_AREA 0x50
PAGE_FAULT_IN_NONPAGED_AREA 0x50 ATTEMPTED_WRITE_TO_READONLY_MEMORY 0xBE
SPECIAL_POOL_DETECTED_MEMORY_CORRUPTION 0xC1
DRIVER_VERIFIER_DETECTED_VIOLATION 0xC4 DRIVER_CAUGHT_MODIFYING_FREED_POOL
0xC6 TIMER_OR_DPC_INVALID 0xC7 DRIVER_VERIFIER_IOMANAGER_VIOLATION 0xC9

驱动程序校验器和图形驱动程序

Windows 2000 内核模式图形驱动程序(例如打印机和显示器驱动程序DLLs)不能直接的调用缓冲池入口点,相反,缓冲池分配通过使用图形设备驱动程序接口(DDI)回调Win32k.sys间接的进行。例如,EngAllocMem是一个图形驱动程序显式地调用来分配缓冲池内存的回调函数。同样,其它特定的回调函数,如EngCreatePalette 和 EngCreateBitmap,返回缓冲池内存。为了给图象驱动程序提供相同种类的自动测试,对于一些驱动程序校验器功能的支持是和Win32k.sys合成一体的。可是因为图形驱动程序与其他kernel模式的驱动程序相比受限制程度更强,所以它们需要一个驱动程序校验器功能性的子集。很显然,IRQL检查和输入输出确认是不需要的。其它的功能性,即运用特殊的缓冲池,缓冲池分配的随机失败和缓冲池跟踪,被支持来改变在不同图形DDI回调信息的位置。提供对随机失效地支持,以用于下列图形DDI回调函数:

EngAllocMem
EngAllocUserMem
EngCreateBitmap
EngCreateDeviceSurface
EngCreateDeviceBitmap
EngCreatePalette
EngCreateClip
EngCreatePath
EngCreateWnd
EngCreateDriverObj
BRUSHOBJ_pvAllocRbrush
CLIPOBJ_ppoGetPath

此外,特殊缓冲池使用和缓冲池跟踪被支持来适合于EngAllocMem。为图形驱动程序激活驱动程序校验器是和其它的驱动程序一样的(为得到其它的信息,请参考本文章的"激活驱动程序校验器"部分)。例如IRQL检查的不支持的标志被忽略。此外,你可以使用gdikdx.verifier kernel调试器命令来检测图形驱动程序的当前驱动程序校验器状态和缓冲踪迹。

注意:你应该为全面测试而使用随机分配失败设置。这个设置的使用导致错误信息,因此你不应该通过确认测试来使用这个设置去检查图形驱动程序的执行的正确性(例如,通过把图形驱动程序输出比作一个参考图象)。

驱动程序校验管理器(Verifier.exe)
驱动程序校验管理器工具(Verifier.exe)是创建和修改驱动程序校验器设置。并且可以收集驱动程序校验器统计表的首选方法。在每一个Windows 2000 安装的过程中,Verifier.exe被定位于%WinDir%\System32文件夹。

驱动程序状态

驱动程序状态属性页为你提供一幅当前驱动程序校验器状态的图象。你能够看到什么驱动程序被探测。状态可能是下面所述之一:

  • Loaded:驱动程序现在被载入和检验。
  • Unloaded:驱动程序现在没有被载入,但是它由于你重新启动计算机而至少被载入一次。
  • Never Loaded:驱动程序从来都不载入。这个状态能够说明驱动程序的图象文件被破坏或者你指定了一个从系统中丢失了的名字。

你可以点击表头来按照驱动程序名字或者状态来重排分类。在对话框上部靠右的区域,你能够查看确认的当前类型。如果你没有转换到手工更新模式,那么驱动程序状态会被自动升级。你可以使用对话框下部靠左区域的radio按钮来修改更新速度。你也能够点击Update Now来强制实行状态升级。如果你激活特殊缓冲池标志并且至少95%的缓冲池分配进入特殊缓冲池,那么一个警告信息将出现在这页中。这意味着你需要选择较小的一套驱动程序来检验或者添加更多的物理内存到计算机,这样可以获得更好的缓冲池分配确认覆盖率。

全局计数器

全局计数器属性页显示一些由驱动程序校验器维持的计数器当前值。对于一个计数器的一个零值可能说明相关的驱动程序校验器标志没有被激活。例如,对于Other/Faults计数器一个0值说明低资源模拟标志没有被激活。你可以监测校验器的活动,因为计数器的值被自动升级(默认方式)。你能够改变更新速度,切换到手动更新或者用对话框下部靠左区域的一组控件来强制更新。

缓冲池跟踪

这个属性页显示由驱动程序校验器收集的更多的统计表。出现在此页的所有计数器与校验器的缓冲池跟踪标志相关。它们大多是特定于一个驱动程序的计数器(例如,当前的分配、当前的分配字节等等)。这意味着你必须从复合框中选择一个驱动程序名字来查看那个特殊驱动程序的计数器。

设置

你能够设置此页来创建和修改驱动程序校验器设置。此设置被存储在注册表里,然后你必须重新启动计算机才能使这个设置有效。你可以使用此列表来查看当前安装的驱动程序。每一个驱动程序可能是下面所述状态之一:

  • Verify Enabled:驱动程序现在被校验。
  • Verify Disabled:驱动程序现在没有被校验。
  • Verify Enabled (Reboot Needed):仅当下次重新启动之后,此驱动程序才被校验。
  • Verify Disabled (Reboot Needed):驱动程序当前被校验,但是在重新启动之后不被校验。

你可以从列表中选择一个或者几个驱动程序,并且使用表下面的两个按钮可以转换状态。你也可以右击一个驱动程序名称来显示内容菜单,它让你执行状态切换。在对话框的底部,你能够指定额外的下次重新启动你想校验的驱动程序(由空格来分隔)。当你想安装一个新的没有载入的驱动程序的时候,你使用这个编辑控制。如果在列表上部的radio按钮组被设置为校验所有驱动程序,那么列表与校验和不校验按钮以及编辑控制是不可用的。这意味着在下次重新启动之后,系统中的所有驱动程序被校验。你能够使用对话框上部靠右区域的检查框来设置校验类型。你能够激活输入输出校验的一级或者二级校验。二级校验比一级校验更强烈。你必须通过点击应用来存储设置的改变。在此页中还有两个按钮:

Preferred Settings:这项选择一些常用的设置(借助所有的校验的驱动程序)。
Reset All:这项清除所有的驱动程序校验器设置,以至于没有驱动程序被校验。

在你点击应用之后,你必须重新启动计算机使改变有效。

易失设置

你能够使用这个属性页来直接改变驱动程序校验器标志。你可以切换驱动程序校验器标志的一些状态,并且你不能够改变正在被校验的列表。在你改变了检查框中一些状态之后,你必须点击应用使改变有效。改变立刻有效后,它们会一直保持下去,直到你做了额外的改变或者直到你重新启动计算机。你也可以从命令行运行Apply(若想得到更多的信息,请在命令提示符下键入verifier.exe /?)。下面的列表显示最常用的命令行标记:

给驱动程序校验器和输入输出校验等级标记指定一个十进制的数值(若想获得更多的信息,请在命令提示符下键入verifier.exe /?或者参考本文章的"激活驱动程序校验器"部分)。用下面校验位值之一来代替value参数。

0 - Special pool checking
1 - Force IRQL checking
2 - Low resources simulation
3 - Pool tracking
4 - I/O verification

例如,键入下面的命令:
c:\verifier /flags 3 /iolevel 2
注意:输入输出校验得默认等级是1。如果输入输出校验位值没有在标记处设置,那么此值被忽略。

verifier.exe /all
校验系统中的所有驱动程序。

verifier.exe /volatile /flags value
立即改变校验器标记。

verifier.exe /reset
擦掉所有当前驱动程序校验器设置。

verifier /query
清除当前驱动程序校验器状态和计数器为标准输出。

verifier.exe /log LOG_FILE_NAME [/interval seconds]
记录驱动程序校验器状态和计数器到一个日志文件(在那里seconds是你以前指定的时间)。