Windows ドライバーのデバッグ - ステップ バイ ステップ ラボ (エコー カーネル モード)

このラボでは、WinDbg カーネル デバッガーについて説明します。 WinDbg を使用して、エコー カーネル モードのサンプル ドライバー コードをデバッグします。

ラボの目的

このラボには、デバッグ ツールの導入、一般的なデバッグ コマンドの説明、ブレークポイントの使用方法の説明、デバッグ拡張機能の使用方法を示す演習が含まれています。

このラボでは、ライブ カーネル デバッグ接続を使用して、次のアクションを確認します。

  • Windows デバッガー コマンドを使用する
  • 標準コマンド (コール スタック、変数、スレッド、IRQL) を使用する
  • 高度なドライバー デバッグ コマンドを使用する (!commands)
  • シンボルを使用する
  • ライブ デバッグでブレークポイントを設定する
  • コール スタックの表示
  • プラグ アンド プレイ デバイス ツリーを表示する
  • スレッドとプロセスのコンテキストを操作する

ユーザー モードとカーネル モードのデバック

Windows デバッガーを操作する場合は、次の 2 種類のデバッグを実行できます。

コンピューター上のアプリケーションとサブシステムは、ユーザー モードで実行されます。 ユーザー モードで実行されるプロセスは、独自の仮想アドレス空間内で実行されます。 システム ハードウェア、使用に割り当てられていないメモリ、システムの整合性を損なう可能性のあるシステムの他の部分など、システムの多くの部分に直接アクセスすることが制限されています。 ユーザー モードで実行されるプロセスは、システムや他のユーザー モード プロセスから効果的に分離されるため、これらのリソースに干渉することはありません。

オペレーティング システムと特権プログラムはカーネル モードで実行されます。 カーネル モード コードには、システムの任意の部分にアクセスするアクセス許可があります。 ユーザー モード コードのように制限されていません。 ユーザー モードまたはカーネル モードのいずれかで実行されている他のプロセスの任意の部分にアクセスできます。 コア OS 機能の大部分と多くのハードウェア デバイス ドライバーは、カーネル モードで実行されます。

この演習では、ユーザー モードとカーネル モードの両方のデバッグ中に頻繁に使用されるデバッグ コマンドについて説明します。 この演習では、カーネル モードのデバッグに使用されるデバッグ拡張機能 (!commandsとも呼ばれる) についても説明します。

ラボのセットアップ

このラボを完了するには、以下ハードウェアが必要です。

  • Windows 10 を実行しているノート PC またはデスクトップ コンピューター (ホスト)
  • Windows 10 を実行している 2 台目のノート PC またはデスクトップ コンピューター (対象)
  • 2 台のコンピューターを接続するためのネットワーク ハブまたはルーターとネットワーク ケーブル
  • シンボル ファイルをダウンロードするためのインターネットへのアクセス

このラボを完了するには、以下ソフトウェアが必要です。

  • Visual Studio
  • Windows 10 用 Windows ソフトウェア開発キット (SDK)
  • Windows 10 用 Windows ドライバー キット (WDK)
  • Windows 10 のサンプル エコー ドライバー

ラボには次のセクションがあります。

カーネル モードの WinDbg セッションに接続する

このセクションでは、ホストとターゲット システムでネットワーク デバッグを構成します。

このラボのコンピューターは、カーネル デバッグにイーサネット ネットワーク接続を使用するように構成する必要があります。

このラボでは、2 台のコンピューターを使用します。 Windows デバッガーはホスト システムで実行され、カーネル モード ドライバー フレームワーク (KMDF) エコー ドライバーは対象のシステムで実行されます。

ネットワーク ハブまたはルーターとネットワーク ケーブルを使用して、2 台のコンピューターを接続します。

ネットワーク ハブまたはルーターを介して接続された 2 台のコンピューターを示す図。

カーネル モード アプリケーションを操作して WinDbg を使用するには、イーサネット トランスポート経由で KDNET を使用することをお勧めします。 イーサネット トランスポート プロトコルの使用方法に関する情報は、「WinDbg の概要 (カーネル モード)」を参照してください。 対象のコンピューターのセットアップの詳細については、「手動ドライバー デプロイ用にコンピューターを準備する」および「KDNET ネットワーク カーネルのデバッグを自動的に設定する」を参照してください。

イーサネットを使用してカーネル モードデバッグを構成する

ターゲット システムでカーネル モード デバッグを有効にするには:

  1. ホスト システムで、コマンド プロンプト ウィンドウを開き、「ipconfig」と入力して IP アドレスを確認します。

    Windows IP Configuration
    Ethernet adapter Ethernet:
       Connection-specific DNS Suffix  . :
       Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b%3
       Autoconfiguration IPv4 Address. . : 169.182.1.1
       Subnet Mask . . . . . . . . . . . : 255.255.0.0
       Default Gateway . . . . . . . . . :
    
  2. ホスト システムの IP アドレスを記録する: ______________________________________

  3. ターゲット システムで、コマンド プロンプト ウィンドウを開き、ping コマンドを使用して 2 つのシステム間のネットワーク接続を確認します。

    ping 169.182.1.1
    

    サンプル出力に示されている 169.182.1.1 ではなく、記録したホスト システムの実際の IP アドレスを使用します。

    Pinging 169.182.1.1 with 32 bytes of data:
    Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
    
    Ping statistics for 169.182.1.1:
        Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
    Approximate round trip times in milli-seconds:
        Minimum = 0ms, Maximum = 1ms, Average = 0ms
    

次の手順を実行して、ターゲット システムでカーネル モード デバッグを有効にします。

重要

