使用内核调试程序 (KD) 调试设备安装

从 Windows Vista 开始,当即插即用 (PnP) 管理器检测到系统中的新设备时,操作系统将启动设备安装主机进程, (DrvInst.exe) 来搜索和安装设备的驱动程序。

由于设备安装发生在此用户模式进程中,因此通常最简单的方法是使用用户模式调试器,如 使用用户模式调试器调试设备安装中所述。 但在某些情况下,使用内核调试器 (KD) 监视用户模式设备安装过程可能会有所帮助。

例如,通过在调试用户模式设备安装时使用 KD,可以执行以下操作:

  • 使用 !devnode、!devobj、!drvobj、!irp 和其他 KD 扩展同时调试内核模式问题。

  • 使用 KD 扩展 !process 或 .process /p 监视其他用户模式进程,而无需管理多个调试器。

有关 KD 和其他调试工具的详细信息,请参阅 Windows 调试

DebugInstall 注册表值指定在系统上启用的设备安装调试支持的类型。 有关此注册表值的详细信息,请参阅 启用对调试设备安装的支持

DebugInstall 注册表值设置为 1 时, DrvInst.exe将首先检查内核调试器在中断到调试器之前已启用且当前已附加。 进行此中断后,可以在当前进程的用户模式模块中设置断点。 例如:

kd> .reload /user
kd> bp /p @$proc setupapi!SetupDiCallClassInstaller

这会在例程 SETUPAPI 上设置断点!SetupDiCallClassInstaller 仅适用于当前进程。

对于 驱动程序包的开发人员,通常最需要调试类安装程序或辅助安装程序 DLL 在安装设备期间的操作。 但是,当 DrvInst.exe 中断调试器时,驱动程序包中的任何类安装程序或辅助安装程序 DLL 都不会加载。 尽管用户模式调试器支持在使用“sx e ld”命令将用户模式模块加载到进程中时设置调试器异常的功能,但内核调试器仅支持具有该命令的内核模式模块。

下面的代码示例演示了“调试器命令程序”如何监视特定类安装程序或辅助安装程序到当前进程中的加载情况。 在此示例中,调试器命令程序将在main入口点上设置断点, (Mycoinst.dll共同安装程序的 CoInstallerProc) :

file: Z:\bpcoinst.txt

r $t1 = 0
!for_each_module .if ($spat("@#ModuleName", "mycoinst*") = 0) {r $t1 = 1}
.if (not @$t1 = 0) {.echo mycoinst is loaded, set bp on mycoinst!CoInstallerProc } .else {.echo mycoinst not loaded}
.if (not @$t1 = 0) {.reload mycoinst.dll}
.if (not @$t1 = 0) {bp[0x20] /p @$proc mycoinst!CoInstallerProc } .else {bc[0x20]}

执行时,调试器命令程序将检查加载到当前进程中Mycoinst.dll的模块列表。 加载此共同安装程序 DLL 后,调试器将使用 CoInstallerProc 入口点函数) 已知断点 ID 设置断点 (。

DrvInst.exe 主机进程启动的调试中断开始,应首先在调用的返回地址上设置断点 ,其中DrvInst.exe 中断到内核调试器中。 此断点将清除在设备安装期间设置的所有断点,并继续执行:

DRVINST.EXE: Entering debugger during PnP device installation.
Device instance = "X\Y\Z" ...

Break instruction exception - code 80000003 (first chance)
010117b7 cc               int     3

kd> bp[0x13] /p @$proc @$ra "bc *;g"

接下来,应在进程中设置一些断点,以允许调试器命令程序中的命令在设备安装期间的适当时间执行。

若要确保在为设备安装调用函数之前设置类安装程序或辅助安装程序 DLL 入口点的断点,应在将新 DLL 加载到当前进程(即对 LoadLibraryExW 的调用返回后)执行调试器命令程序:

kd> .reload
kd> bp[0x10] /p @$proc kernel32!LoadLibraryExW "gu;$$><Z:\\bpcoinst.txt;g"

开发人员可以将程序限制为仅在将类安装程序和共同安装程序 DLL 加载到进程中时,而不是在进程 (bp[0x10]) 中对每个 LoadLibraryEx 调用执行程序。 由于 SetupDiCallClassInstaller 是调用为设备注册的类安装程序和辅助安装程序的例程,因此在调用期间,这些 DLL 将加载到进程中。

由于不应假设何时会从DrvInst.exe主机进程中卸载这些 DLL,因此必须确保断点可以在从DrvInst.exe 主机进程SetupDiCallClassInstaller 进行的任何调用期间处理查找 DLL 入口点。

kd> bd[0x10]
kd> bp[0x11] /p @$proc setupapi!SetupDiCallClassInstaller "be[0x10];bp[0x12] /p @$proc @$ra \"bd[0x10];bc[0x12];g\";g"
kd> g

最初禁用执行调试器命令程序 (bp[0x10]) 的断点。 每当 (bp[0x11]) 调用 SetupDiCallClassInstaller 并继续执行时,它就会启用。 当 SetupDiCallClassInstaller 通过设置该例程本身 (bp[0x12]) 的返回地址上的断点,再次禁用调试器命令程序 (bp[0x10]) 。

请注意,禁用调试器命令程序的断点也会自行清除并继续执行,直到再次调用 SetupDiCallClassInstaller 或安装程序完成并且所有断点 (bp[0x13]) 清除为止。

在设置上述断点后开始执行时,进程将在每次调用 mycoinst 时中断!CoInstallerProc。 这使你可以在核心设备安装期间调试类安装程序或共同安装程序 DLL 的执行。

完成安装过程的默认时间段为 5 分钟。 如果进程未在给定时间段内完成,则系统会假定进程已停止响应,并且已终止。

通过内核调试器调试进程时,对设备安装设置的默认超时限制仍然有效。 由于系统上所有程序的执行在中断到调试器中时都会停止,因此跟踪安装过程所花费的时间量与在未调试的系统上的时间相同。