次の方法で共有


カーネル デバッガー (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」コマンドを使用してプロセスに読み込まれるときにデバッガーの例外を設定する機能をサポートしますが、カーネルデバッガーは、そのコマンドを使用したカーネルモードモジュールのみをサポートします。

次のコード例は、「デバッガ―コマンドプログラム」が、特定のクラスインストーラーまたは共同インストーラーの現在のプロセスへの読み込みを監視する方法を示しています。 この例では、デバッガーコマンドプログラムは、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"

開発者は、プロセス内のすべての LoadLibraryEx 呼び出し (bp[0x10]) でプログラムを実行するのではなく、クラスインストーラーと共同インストーラー DLL がプロセスに読み込まれるときにのみ実行するように制限できます。 理由として、SetupDiCallClassInstaller は、デバイスに登録されているクラスインストーラーと共同インストーラーを呼び出すルーチンであるため、これらの DLL は、その呼び出し中にプロセスに読み込まれます。

これらの DLL が DrvInst.exe のホストプロセスからアンロードされるタイミングを想定する必要はないため、 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]) を実行するブレークポイントは、最初は無効になっています。 SetupDiCallClassInstaller が呼び出されるたびに有効になり (bp[0x11])、実行が続行されます。 デバッガーのコマンドプログラム (bp[0x10]) は、SetupDiCallClassInstaller がそのルーチン自体のリターンアドレス (bp[0x12]) にブレークポイントを設定して戻るときに、再度無効になります。

デバッガーのコマンドプログラムを無効にするブレークポイントもそれ自体をクリアし、SetupDiCallClassInstaller が再度呼び出されるまで、またはインストールプログラムが完了してすべてのブレークポイントがクリアされるまで実行を続行することに注意してください (bp[0x13])。

上記のブレークポイントが設定された後に実行が開始されると、mycoinst!CoInstallerProc への呼び出しごとにプロセスが中断されます。 これにより、コアデバイスのインストール中にクラスインストーラーまたは共同インストーラー DLL の実行をデバッグできます。

インストールのプロセスが完了するまでの既定時間は 5 分です。 指定時間内にプロセスが完了しない場合、システムはプロセスがハング (応答を停止) して、インストールのプロセスが終了したと見なします。

プロセスがカーネルデバッガーを使用してデバッグされている間、デバイスのインストールに適用される既定のタイムアウト制限は引き続き有効です。 デバッガーに分割されている間、システム上のすべてのプログラムの実行が停止されるため、インストールのプロセスにかかる時間は、デバッグされていないシステムの場合と同じように追跡されます。