BCDEdit を使用してブート情報を変更する前に、テスト コンピューターで BitLocker やセキュア ブートなどの Windows セキュリティ機能を一時的に中断することが必要になる場合があります。 テストが完了したら、これらのセキュリティ機能を再度有効にします。 セキュリティ機能が無効になっている場合は、テスト コンピューターを適切に管理してください。 セキュア ブートは通常、UEFI では無効になります。 UEFI 設定にアクセスするには、システム、回復、高度な起動を使用します。 再起動時、[トラブルシューティング]、[詳細オプション]、[UEFI ファームウェア設定] を選択します。 UEFI オプションを誤って設定したり、BitLocker を無効にしたりすると、システムが動作しなくなる可能性があるため、注意してください。

  1. ターゲット コンピューターで、管理者として [コマンド プロンプト] ウィンドウを開きます。 デバッグを有効にするには、次のコマンドを入力します。

    bcdedit /set {default} DEBUG YES
    
  2. テスト署名を有効にするには、次のコマンドを入力します。

    bcdedit /set TESTSIGNING ON 
    
  3. このコマンドを入力して、ホスト システムの IP アドレスを設定します。 表示されている IP アドレスではなく、前に記録したホスト システムの IP アドレスを使用します。

    bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    

    警告

    接続のセキュリティを強化し、ランダムなクライアント デバッガー接続要求のリスクを減らすには、自動生成されたランダム キーを使用します。 詳細については、「KDNET ネットワーク カーネル デバッグの自動設定」を参照してください。

  4. 次のコマンドを入力して、dbgsettings の値が正しく設定されていることを確認します。

    bcdedit /dbgsettings
    
    key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    debugtype               NET
    hostip                  169.168.1.1
    port                    50000
    dhcp                    Yes
    The operation completed successfully.
    

    Note

    ファイアウォールからメッセージを受信し、デバッガーを使用する場合は、3 つのボックスをすべて選択します。

    Windows ファイアウォールがアプリの一部の機能をブロックしたことを示す [Windows セキュリティ アラート] ダイアログ ボックスのスクリーンショット。

  5. ホスト コンピューターで、管理者として [コマンド プロンプト] ウィンドウを開きます。 このラボでは、Windows キットのインストールの一部としてインストールされた Windows Driver Kit (WDK) の x64 バージョンから WinDbg.exe を使用します。 既定の WinDbg ディレクトリに変更します。既定の場所は次に示します。

    cd C:\Program Files(x86)\Windows Kits\10\Debuggers\x64 
    

    このラボでは、両方のコンピューターがターゲットとホストの両方で 64 ビット バージョンの Windows を実行することを前提としています。 そうでない場合は、ターゲットが実行されているホストで同じ ビット数 のツールを実行することをお勧めします。 たとえば、ターゲットが 32 ビット Windows を実行するる場合は、ホストで 32 ビット バージョンのデバッガーを実行します。 詳細については、「32 ビットまたは 64 ビット デバッグ ツールの選択」を参照してください。

  6. 次のコマンドを使用して、リモート ユーザー デバッグで WinDbg を開きます。 キーとポートの値は、ターゲット コンピューターで BCDEdit を使用して前に設定した値と一致します。

    WinDbg –k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  7. ターゲット システムを再起動します。

  8. 1~2 分で、デバッグ出力がホスト システムに表示されます。

    Microsoft (R) Windows Debugger Version 10.0.17074.1002 AMD64
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    Using NET for debugging
    Opened WinSock 2.0
    Waiting to reconnect...
    Connected to target 169.182.1.1 on port 50005 on local IP 169.182.1.2
    You can get the target MAC address by running .kdtargetmac command.
    Connected to Windows 10 16299 x64 target at (Wed Feb 28 17:16:23.051 2018 (UTC - 8:00)), ptr64 TRUE
    Kernel Debugger connection established.  (Initial Breakpoint requested)
    Symbol search path is: srv*
    Executable search path is: 
    Windows 10 Kernel Version 16299 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 16299.15.amd64fre.rs3_release.170928-1534
    Machine Name:
    Kernel base = 0xfffff800`9540d000 PsLoadedModuleList = 0xfffff800`95774110
    Debug session time: Wed Feb 28 17:16:23.816 2018 (UTC - 8:00)
    System Uptime: 0 days 0:00:20.534
    

デバッガー コマンド ウィンドウは、WinDbg のプライマリ デバッグ情報ウィンドウです。 デバッガー コマンドを入力し、このウィンドウでコマンドの出力を表示できます。

デバッガー コマンド ウィンドウは 2 つのペインに分割されます。 ウィンドウの下部にあるコマンド入力ペインの小さなペインにコマンドを入力し、ウィンドウの上部にある大きなペインでコマンドの出力を表示します。

コマンド入力ペインで、上方向キーと下方向キーを使用して、コマンド履歴をスクロールします。 コマンドが表示されたら、コマンドを編集するか、Enter キーを押してコマンドを実行できます。

カーネルモード デバッグのコマンドと手法

このセクションでは、デバッグ コマンドを使用して、ターゲット システムに関する情報を表示します。

一部のデバッグ コマンドでは、選択するとより多くの情報をすばやく収集できるデバッガー マークアップ言語 (DML) を使用してテキストが表示されます。

  1. ホスト システムでは、WinDBg で Ctrl + Scroll Lock を使用して、ターゲット システムで実行されているコードに分割します。 ターゲット システムが応答するまでに時間がかかる場合があります。

    ライブ カーネル接続からのコマンド ウィンドウ出力を示すデバッガーのメイン画面。

  2. デバッガー コマンド ウィンドウで DML を有効にするには、次のコマンドを入力します。

    0: kd> .prefer_dml 1
    DML versions of commands on by default
    
  3. .hh コマンドを使用して、参照コマンドのヘルプにアクセスできます。 次のコマンドを入力して、.prefer_dml のコマンドリファレンスヘルプを表示します。

    0: kd> .hh .prefer_dml
    

    デバッガー のヘルプ ファイルには、.prefer_dml コマンドのヘルプが表示されます。

    .prefer-dml コマンドのヘルプを表示するデバッガー ヘルプ アプリケーションのスクリーンショット。

  4. ターゲット システムの詳細なバージョン情報を表示するには、WinDbg ウィンドウで vertarget (ターゲット コンピューターのバージョンの表示) コマンドを入力します。

    0: kd> vertarget
    Windows 10 Kernel Version 9926 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 9926.0.amd64fre.fbl_awesome1501.150119-1648
    Machine Name: ""
    Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0
    Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)
    System Uptime: 0 days 01:31:58.931
    
  5. 正しいカーネル モード プロセスを使用しているかを確認するには、WinDbg ウィンドウで lm (List Loaded Modules) コマンドを入力して、読み込まれたモジュールを表示します。

    0: Kd> lm
    start             end                 module name
    fffff801`09200000 fffff801`0925f000   volmgrx    (no symbols)
    fffff801`09261000 fffff801`092de000   mcupdate_GenuineIntel   (no symbols)
    fffff801`092de000 fffff801`092ec000   werkernel   (export symbols)       werkernel.sys
    fffff801`092ec000 fffff801`0934d000   CLFS       (export symbols)       CLFS.SYS
    fffff801`0934d000 fffff801`0936f000   tm         (export symbols)       tm.sys
    fffff801`0936f000 fffff801`09384000   PSHED      (export symbols)       PSHED.dll
    fffff801`09384000 fffff801`0938e000   BOOTVID    (export symbols)       BOOTVID.dll
    fffff801`0938e000 fffff801`093f7000   spaceport   (no symbols)
    fffff801`09400000 fffff801`094cf000   Wdf01000   (no symbols)
    fffff801`094d9000 fffff801`09561000   CI         (export symbols)       CI.dll
    ...
    

    省略された出力は、ラボの "..." で示されます。

  6. 特定のモジュールに関する詳細情報を要求するには、v (verbose) オプションを使用します。

    0: Kd> lm v m tcpip
    Browse full module list
    start             end                 module name
    fffff801`09eeb000 fffff801`0a157000   tcpip      (no symbols)           
        Loaded symbol image file: tcpip.sys
        Image path: \SystemRoot\System32\drivers\tcpip.sys
        Image name: tcpip.sys
        Browse all global symbols  functions  data
        Timestamp:        Sun Nov 09 18:59:03 2014 (546029F7)
        CheckSum:         00263DB1
        ImageSize:        0026C000
        Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    
    Unable to enumerate user-mode unloaded modules, Win32 error 0n30
    

    シンボル パスと読み込まれたシンボルは設定されていないため、デバッガーでは限られた情報を使用できます。

KMDF エコー ドライバーをダウンロードして構築する

このセクションでは、KMDF エコー ドライバーをダウンロードして構築します。

通常、WinDbg を使用する場合は、独自のドライバー コードを使用します。 WinDbg 操作について理解を深めるために、このラボでは KMDF テンプレート "Echo" サンプル ドライバーを使用します。 ソース コードは、WinDbg に表示される情報を理解するのに役立ちます。 このサンプルは、ネイティブ カーネルモード コードをシングルステップで実行する方法の説明にも使用されます。 この手法は、複雑なカーネルモード コードの問題をデバッグする場合に役立ちます。

Echo サンプル オーディオ ドライバーをダウンロードして構築するには:

  1. GitHub から KMDF Echo サンプルをダウンロードして抽出します。

    KMDF Echo サンプルは、[一般] フォルダーにあります。

    一般的なフォルダーとダウンロード zip ボタンが強調表示されている GitHub windows-driver-samples ページのスクリーンショット。

    1. 1 つの zip ファイルでドライバーのサンプルをダウンロードする: ドライバーのサンプル

    2. zip ファイルをローカル ハード ドライブにダウンロードします。

    3. zipファイルを選択して長押しするか、[すべて展開] を選択します。 新しいフォルダーを指定するか、既存のフォルダーを参照して抽出されたファイルを格納します。 たとえば、ファイルを抽出する新しいフォルダーとして C:\DriverSamples\ を指定できます。

    4. ファイルが抽出されたら、次のサブフォルダーに移動します: C:\DriverSamples\general\echo\kmdf

  2. Microsoft Visual Studio で [ファイル]>[開く]>[プロジェクト/ソリューション...] を選択し、抽出されたファイルを含むフォルダー (C:\DriverSamples\general\echo\kmdf など) に移動します。 kmdfecho ソリューション ファイルをダブルクリックして開きます。

    Visual Studio で、ソリューション エクスプローラーを見つけます。 このウィンドウがまだ開いていない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します。 ソリューション エクスプローラーでは、3 つのプロジェクトを含む 1 つのソリューションを確認できます。

    kmdfecho プロジェクトから読み込まれた device.c ファイルを表示している Visual Studio のスクリーンショット。

  3. サンプルの構成とプラットフォームを設定します。 ソリューション エクスプローラーでは、ソリューション 'kmdfecho' (3 プロジェクト)を長押し (または右クリック) し、[構成マネージャー] を選びます。 構成とプラットフォームの設定が 3 つのプロジェクトで同じになっていることを確認します。 既定では、構成は Win10 Debug に設定され、プラットフォームはすべてのプロジェクトで Win64 に設定されます。 1 つのプロジェクトに対して構成またはプラットフォームを変更する場合は、残りの 3 つのプロジェクトに対しても同じ変更を行います。

  4. 既存のドライバーと重複しない値を使用するには、ドライバ ーサンプルを変更する必要があります。 Windows にインストールされている既存の実際のドライバーと共存する一意のドライバー サンプルを作成する方法について「サンプル コードから運用ドライバーへ - サンプルで変更する内容」を参照してください。

  5. ランタイム ライブラリを設定します。 エコー ドライバーのプロパティ ページを開き、C/C++>Code Generation を見つけます。 ランタイム ライブラリをマルチスレッド デバッグ (/MTd) に変更します。 構築オプションの詳細については、「/MD、/MT、/LD (ランタイム ライブラリの使用)」のトピックを参照してください。

    ランタイム ライブラリ設定が強調表示されている、Visual Studio のエコー プロパティ ページのスクリーンショット。

  6. ドライバーのプロパティで、ドライバー署名>の署名モードテスト署名に設定されていることを確認します。

    署名モード設定が強調表示されている、Visual Studio のエコー プロパティ ページのスクリーンショット。

  7. Visual Studio で、[構築]>[ソリューションのビルド] を選択します。

    構築ウィンドウには、3 つのプロジェクトすべての構築が成功したことを示すメッセージが表示されます。

ヒント

構築エラー メッセージが表示された場合は、構築エラー番号を使用して修正プログラムを特定します。 たとえば、 MSBuild エラー MSB8040 では、 spectre 軽減ライブラリを操作する方法について説明します。

  1. エクスプローラーで、サンプルの抽出されたファイルを含むフォルダーに移動します。 たとえば、先ほど指定したフォルダーの場合は、C:\DriverSamples\general\echo\kmdf に移動します。 そのフォルダー内では、コンパイルされたドライバー ファイルの場所は、Configuration Manager で選択した構成とプラットフォームの設定によって異なります。 既定の設定を変更しない場合、コンパイルされたドライバー ファイルは、64 ビット デバッグ構築の \x64\Debug という名前のフォルダーに保存されます。

    自動同期ドライバーの構築ファイルが含まれているフォルダーに移動します: C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug

    フォルダーには、次のファイルが含まれているはずです。

    ファイル 説明
    Echo.sys ドライバー ファイル。
    Echo.inf ドライバーのインストールに必要な情報を含む情報 (INF) ファイル。

    また、echoapp.exe ファイルが構築されており、C:\DriverSamples\general\echo\kmdf\exe\x64\Debug にあります。

    ファイル 説明
    EchoApp.exe echo.sys ドライバーと通信するコマンド プロンプト実行可能テスト ファイル。
  2. USB サム ドライブを見つけるか、構築されたドライバー ファイルとテスト EchoApp をホストからターゲット システムにコピーするようにネットワーク共有を設定します。

次のセクションでは、ターゲット システムにコードをコピーし、ドライバーをインストールしてテストを行います。

ターゲット システムに KMDF エコー ドライバー サンプルをインストールする

このセクションでは、DevCon ツールを使用してエコー サンプル ドライバーをインストールします。

ドライバーをインストールするコンピューターは、ターゲット コンピューターまたはテスト コンピューターと呼ばれます。 通常、このコンピューターは、ドライバー パッケージを開発および構築するコンピューターとは別です。 ドライバーを開発および構築するコンピューターは、ホスト コンピューターと呼ばれます。

ドライバーパッケージをターゲットコンピューターに移動し、ドライバーをインストールするプロセスをドライバーのデプロイと呼びます。

テスト署名済みドライバーをデプロイする前に、テスト署名を有効にしてターゲット コンピューターを準備します。 また、WDK インストールで DevCon ツールを見つけて、ターゲット システムにコピーする必要もあります。

ターゲット システムにドライバーをインストールするには、次の手順を実行します。

ターゲット システムで、テスト署名済みドライバーを有効にします。

  1. [Windows の設定] を開きます。

  2. [更新とセキュリティ] で、[リカバリ] を選択します。

  3. [PC の起動をカスタマイズする] で、[今すぐ再起動] を選びます。

  4. コンピューターが再起動したら、[スタートアップ オプション] を選択します。 Windows 10 で、[スタートアップ設定][詳細オプション]> の [トラブルシューティング]> を選択し、[再起動] を選択します。

  5. F7 キーを押して [ドライバー署名の適用を無効にする] を選択します。

  6. 対象のコンピューターを再起動します。

ホスト システムで、WDK インストールの [ツール] フォルダーに移動し、DevCon ツールを見つけます。 たとえば、次のフォルダーを探します: C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe

構築されたドライバー パッケージのターゲットにフォルダー (C:\EchoDriver など) を作成します。 devcon.exe をターゲット システムにコピーします。 ホスト システムで .cer 証明書を見つけます。 これは、構築されたドライバー ファイルを含むフォルダー内のホスト コンピューター上の同じフォルダーにあります。 ホスト コンピューターで前述した構築ドライバーからすべてのファイルをコピーし、ターゲット コンピューターで作成したのと同じフォルダーに保存します。

ターゲット コンピューターで、証明書ファイルを選択して長押しするか右クリックし、[インストール] を選択してから、プロンプトに従ってテスト証明書をインストールします。

ターゲット コンピューター設定のより詳細な手順が必要な場合は、「手動ドライバー デプロイ用のコンピューターの準備」を参照してください。

次の手順では、サンプル ドライバーをインストールしてテストする方法を説明します。 ドライバーのインストールに使用する devcon ツールの一般的な構文を次に示します。

devcon install <INF file> <hardware ID>

このドライバーのインストールに必要な INF ファイルは echo.inf です。 inf ファイルには、echo.sys をインストールするためのハードウェア ID が含まれています。 エコー サンプルの場合、ハードウェア ID は root\ECHO です。

ターゲット コンピューターで、管理者として [コマンド プロンプト] ウィンドウを開きます。 ご自身のドライバー パッケージのフォルダーに移動し、次のコマンドを入力します。

devcon install echo.inf root\ECHO

devcon が認識されないというエラー メッセージが表示される場合は、devcon ツールへのパスを追加してみてください。 たとえば、C:\Tools というフォルダーにコピーした場合は、次のコマンドを使用してみてください。

c:\tools\devcon install echo.inf root\ECHO

テスト ドライバーが署名されていないドライバーであることを示すダイアログ ボックスが表示されます。 [かまわず続行] を選択して続行します。

Windows がドライバー ソフトウェアの発行元を確認できないことを示す、Windows セキュリティ警告のスクリーンショット。

ヒント

 インストールに問題がある場合は、次のファイルをチェックして詳細を確認してください。 %windir%\inf\setupapi.dev.log

サンプル ドライバーが正常にインストールされたら、テストする準備ができたということです。

ターゲット コンピューターのコマンド プロンプト ウィンドウで、「devmgmt」と入力して、デバイス マネージャーを開きます。 デバイス マネージャーで、[表示] メニューの [デバイスの種類] を選択します。デバイス ツリーで、サンプル デバイス ノードからサンプル WDF エコー ドライバーを見つけます。

サンプルの WDF エコー ドライバーが強調表示されているデバイス マネージャー ツリーのスクリーンショット。

echoapp を入力してテスト エコー アプリを起動し、ドライバーが機能していることを確認します。

C:\Samples\KMDF_Echo_Sample> echoapp
DevicePath: \\?\root#sample#0005#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a}
Opened device successfully
512 Pattern Bytes Written successfully
512 Pattern Bytes Read successfully
Pattern Verified successfully
30720 Pattern Bytes Written successfully
30720 Pattern Bytes Read successfully
Pattern Verified successfully

WinDbg を使用してドライバーに関する情報を表示する

このセクションでは、シンボル パスを設定し、カーネル デバッガー コマンドを使用して KMDF エコー サンプル ドライバーに関する情報を表示します。

ドライバに関する情報を表示するには:

  1. ホスト システムでデバッガーを閉じた場合は、管理者のコマンド プロンプト ウィンドウで次のコマンドを使用して再度開きます。

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Ctrl + Break (スクロール ロック) を使用して、ターゲット システムで実行されているコードを中断します。

  3. WinDbg 環境で Microsoft シンボル サーバーへのシンボル パスを設定するには、.symfix コマンドを使用します。

    0: kd> .symfix
    
  4. ローカル シンボルを使用するローカル シンボルの場所を追加するには、.sympath+ を使用してパスを追加して .reload /f

    0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf
    0: kd> .reload /f
    

    /f 強制オプションを指定した .reload コマンドは 、指定したモジュールのすべてのシンボル情報を削除し、シンボルを再読み込みします。 場合によっては、このコマンドはモジュール自体のリロードやアンロードも行います。

WinDbg で提供されている高度な機能のすべてを使用するには、適切なシンボルを読み込む必要があります。 シンボルが適切に構成されていない場合は、シンボルに依存する機能を使用しようとしたときに、そのシンボルが使用できないことを示すメッセージが表示されます。

0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type “.hh dbgerr005” for details.

シンボルを操作する上で使用できる方法はたくさんあります。 多くの場合で、必要なときに Microsoft が提供するシンボル サーバーからシンボルにアクセスするようにコンピューターを構成できます。 このラボでは、そのアプローチを使用します。 お使いの環境内のシンボルが別の場所にある場合は、その場所を使用するように手順を変更します。 詳細については、「Windows デバッカーのシンボル パス」を参照してください。

ソース デバッグを実行するには、バイナリのチェック (デバッグ) バージョンを構築する必要があります。 コンパイラはシンボル ファイル (.pdb ファイル) を作成します。 これらのシンボル ファイルは、バイナリ命令がソース行にどのように対応するかをデバッガーに示します。 実際のソース ファイル自体もデバッガーからアクセスできるようにする必要があります。

シンボル ファイルには、ソース コードのテキストが含まれません。 デバッグの場合は、リンカーがコードを最適化しない場合に最適です。 コードが最適化されている場合、ソースのデバッグとローカル変数へのアクセスは困難になり、場合によってはほぼアクセスできなくなります。 ローカル変数またはソース行の表示で問題が発生した場合は、次の構築オプションを設定します。

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. デバッガーのコマンド領域に次のコマンドを入力して、エコー ドライバーに関する情報を表示します。

    0: kd> lm m echo* v
    Browse full module list
    start             end                 module name
    fffff801`4ae80000 fffff801`4ae89000   ECHO       (private pdb symbols)  C:\Samples\KMDF_ECHO_SAMPLE\echo.pdb
        Loaded symbol image file: ECHO.sys
        Image path: \SystemRoot\system32\DRIVERS\ECHO.sys
        Image name: ECHO.sys
    ...  
    

    詳細については、「lm」を参照してください。

  2. このラボは以前にprefer_dml 設定がされているため、出力の一部の要素は、選択できるホット リンクです。 デバッグ出力にある [すべてのグローバル シンボルの参照] リンクを選択すると、文字 "a" で始まる項目シンボルに関する情報が表示されます。

    0: kd> x /D Echo!a*
    
  3. エコー サンプルには、文字 "a" で始まるシンボルは含まれていないため、"Echo" で始まるエコー ドライバーに関連付けられているすべてのシンボルに関する情報を表示するように x ECHO!Echo* を入力します。

    0: kd> x ECHO!Echo*
    fffff801`0bf95690 ECHO!EchoEvtIoQueueContextDestroy (void *)
    fffff801`0bf95000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    fffff801`0bf95ac0 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    fffff801`0bf9b120 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    ...
    

    詳細については、「x (Examine Symbols)」を参照してください。

  4. !lmi 拡張子は、モジュールに関する詳細情報を表示します。 「!lmi echo」と入力します。 出力は、次の例に示すテキストのようになります。

    0: kd> !lmi echo
    Loaded Module Info: [echo] 
             Module: ECHO
       Base Address: fffff8010bf94000
         Image Name: ECHO.sys
    … 
    
  5. !dh 拡張機能を使用して、次の例に示すようにヘッダー情報を表示します。

    0: kd> !dh echo
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
         14C machine (i386)
           6 number of sections
    54AD8A42 time date stamp Wed Jan 07 11:34:26 2015
    ...
    
  6. ターゲット システムからのすべてのデバッグ メッセージがデバッガーに表示されるように、既定のデバッグ ビット マスクを変更するには、次のように入力します。

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    

    一部のドライバーでは、0xFFFFFFFF のマスクを使用すると追加情報が表示されます。 表示される情報の量を減らす場合は、マスクを 0x00000000 に設定します。

    0: kd> ed nt!Kd_DEFAULT_MASK 0x00000000
    

    ddコマンドを使用して、マスクがすべてのデバッカー メッセージを表示するように設定されていることを確認します。

    0: kd> dd nt!kd_DEFAULT_MASK 
    fffff802`bb4057c0  ffffffff 00000000 00000000 00000000
    fffff802`bb4057d0  00000000 00000000 00000000 00000000
    fffff802`bb4057e0  00000001 00000000 00000000 00000000
    fffff802`bb4057f0  00000000 00000000 00000000 00000000
    fffff802`bb405800  00000000 00000000 00000000 00000000
    fffff802`bb405810  00000000 00000000 00000000 00000000
    fffff802`bb405820  00000000 00000000 00000000 00000000
    fffff802`bb405830  00000000 00000000 00000000 00000000
    

プラグ アンド プレイ デバイス ツリーに関する情報を表示する

このセクションでは、エコー サンプル デバイス ドライバーと、それがプラグ アンド プレイ デバイス ツリー内のどこに存在するかについての情報を表示します。

プラグ アンド プレイ デバイス ツリーのデバイス ドライバーに関する情報は、トラブルシューティングに役立ちます。 たとえば、デバイス ドライバーがデバイス ツリーに常駐していない場合、デバイス ドライバーのインストールに問題がある可能性があります。

デバイス ノードデバッグ拡張機能の詳細については、「!devnode」を参照してください。

  1. ホスト システムでプラグ アンド プレイ デバイス ツリー内のデバイス ノードをすべて表示するには、!devnode 0 1 コマンドを入力します。

    0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30)
    DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0…
    …
    
  2. 生成された出力を検索して、デバイス ドライバーの名前である echo を検索するには、Ctrl + F キーを押します。

  3. エコー デバイス ドライバーを読み込む必要があります。 !devnode 0 1 echo コマンドを使用して、次の例に示すように、エコー デバイス ドライバーに関連付けられているプラグ アンド プレイ情報を表示します。

    0: Kd> !devnode 0 1 echo
    Dumping IopRootDeviceNode (= 0xffffe0007b725d30)
    DevNode 0xffffe0007b71a630 for PDO 0xffffe0007b71a960
      InstancePath is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    …
    
  4. 前のコマンドに表示される出力には、ドライバーの実行中のインスタンスに関連付けられている PDO が含まれています。この例では、0xffffe0007b71a960 です。 エコー デバイス ドライバーに関連付けられているプラグ アンド プレイ情報を表示する !devobj <PDO address> コマンドを入力します。 ここではなく、!devnode がコンピューターに表示する PDO アドレスを使用します。

    0: kd> !devobj 0xffffe0007b71a960
    Device object (ffffe0007b71a960) is for:
     0000000e \Driver\PnpManager DriverObject ffffe0007b727e60
    Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
    Dacl ffffc102c9b36031 DevExt 00000000 DevObjExt ffffe0007b71aab0 DevNode ffffe0007b71a630 
    ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe000801fee20 \Driver\ECHO
    Device queue is not busy.
    
  5. !devnode 0 1 コマンドに表示される出力には、ドライバーの実行中のインスタンスに関連付けられている PDO アドレスが含まれています。この例では、0xffffe0007b71a960 です。 デバイス ドライバーに関連付けられているプラグ アンド プレイ情報を表示する !devstack <PDO address> コマンドを入力します。 この例ではなく、!devnode がコンピューターに表示する PDO アドレスを使用します。

    0: kd> !devstack 0xffffe0007b71a960
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe000801fee20  \Driver\ECHO       ffffe0007f72eff0  
    > ffffe0007b71a960  \Driver\PnpManager 00000000  0000000e
    !DevNode ffffe0007b71a630 :
      DeviceInst is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
    

出力は、非常に単純なデバイス ドライバー スタックがあることを示しています。 エコー ドライバーは、PnPManager ノードの子です。 PnPManager はルート ノードです。

\Driver\ECHO
\Driver\PnpManager

この図は、より複雑なデバイス ノード ツリーを示しています。

約 20 個のノードからなるデバイス ノード ツリーを示している図。

より複雑なドライバー スタックの詳細については、「ドライバー スタックデバイス ノードとデバイス スタック」を参照してください。

ブレークポイントとソース コードを操作する

このセクションでは、ブレークポイントを設定し、カーネル モードのソース コードを 1 ステップで実行します。

コードをステップを通して実行し、変数の値をリアルタイムでチェックできるようにするには、ブレークポイントを有効にして、ソース コードへのパスを設定します。

ブレークポイントは、特定のコード行でコードの実行を停止します。 コードの特定のセクションをデバッグするには、その時点からコードを一歩進めます。

デバッグ コマンドを使用してブレークポイントを設定するには、次のいずれかの b コマンドを使用します。

コマンド 説明
bp 含まれるモジュールがアンロードされるまでアクティブなブレークポイントを設定します。
bu モジュールのアンロード時に未解決のブレークポイントを設定し、モジュールの再読み込み時に再度有効にします。
bm シンボルのブレークポイントを設定します。 このコマンドは、bu または bp を適切に使用し、クラス内のすべてのメソッドと同様に、一致するすべてのシンボルにブレークポイントを設定するために、ワイルドカード (*) を使用できるようにします。

詳細については、「WinDbg でのソース コードのデバッグ」を参照してください。

  1. ホスト システムで、WinDbg UI を使用して、現在の WinDbg セッションでデバッグ>ソース モードが有効になっていることを確認します。

  2. 次のコマンドを入力して、ローカル コードの場所をソース パスに追加します。

    .srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  3. 次のコマンドを入力して、ローカル シンボルの場所をシンボル パスに追加します。

    .sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  4. x コマンドを使用して、エコー ドライバーに関連付けられているシンボルを調べて、ブレークポイントに使用する関数名を決定します。 ワイルドカードまたは Ctrl + F キーを使用して、DeviceAdd 関数名を検索できます。

    0: kd> x ECHO!EchoEvt*
    8b4c7490          ECHO!EchoEvtIoQueueContextDestroy (void *)
    8b4c7000          ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    8b4c7820          ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    8b4cb0e0          ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    8b4c75d0          ECHO!EchoEvtIoWrite (struct WDFQUEUE__ *, struct WDFREQUEST__ *, unsigned int)
    8b4cb170          ECHO!EchoEvtDeviceAdd (struct WDFDRIVER__ *, struct 
    …
    

    出力は、エコー ドライバーの DeviceAdd メソッドが ECHO!EchoEvtDeviceAdd であることを示しています。

    または、ソース コードを確認して、ブレークポイントの関数名を見つけます。

  5. ドライバーの名前を使用して bm コマンドとブレークポイントを設定し、次に関数名 (たとえば、 AddDevice、感嘆符で区切ってブレークポイントを設定する場所) を設定します。 このラボでは、読み込まれているドライバーを監視するために AddDevice を使用します。

    0: kd> bm ECHO!EchoEvtDeviceAdd
      1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
    

    さまざまな構文を、<module>!<symbol><class>::<method>、または'<file.cpp>:<line number>' などの変数の設定と組み合わせて使用したり、何度もスキップすることができます<condition> <#>。 詳細については、「WinDbgおよびその他のWindows デバッガーの条件付きブレークポイント」 を参照してください。

  6. 現在のブレークポイントを一覧表示し、ブレークポイントが bl コマンドを入力して設定されたことを確認します。

    0: kd> bl
    1 e fffff801`0bf9b1c0     0001 (0001) ECHO!EchoEvtDeviceAdd
    

    ここに示す出力の "e" は、ブレークポイント番号 1 の起動が有効になっていることを示しています。

  7. g (go) コマンドを入力して、ターゲット システムでのコード実行を再開します。

  8. ターゲット システムの Windows で、アイコンを使用するか mmc devmgmt.msc と入力してデバイス マネージャーを開きます。 デバイス マネージャーで、[サンプル] ノードを展開します。

  9. KMDF エコー ドライバー エントリを長押しするか右クリックし、メニューから [無効] を選択します。

  10. KMDF エコー ドライバー エントリを再度長押しするか右クリックし、メニューから [有効] を選択します。

  11. ホスト システムでドライバーが有効になっていると、 AddDevice デバッグ ブレークポイントが起動します。 ターゲット システムのドライバー コードの実行が停止します。 ブレークポイントに達すると、AddDevice ルーチンの開始時に実行が停止されます。 デバッグ コマンドの出力が Breakpoint 1 hit を表示します。

    サンプル コードのローカルとコマンド ウィンドウが表示されている WinDbg のスクリーンショット。

  12. p コマンドを入力するか F10 キーを押して、次の AddDevice ルーチンの最後に到達するまでコードを 1 行ずつ実行します。 中括弧文字 (}) は、次のようにハイライトされます。

    AddDevice ルーチンの先頭で中かっこ文字が強調表示されているコード ウィンドウのスクリーンショット。

次のセクションでは、DeviceAdd コードが実行された後の変数の状態を調べます。

次のコマンドを使用して、既存のブレークポイントを変更できます。

コマンド 説明
bl ブレークポイントを一覧表示します。
bc 一覧からブレークポイントをクリアします。 すべてのブレークポイントをクリアするために bc * を使用します。
bd ブレークポイントを無効にします。 bd * を使用してブレークポイントを無効にします。
be ブレークポイントの有効化します。 be * を使用してブレークポイントを有効にします。

または、WinDbg UI でブレークポイントを変更することもできます。

また、メモリ位置にアクセスしたときに発生するブレークポイントを設定できます。 次の構文といっしょに ba (アクセス時に中断) コマンドを使用します。

ba <access> <size> <address> {options}
オプション 説明
e execute: CPU がアドレスから命令をフェッチする場合
r read/write: CPU がアドレスに対して読み取りまたは書き込みを行うとき
w write: CPU がアドレスに書き込むとき

特定の時点で設定できるデータ ブレークポイントは 4 つだけです。 ブレークポイントをトリガーするためにデータを正しく配置しているかを確認するのはユーザーの判断です。 単語は、2 で割り切れるアドレスで終わる必要があり、dwords は 4 で割り切れ、クワッド ワードは 0 または 8 で割り切れなければなりません。

たとえば、特定のメモリ アドレスに読み取り/書き込みブレークポイントを設定するには、次の例のようなコマンドを使用できます。

ba r 4 0x0003f7bf0

次のコマンドを使用して、括弧で囲まれた関連するキーボードショートカットを使用してコードのステップを進めることができます。

  • 中断 (Ctrl + Break)。 このコマンドは、システムが実行され、WinDbg と通信している限り、システムを中断します。 カーネル デバッガーのシーケンスは Ctrl + C です。
  • カーソルまで実行 (F7 または Ctrl + F10)。 実行を中断するソースまたは逆アセンブル ウィンドウにカーソルを置き、F7 キーを押します。 コードの実行は、その時点まで実行されます。 コード実行のフローがカーソルによって示されるポイントに達しない場合、WinDbg は中断されません。 この状況は、IF ステートメントが実行されていない場合に発生する可能性があります。
  • (F5) を実行します。 ブレークポイントが検出されるか、バグ チェックなどのイベントが発生するまで実行します。
  • ステップ オーバー (F10)。 このコマンドを実行すると、コードの実行が一度に 1 つのステートメントまたは 1 つの命令ずつ続行します。 呼び出しが発生した場合、呼び出されたルーチンに入らずにコード実行が呼び出しを通過します。 プログラミング言語が C または C++ で、WinDbg がソース モードの場合は、デバッグ>ソース モードを使用してソース モードを有効または無効にすることができます。
  • ステップ イン (F11)。 このコマンドはステップオーバーに似ていますが、呼び出しの実行が呼び出されたルーチンに入る点が異なります。
  • ステップ アウト (ShiftF11)。 このコマンドを実行すると、コール スタック内の現在のルーチンまたは現在の場所に対して実行が行われ、終了します。 このコマンドは、ルーチンを十分に確認した場合に便利です。

詳細については、「WinDbg でのソース コードのデバッグ」を参照してください。

変数とコール スタックを表示する

このセクションでは、変数とコール スタックに関する情報を表示します。

このラボでは、前に説明したプロセスを使用して、AddDevice ルーチンで停止していることを前提としています。 ここで示す出力を表示するには、必要に応じて、前に説明した手順を繰り返します。

ホスト システムで変数を表示するには、ローカル変数を表示する [ローカル表示>] メニュー項目を使用します。

ローカル変数ウィンドウが表示されている WinDbg のスクリーンショット。

グローバル変数アドレスの場所を検索するには、「? <variable name>」と入力します。

  • ステップ アウト (Shift + F11) – このコマンドを実行すると、現在のルーチン (コール スタック内の現在の場所) に対して実行され、終了します。 これは、ルーチンを十分に確認した場合に便利です。

詳細については、デバッグ リファレンス ドキュメントの「WinDbg (クラシック) にあるソース コードのデバッグ」を参照してください。

セクション 8: 変数とコール スタックの表示

セクション 8 では、変数とコール スタックに関する情報を表示します。

このラボでは、前に説明したプロセスを使用して、AddDevice ルーチンで停止していることを前提としています。 ここで示す出力を表示するには、必要に応じて、前に説明した手順を繰り返します。

<- ホスト システム上

変数の表示

ローカル変数を表示するには、[ローカル表示>] メニュー項目の表示を使用します。

ローカル変数ウィンドウが表示されている WinDbg のスクリーンショット。

グローバル変数

? <variable name>」と入力すると、グローバル変数アドレスの場所を見つけることができます

ローカル変数

dv コマンドを入力すると、特定のフレームのすべてのローカル変数の名前と値を表示できます。 特定のフレームのすべてのローカル変数の名前と値を表示するには、dv コマンドを入力します。

0: kd> dv
         Driver = 0x00001fff`7ff9c838
     DeviceInit = 0xffffd001`51978190
         status = 0n0

呼び出し履歴は、プログラム カウンターの現在の場所に至った関数呼び出しのチェーンです。 呼び出し履歴の最上位の関数は現在の関数、次の関数は現在の関数を呼び出した関数などです。

コール スタックを表示するには、k* コマンドを使用します。

コマンド 説明
kb スタックと最初の 3 つのパラメーターを表示します。
kp スタックとパラメータの完全なリストを表示します。
kn スタックの横にフレーム情報を表示できます。
  1. ホスト システムで、コール スタックを使用できるようにする場合は、[コール スタック表示>] を選択して表示します。 ウィンドウの上部にある列を選択して、追加情報の表示を切り替えます。

    呼び出しスタック ウィンドウが表示されている WinDbg のスクリーンショット。

  2. kn コマンドを使用して、中断状態のサンプル アダプター コードのデバッグ中にコール スタックを表示します。

    3: kd> kn
    # Child-SP          RetAddr           Call Site
    00 ffffd001`51978110 fffff801`0942f55b ECHO!EchoEvtDeviceAdd+0x66 [c:\Samples\kmdf echo sample\c++\driver\autosync\driver.c @ 138]
    01 (Inline Function) --------`-------- Wdf01000!FxDriverDeviceAdd::Invoke+0x30 [d:\wbrtm\minkernel\wdf\framework\shared\inc\private\common\fxdrivercallbacks.hpp @ 61]
    02 ffffd001`51978150 fffff801`eed8097d Wdf01000!FxDriver::AddDevice+0xab [d:\wbrtm\minkernel\wdf\framework\shared\core\km\fxdriverkm.cpp @ 72]
    03 ffffd001`51978570 fffff801`ef129423 nt!PpvUtilCallAddDevice+0x35 [d:\9142\minkernel\ntos\io\pnpmgr\verifier.c @ 104]
    04 ffffd001`519785b0 fffff801`ef0c4112 nt!PnpCallAddDevice+0x63 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 7397]
    05 ffffd001`51978630 fffff801`ef0c344f nt!PipCallDriverAddDevice+0x6e2 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 3390]
    ...
    

コール スタックは、カーネル (nt) がプラグ アンド プレイ コード (PnP) を呼び出し、そのコードがドライバー フレームワーク コード (WDF) を呼び出した後、エコー ドライバー DeviceAdd 関数を呼び出したことを示しています。

プロセスとスレッドを表示する

このセクションでは、カーネル モードで実行されているプロセスとスレッドに関する情報を表示します。

処理

!process デバッガー拡張機能を使用して、プロセス情報を表示または設定できます。 ブレークポイントを設定して、サウンドの再生時に使用されるプロセスを調べます。

  1. ホスト システムで、EchoEvtIoルーチンに関連付けられているロケール変数を調べる dv コマンドを入力します。

    0: kd> dv ECHO!EchoEvtIo*
    ECHO!EchoEvtIoQueueContextDestroy
    ECHO!EchoEvtIoWrite
    ECHO!EchoEvtIoRead         
    
  2. bc * を使用して、前のブレークポイントをクリアします。

    0: kd> bc *  
    
  3. 次のコマンドを使用して、EchoEvtIo ルーチンにシンボル ブレークポイントを設定します。

    0: kd> bm ECHO!EchoEvtIo*
      2: aade5490          @!”ECHO!EchoEvtIoQueueContextDestroy”
      3: aade55d0          @!”ECHO!EchoEvtIoWrite”
      4: aade54c0          @!”ECHO!EchoEvtIoRead”
    
  4. ブレークポイントを一覧表示して、ブレークポイントが正しく設定されていることを確認します。

    0: kd> bl
    1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197]    0001 (0001) ECHO!EchoEvtIoQueueContextDestroy
    ...
    
  5. g と入力してコードの実行を再開します。

    0: kd> g
    
  6. ターゲット システムで、ターゲット システムの EchoApp.exe ドライバー テスト プログラムを実行します。

  7. ホスト システムでは、テスト アプリを実行すると、ドライバーの I/O ルーチンが呼び出されます。 この呼び出しによりブレークポイントが起動し、ターゲット システムでのドライバー コードの実行が停止します。

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. !process コマンドを使用して、echoapp.exe の実行に関連する現在のプロセスを表示します。

    0: kd> !process
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 03c4    Peb: 7ff7cfec4000  ParentCid: 0f34
        DirBase: 1efd1b000  ObjectTable: ffffc001d77978c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000802c79f0 Vads 30 Clone 0 Private 135. Modified 5. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf270050
        ElapsedTime                       00:00:00.052
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (682, 50, 345) (2728KB, 200KB, 1380KB)
        PeakWorkingSetSize                652
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    688
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe00080e32080  Cid 03c4.0ec0  Teb: 00007ff7cfece000 Win32Thread: 0000000000000000 RUNNING on processor 1
    

    出力は、ドライバー書き込みイベントのブレークポイントが達したときに実行されていた echoapp.exe スレッドにプロセスが関連付けられていることを示しています。 詳細については、「!process」に関するページを参照してください。

  9. !process 0 0 を使用して、すべてのプロセスの概要情報を表示します。 出力で、Ctrl + F キーを押して、echoapp.exe イメージに関連付けられているプロセスと同じプロセス アドレスを見つけます。 この例では、プロセス アドレスは ffffe0007e6a7780 です。

    ...
    
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
        DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
        Image: echoapp.exe
    
    ...
    
  10. このラボの後半で使用する echoapp.exe に関連付けられているプロセス ID を記録します。 後で使用するために、Ctrl + C キーを押してアドレスをコピー バッファーにコピーすることもできます。

    _____________________________________________________(echoapp.exe プロセス アドレス)

  11. 必要に応じて g をデバッガーに入力し、echoapp.exe の実行が完了するまでコードを前に進めます。 読み取りおよび書き込みイベントのブレークポイントに何度も達します。 echoapp.exe が完了したら、Ctrl + ScrLk (Ctrl + Break) キーを押してデバッガーを中断します。

  12. !process コマンドを使用して、別のプロセスを実行していることを確認します。 ここで示す出力では、System の Image 値を持つプロセスは、Echo Image の値とは異なります。

    1: kd> !process
    PROCESS ffffe0007b65d900
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001ab000  ObjectTable: ffffc001c9a03000  HandleCount: 786.
        Image: System
        VadRoot ffffe0007ce45930 Vads 14 Clone 0 Private 22. Modified 131605. Locked 64.
        DeviceMap ffffc001c9a0c220
        Token                             ffffc001c9a05530
        ElapsedTime                       21:31:02.516
    ...
    

    出力は、OS を停止したときにシステム プロセス ffffe0007b65d900 が実行されていたことを示しています。

  13. !process コマンドを使用して、前に記録した echoapp.exe に関連付けられたプロセス ID を調べます。 この例で示したプロセス アドレスの例ではなく、前に記録した echoapp.exe プロセス アドレスを指定します。

    0: kd> !process ffffe0007e6a7780
    TYPE mismatch for process object at 82a9acc0
    

    echoapp.exe プロセスが実行されなくなったため、プロセス オブジェクトは使用できなくなりました。

スレッド数

スレッドを表示および設定するコマンドは、プロセスのコマンドと似ています。 !thread コマンドを使用してスレッドを表示します。 現在のスレッドを設定するには、.thread を使用します。

  1. ホスト システムで、デバッガーに g と入力し、ターゲット システムでコードの実行を再開します。

  2. ターゲット システムで、EchoApp.exe ドライバー テスト プログラムを実行します。

  3. ホスト システムでは、ブレークポイントに達し、コードの実行が停止します。

    Breakpoint 4 hit
    ECHO!EchoEvtIoRead:
    aade54c0 55              push    ebp
    
  4. 実行中のスレッドを表示するには、「!thread」と入力します。 次の例のような情報が表示されます。

    0: kd>  !thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    ...
    

    echoapp.exe のイメージ名をメモします。 これは、テスト アプリに関連付けられているスレッドを確認していることを示します。

  5. !process コマンドを使用して、このスレッドが、echoapp.exe に関連付けられているプロセスで実行されている唯一のスレッドであるかどうかを判断します。 プロセス内の実行中のスレッド番号は、!thread コマンドが表示されたのと同じスレッドです。

    0: kd> !process
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    
  6. !process 0 0 コマンドを使用して、2 つの関連プロセスのプロセス アドレスを見つけ、それらのプロセス アドレスをここに記録します。

    Cmd.exe: ____________________________________________________________

    EchoApp.exe: _______________________________________________________

    0: kd> !process 0 0 
    
    …
    
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
    …
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
    …
    

    または、!process 0 17 を使用して、すべてのプロセスに関する詳細情報を表示できます。 このコマンドからの出力は長い場合があります。 出力は、Ctrl + F キーを使用して検索できます。

  7. !process コマンドを使用して、コンピューターを実行している両方のプロセスのプロセス情報を一覧表示します。 この例に示されているアドレスではなく、!process 0 0 出力のプロセス アドレスを指定します。

    この出力例は、前に記録した cmd.exe プロセス ID を対象としています。 このプロセス ID のイメージ名は cmd.exe

    0: kd>  !process ffffe0007bbde900
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
        VadRoot ffffe0007bb8e7b0 Vads 25 Clone 0 Private 117. Modified 20. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001d8c48050
        ElapsedTime                       21:33:05.840
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         24656
        QuotaPoolUsage[NonPagedPool]      3184
        Working Set Sizes (now,min,max)  (261, 50, 345) (1044KB, 200KB, 1380KB)
        PeakWorkingSetSize                616
        VirtualSize                       2097164 Mb
        PeakVirtualSize                   2097165 Mb
        PageFaultCount                    823
        MemoryPriority                    FOREGROUND
        BasePriority                      8
        CommitCharge                      381
    
            THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
                ffffe0008096c900  ProcessObject
            Not impersonating
    ...
    

    この出力例は、前に記録した echoapp.exeプロセス ID を対象としています。

    0: kd>  !process ffffe0008096c900
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
            IRP List:
                ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
            Not impersonating
    ...
    
  8. 2 つのプロセスに関連付けられている最初のスレッド アドレスをここに記録します。

    Cmd.exe: ____________________________________________________

    EchoApp.exe: _________________________________________________

  9. 現在のスレッドに関する情報を表示するには、!Thread コマンドを使用します。

    0: kd>  !Thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    Attached Process          N/A            Image:         N/A
    ...
    

    予想どおり、現在のスレッドは echoapp.exe に関連付けられているスレッドであり、実行中の状態です。

  10. !Thread コマンド使用して、cmd.exe プロセスに関連付けられているスレッドに関する情報表示します。 前に記録したスレッド アドレスを指定します。

    0: kd> !Thread ffffe0007cf34880
    THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
        ffffe0008096c900  ProcessObject
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0007bbde900       Image:         cmd.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      4134621        Ticks: 0
    Context Switch Count      4056           IdealProcessor: 0             
    UserTime                  00:00:00.000
    KernelTime                00:00:01.421
    Win32 Start Address 0x00007ff72e9d6e20
    Stack Init ffffd0015551dc90 Current ffffd0015551d760
    Base ffffd0015551e000 Limit ffffd00155518000 Call 0
    Priority 14 BasePriority 8 UnusualBoost 3 ForegroundBoost 2 IoPriority 2 PagePriority 5
    Child-SP          RetAddr           : Args to Child                                                           : Call Site
    ffffd001`5551d7a0 fffff801`eed184fe : fffff801`eef81180 ffffe000`7cf34880 00000000`fffffffe 00000000`fffffffe : nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    ffffd001`5551d8e0 fffff801`eed17f79 : ffff03a5`ca56a3c8 000000de`b6a6e990 000000de`b6a6e990 00007ff7`d00df000 : nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    ffffd001`5551d980 fffff801`eecea340 : ffffd001`5551da18 00000000`00000000 00000000`00000000 00000000`00000388 : nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    ...
    

    このスレッドは cmd.exe に関連付けられ、待機状態です。

  11. 待機中の CMD.exe CMD.exe スレッドのスレッド アドレス 指定して、コンテキストをその待機中のスレッドに変更します。

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. k コマンドを使用して、待機中のスレッドに関連付けられているコール スタックを表示します。

    0: kd> k
      *** Stack trace for last set context - .thread/.cxr resets it
    # Child-SP          RetAddr           Call Site
    00 ffffd001`5551d7a0 fffff801`eed184fe nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    01 ffffd001`5551d8e0 fffff801`eed17f79 nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    02 ffffd001`5551d980 fffff801`eecea340 nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    03 ffffd001`5551da00 fffff801`ef02e642 nt!KeWaitForSingleObject+0x2c0 [d:\9142\minkernel\ntos\ke\wait.c @ 683]
    ...
    

    このスレッドが期待どおりに実行されていないことを示す KiCommitThreadWait などのコール スタック要素。

スレッドとプロセスの詳細については、次のリファレンスを参照してください。

IRQL、登録、WinDbg セッションの終了

このセクションでは、割り込み要求レベル (IRQL) とレジスタの内容を表示します。

保存した IRQL を表示する

IRQL は、サービス割り込みの優先順位を管理するために使用されます。 各プロセッサには、スレッドが増減できる IRQL 設定があります。 プロセッサの IRQL 設定下で発生する割り込みはマスクされ、現在の操作に干渉しません。 プロセッサの IRQL 設定より上に発生する割り込みは、現在の操作よりも優先されます。

ホスト システムでは、!irql 拡張機能は、デバッガーの中断が発生する前に、ターゲット コンピューターの現在のプロセッサに IRQL を表示します。 ターゲット コンピューターがデバッガーに侵入すると、IRQL は変更されますが、デバッガーが中断される直前に有効だった IRQL は保存され、!irql によって表示されます。

0: kd> !irql
Debugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)

レジスタを表示する

ホスト システムで、r (Registers) コマンドを使用して、現在のプロセッサ上の現在のスレッドのレジスタの内容を表示します。

0: kd> r
rax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001
rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0
rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620
 r8=000000000000003e  r9=ffffe00167a4a000 r10=000000000000001e
r11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0
r14=0000000000000001 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
nt!DbgBreakPointWithStatus:
fffff803`bb757020 cc              int     3

または、[表示]>[レジスタ] を選択してレジスタの内容を表示することもできます。 詳細については、「r (レジスタ)」を参照してください。

アセンブリ言語コードの実行やその他のシナリオでは、レジスタの内容を表示すると便利です。 アセンブリ言語の逆アセンブリの詳細については、「注釈付き x86 逆アセンブリ」および「注釈付き x64 逆アセンブリ」を参照してください。

レジスタの内容については、「x86 アーキテクチャ」と「x64 アーキテクチャ」に関するページを参照してください。

WinDbg セッションを終了する

デバッガーをアタッチしたままでターゲットで作業する場合は、ターゲット コンピューターがホスト コンピューター デバッガーへの接続を試みないように、bc * を使用してブレークポイントをクリアします。 次に、g コマンドを使用して、ターゲット コンピューターを再度実行します。

デバッグ セッションを終了するには、ホスト システムでデバッガーを中断し、qd(終了とデタッチ) コマンドを入力するか、メニューから [デバッグの停止] を選択します。

0: kd> qd

詳細については、「WinDbg でデバッグ セッションを終了する」を参照してください。

Windows デバッグ リソース

詳細については、Windows デバッグで参照してください。 これらの書籍の一部では、Windows Vista のような以前のバージョンの Windows が使用されていますが、説明されている概念はほとんどのバージョンの Windows に適用できます。

関連項目