Windows ドライバーのデバッグのステップ バイ ステップ ラボ (エコー カーネル モード)
このラボでは、WinDbg カーネル デバッガーについて説明します。 WinDbg を使用して、エコー カーネル モードのサンプル ドライバー コードをデバッグします。
ラボの目的
このラボには、デバッグ ツールの導入、一般的なデバッグ コマンドの指導、ブレークポイントの使用の説明、デバッグ拡張機能の使用方法を示す演習が含まれています。
このラボでは、ライブ カーネル デバッグ接続を使用して、次のアクションを確認します。
- Windows デバッガー コマンドを使用する
- 標準コマンド (呼び出し履歴、変数、スレッド、IRQL) を使用する
- 高度なドライバー デバッグ コマンド (!コマンド) を使用する
- シンボルを使用する
- ライブ デバッグでブレークポイントを設定する
- 呼び出し履歴を表示する
- プラグ アンド プレイ デバイス ツリーを表示する
- スレッドとプロセスのコンテキストを操作する
ユーザー モードとカーネル モードのデバッグ
Windows デバッガーを使用する場合は、次の 2 種類のデバッグを実行できます。
ユーザー モード - アプリケーションとサブシステムは、ユーザー モードでコンピューター上で実行されます。 ユーザー モードで実行されるプロセスは、独自の仮想アドレス空間内で実行されます。 システム ハードウェア、使用のために割り当てられていないメモリ、システムの整合性を損なう可能性があるシステムの他の部分など、システムの多くの部分に直接アクセスすることは制限されています。 ユーザー モードで実行されるプロセスは、システムや他のユーザー モード プロセスから効果的に分離されるため、これらのリソースに干渉することはできません。
カーネル モード - オペレーティング システムと特権プログラムはカーネル モードで実行されます。 カーネル モード コードには、システムの任意の部分にアクセスするためのアクセス許可があります。 これは、ユーザー モード コードのように制限されません。 ユーザー モードまたはカーネル モードで実行されている他のプロセスの任意の部分にアクセスできます。 コア OS 機能の大部分と多くのハードウェア デバイス ドライバーは、カーネル モードで実行されます。
この演習では、ユーザー モードとカーネル モードの両方のデバッグ中に頻繁に使用されるデバッグ コマンドについて説明します。 この演習では、カーネル モードデバッグに使用されるデバッグ拡張機能 ( !コマンドとも呼ばれます) についても説明します。
ラボのセットアップ
ラボを完了するには、次のハードウェアが必要です。
- Windows 10を実行しているノート PC またはデスクトップ コンピューター (ホスト)
- Windows 10を実行している 2 台目のノート PC またはデスクトップ コンピューター (ターゲット)
- 2 台のコンピューターを接続するためのネットワーク ハブまたはルーターとネットワーク ケーブル
- シンボル ファイルをダウンロードするためのインターネットへのアクセス
ラボを完了するには、次のソフトウェアが必要です。
- Visual Studio
- Windows 10 用 Windows ソフトウェア開発キット (SDK)
- windows Driver Kit (WDK) for Windows 10
- Windows 10用のサンプル エコー ドライバー
ラボには、次のセクションがあります。
- カーネル モードの WinDbg セッションに接続する
- カーネル モードのデバッグ コマンドと手法
- KMDF エコー ドライバーをダウンロードしてビルドする
- ターゲット システムにエコー ドライバーのサンプルをインストールする
- WinDbg を使用してドライバーに関する情報を表示する
- デバイス ツリー情報プラグ アンド プレイ表示する
- ブレークポイントとソース コードを操作する
- 変数と呼び出し履歴を表示する
- プロセスとスレッドを表示する
- IRQL、レジスタ、WinDbg セッションの終了
- Windows デバッグ リソース
カーネル モードの WinDbg セッションに接続する
このセクションでは、ホストおよびターゲット システムでネットワーク デバッグを構成します。
このラボのコンピューターは、カーネル デバッグにイーサネット ネットワーク接続を使用するように構成する必要があります。
このラボでは、2 台のコンピューターを使用します。 Windows デバッガーは ホスト システムで実行され、カーネル モード ドライバー フレームワーク (KMDF) エコー ドライバーは ターゲット システムで実行されます。
2 台のコンピューターを接続するには、ネットワーク ハブまたはルーターとネットワーク ケーブルを使用します。
カーネル モード アプリケーションを操作し、WinDbg を使用するには、KDNET over Ethernet トランスポートを使用することをお勧めします。 イーサネット トランスポート プロトコルの使用方法については、「 WinDbg の概要 (カーネル モード)」を参照してください。 ターゲット コンピューターのセットアップの詳細については、「 手動でドライバーを展開するためのコンピューターの準備 」および 「KDNET ネットワーク カーネルのデバッグを自動的に設定する」を参照してください。
イーサネットを使用してカーネル モード デバッグを構成する
ターゲット システムでカーネル モード デバッグを有効にするには:
ホスト システムで、コマンド プロンプト ウィンドウを開き、「 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 . . . . . . . . . :
ホスト システムの IP アドレス ________
ターゲット システムで、コマンド プロンプト ウィンドウを開き、 コマンドを
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 セキュリティ機能を一時的に中断することが必要になる場合があります。 テストが完了したら、これらのセキュリティ機能を再度有効にします。 セキュリティ機能が無効になっている場合は、テスト コンピューターを適切に管理します。
ターゲット コンピューターで、管理者としてコマンド プロンプト ウィンドウを開きます。 デバッグを有効にするには、次のコマンドを入力します。
bcdedit /set {default} DEBUG YES
次のコマンドを入力して、テスト署名を有効にします。
bcdedit /set TESTSIGNING ON
このコマンドを入力して、ホスト システムの IP アドレスを設定します。 表示される IP アドレスではなく、前に記録したホスト システムの IP アドレスを使用します。
bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
警告
接続のセキュリティを強化し、ランダム クライアント デバッガー接続要求のリスクを減らすには、自動生成されたランダム キーを使用します。 詳細については、「 KDNET ネットワーク カーネルのデバッグを自動的に設定する」を参照してください。
の値が正しく設定されていることを確認するには、次のコマンドを
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 Driver Kit (WDK) の x64 バージョンの WinDbg.exe を使用します。 既定の WinDbg ディレクトリに変更します。既定の場所を次に示します。
cd C:\Program Files(x86)\Windows Kits\10\Debuggers\x64
このラボでは、両方のコンピューターがターゲットとホストの両方で 64 ビット バージョンの Windows を実行することを前提としています。 そうでない場合は、ターゲットが実行するのと同じ ビット 数のツールをホスト上で実行することをお勧めします。 たとえば、ターゲットが 32 ビット Windows を実行している場合は、ホストで 32 ビット バージョンのデバッガーを実行します。 詳細については、「32 ビットまたは 64 ビット デバッグ ツールの選択」を参照してください。
次のコマンドを使用して、リモート ユーザー デバッグで WinDbg を開きます。 キーとポートの値は、ターゲット コンピューターで BCDEdit を使用して前に設定した値と一致します。
WinDbg –k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
ターゲット システムを再起動します。
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) を使用してテキストが表示され、より多くの情報をすばやく収集するために選択できます。
ホスト システムで、WinDBg で Ctrl + Scroll Lock を使用して、ターゲット システムで実行されているコードに分割します。 ターゲット システムが応答するまでに時間がかかる場合があります。
[デバッガー コマンド] ウィンドウで DML を有効にするには、次のコマンドを入力します。
0: kd> .prefer_dml 1 DML versions of commands on by default
参照コマンド ヘルプには、 コマンドを
.hh
使用してアクセスできます。 次のコマンドを入力して、 のコマンド リファレンス ヘルプを.prefer_dml
表示します。0: kd> .hh .prefer_dml
デバッガー ヘルプ ファイルには、 コマンドのヘルプが
.prefer_dml
表示されます。ターゲット システムの詳細なバージョン情報を表示するには、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
正しいカーネル モード プロセスを使用していることを確認するには、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 ...
省略された出力は"..." で示されます。このラボでは。
特定のモジュールに関する詳細情報を要求するには、 (詳細) オプションを
v
使用します。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 サンプル オーディオ ドライバーをダウンロードしてビルドするには:
GitHub から KMDF Echo サンプルをダウンロードして抽出します。
サンプルについては、こちらをご確認ください。
すべての Windows ドライバー サンプルを参照します。
KMDF Echo サンプルは、 全般 フォルダーにあります。
1 つの zip ファイルでドライバーのサンプルをダウンロードする: ドライバーのサンプル
zip ファイルをローカル ハード ドライブにダウンロードします。
zip ファイルを選択して長押しするか右クリックし、[ すべて抽出] を選択します。 新しいフォルダーを指定するか、既存のフォルダーを参照して抽出されたファイルを格納します。 たとえば、ファイルを抽出する新しいフォルダーとして C:\DriverSamples\ を指定できます。
ファイルが抽出されたら、次のサブフォルダーに移動します: C:\DriverSamples\general\echo\kmdf
Microsoft Visual Studio で[ ファイルを>開く>プロジェクト/ソリューション... ] を選択し、抽出されたファイルを含むフォルダー ( C:\DriverSamples\general\echo\kmdf など) に移動します。 kmdfecho ソリューション ファイルをダブルクリックして開きます。
Visual Studio で、ソリューション エクスプローラーを見つけます。 このウィンドウがまだ開いていない場合は、[表示] メニューから [ソリューション エクスプローラー] を選択します。 ソリューション エクスプローラーでは、3 つのプロジェクトを含む 1 つのソリューションを確認できます。
サンプルの構成とプラットフォームを設定します。 ソリューション エクスプローラーで、ソリューション 'kmdfecho' (3 つのプロジェクト) を選択して長押しするか右クリックし、[Configuration Manager] を選択します。 構成とプラットフォームの設定が 3 つのプロジェクトで同じであることを確認します。 既定では、構成は Win10 デバッグに設定され、プラットフォームはすべてのプロジェクトで Win64 に設定されます。 1 つのプロジェクトに対して構成またはプラットフォームを変更する場合は、残りの 3 つのプロジェクトに対して同じ変更を行います。
ドライバー サンプルは、既存のドライバーと重複しない値を使用するように変更する必要があります。 Windows にインストールされている既存の実際のドライバーと共存する一意のドライバー サンプルを作成する方法については、「 サンプル コードから運用ドライバーへ - サンプルの変更点 」を参照してください。
ランタイム ライブラリを設定します。 エコー ドライバーのプロパティ ページを開き、 C/C++>コード生成を見つけます。 [ランタイム ライブラリ] を [マルチスレッド デバッグ (/MTd)] に変更します。 ビルド オプションの詳細については、「 /MD、/MT、/LD (Run-Time ライブラリを使用する)」を参照してください。
ドライバーのプロパティで、[ ドライバー署名の署名>モード ] が [テスト 署名] に設定されていることを確認します。
Visual Studio で、[Build Build Solution]\(ソリューションのビルド\>) を選択します。
ビルド ウィンドウには、3 つのプロジェクトすべてのビルドが成功したことを示すメッセージが表示されます。
ヒント
ビルド エラー メッセージが表示された場合は、ビルド エラー番号を使用して修正を決定します。 たとえば、 MSBuild エラー MSB8040 では、spectre 軽減ライブラリを操作する方法について説明します。
エクスプローラーで、サンプルの抽出されたファイルを含むフォルダーに移動します。 たとえば、前に指定したフォルダーの場合は、 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 ドライバーと通信するコマンド プロンプト実行可能テスト ファイル。 USB サム ドライブを見つけるか、ネットワーク共有を設定して、ビルドされたドライバー ファイルとテスト EchoApp をホストからターゲット システムにコピーします。
次のセクションでは、ターゲット システムにコードをコピーし、ドライバーをインストールしてテストします。
ターゲット システムに KMDF エコー ドライバー サンプルをインストールする
このセクションでは、DevCon ツールを使用してエコー サンプル ドライバーをインストールします。
ドライバーをインストールするコンピューターは、 ターゲット コンピューター または テスト コンピューターと呼ばれます。 通常、このコンピューターは、ドライバー パッケージを開発してビルドするコンピューターとは別です。 ドライバーを開発およびビルドするコンピューターを ホスト コンピューターと呼びます。
ドライバー パッケージをターゲット コンピューターに移動し、ドライバーをインストールするプロセスは、ドライバーの 展開 と呼ばれます。
テスト署名済みドライバーを展開する前に、テスト署名を有効にしてターゲット コンピューターを準備します。 また、WDK インストールで DevCon ツールを見つけて、ターゲット システムにコピーする必要もあります。
ターゲット システムにドライバーをインストールするには、次の手順を実行します。
ターゲット システムで、テスト署名されたドライバーを有効にします。
[Windows の設定] を開きます。
[ 更新とセキュリティ] で、[回復] を選択 します。
[ 高度なスタートアップ] で、[ 今すぐ再起動] を選択します。
コンピューターが再起動したら、[ スタートアップ オプション] を選択します。 [Windows 10で、[トラブルシューティング>] [詳細オプション>] [スタートアップ設定] の順に選択し、[再起動] を選択します。
F7 キーを押して [ ドライバー署名の適用を無効にする] を選択 します。
対象のコンピューターを再起動します。
ホスト システムで、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
テスト ドライバーが署名されていないドライバーであることを示すダイアログ ボックスが表示されます。 [かまわず続行] を選択して続行します。
ヒント
インストールに問題がある場合は、次のファイルで詳細を確認してください。 %windir%\inf\setupapi.dev.log
サンプル ドライバーが正常にインストールされたら、テストする準備ができました。
ターゲット コンピューターのコマンド プロンプト ウィンドウで、「devmgmt」と入力して、デバイス マネージャーを開きます。 デバイス マネージャーで、[表示] メニューの [デバイスの種類] を選択します。デバイス ツリーで、[サンプル デバイス] ノードで [Sample WDF Echo Driver]\(サンプル 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 エコー サンプル ドライバーに関する情報を表示します。
ドライバーに関する情報を表示するには:
ホスト システムでデバッガーを閉じた場合は、管理者コマンド プロンプト ウィンドウで次のコマンドを使用して、デバッガーをもう一度開きます。
WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
Ctrl + Break (スクロール ロック) を使用して、ターゲット システムで実行されているコードに分割します。
WinDbg 環境で Microsoft シンボル サーバーへのシンボル パスを設定するには、 コマンドを
.symfix
使用します。0: kd> .symfix
ローカル シンボルを使用するローカル シンボルの場所を追加するには、 を使用してパスを追加し、 を使用
.sympath+
します.reload /f
。0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf 0: kd> .reload /f
force オプションを指定した
/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
デバッガーのコマンド領域に次のコマンドを入力して、エコー ドライバーに関する情報を表示します。
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」を参照してください。
このラボは前に設定
prefer_dml
したため、出力の一部の要素は、選択できるホット リンクです。 デバッグ出力で [ すべてのグローバル シンボルを参照] リンクを選択すると、文字 "a" で始まる項目シンボルに関する情報が表示されます。0: kd> x /D Echo!a*
エコー サンプルには文字 "a" で始まるシンボルが含まれていないため、「」と入力
x ECHO!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 (シンボルを調べる)」を参照してください。
拡張機能には
!lmi
、モジュールに関する詳細情報が表示されます。 「!lmi echo
」と入力します。 出力は、次の例に示すテキストのようになります。0: kd> !lmi echo Loaded Module Info: [echo] Module: ECHO Base Address: fffff8010bf94000 Image Name: ECHO.sys …
拡張機能を使用して、
!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 ...
既定のデバッグ ビット マスクを変更して、ターゲット システムからのすべてのデバッグ メッセージがデバッガーに表示されるようにするには、次のように入力します。
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」を参照してください。
ホスト システムで、プラグ アンド プレイ デバイス ツリー内のすべてのデバイス ノードを表示するには、 コマンドを
!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… …
Ctrl + F キーを押して生成された出力を検索し、デバイス ドライバーの名前である echo を検索します。
エコー デバイス ドライバーを読み込む必要があります。 コマンドを
!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) …
前のコマンドに表示される出力には、ドライバーの実行中のインスタンスに関連付けられている 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.
コマンドに
!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
この図は、より複雑なデバイス ノード ツリーを示しています。
より複雑なドライバー スタックの詳細については、「 ドライバー スタック 」および「 デバイス ノードとデバイス スタック」を参照してください。
ブレークポイントとソース コードを操作する
このセクションでは、ブレークポイントを設定し、カーネル モードのソース コードをシングルステップで実行します。
コードをステップ実行し、変数の値をリアルタイムで確認できるようにするには、ブレークポイントを有効にして、ソース コードへのパスを設定します。
ブレークポイントは、特定のコード行でのコード実行を停止します。 コードの特定のセクションをデバッグするには、そのポイントからコードを順を追って進めます。
デバッグ コマンドを使用してブレークポイントを設定するには、次 b
のいずれかのコマンドを使用します。
command | 説明 |
---|---|
bp |
アクティブになっているモジュールがアンロードされるまでアクティブなブレークポイントを設定します。 |
bu |
モジュールがアンロードされたときに未解決のブレークポイントを設定し、モジュールの再読み込み時に再度有効にします。 |
bm |
シンボルのブレークポイントを設定します。 このコマンドは、 または bp を適切に使用bu し、ワイルドカード (* ) を使用して、クラス内のすべてのメソッドと同様に、一致するすべてのシンボルにブレークポイントを設定できるようにします。 |
詳細については、「 WinDbg でのソース コードのデバッグ」を参照してください。
ホスト システムで、WinDbg UI を使用して、現在の WinDbg セッションで デバッグ>ソース モード が有効になっていることを確認します。
次のコマンドを入力して、ソース パスにローカル コードの場所を追加します。
.srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
次のコマンドを入力して、ローカル シンボルの場所をシンボル パスに追加します。
.sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
コマンドを
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 …
出力は、エコー ドライバーの メソッドが
ECHO!EchoEvtDeviceAdd
であることをDeviceAdd
示しています。または、ソース コードを確認して、ブレークポイントの関数名を見つけます。
ドライバーの名前を使用して コマンドを使用してブレークポイント
bm
を設定し、その後に関数名 (例:AddDevice
) を設定します。ブレークポイントは感嘆符で区切って設定します。 このラボでは、 を使用AddDevice
して、読み込まれているドライバーを監視します。0: kd> bm ECHO!EchoEvtDeviceAdd 1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
、 などの
<module>!<symbol>
<class>::<method>
'<file.cpp>:<line number>'
変数の設定と組み合わせてさまざまな構文を使用したり、何度<condition> <#>
もスキップしたりすることができます。 詳細については、「 WinDbg およびその他の Windows デバッガーの条件付きブレークポイント」を参照してください。現在のブレークポイントを一覧表示して、コマンドを入力
bl
してブレークポイントが設定されたことを確認します。0: kd> bl 1 e fffff801`0bf9b1c0 0001 (0001) ECHO!EchoEvtDeviceAdd
次に示す出力の "e" は、ブレークポイント番号 1 の起動が有効になっていることを示しています。
(go) コマンドを入力して、ターゲット システムでのコード実行を
g
再起動します。ターゲット システムの Windows で、アイコンを使用するか、mmc devmgmt.msc と入力してデバイス マネージャーを開きます。 デバイス マネージャーで、[サンプル] ノードを展開します。
KMDF エコー ドライバー エントリを長押しするか右クリックし、メニューから [無効] を選択します。
KMDF エコー ドライバー エントリをもう一度選択して長押しするか右クリックし、メニューから [有効にする ] を選択します。
ホスト システムで、ドライバーが有効になっていると、 AddDevice デバッグ ブレークポイントが起動します。 ターゲット システムでのドライバー コードの実行は停止する必要があります。 ブレークポイントにヒットすると、 AddDevice ルーチンの開始時に実行を停止する必要があります。 debug コマンドの出力に が表示されます
Breakpoint 1 hit
。コマンドを入力するか、AddDevice ルーチンの次の
p
終わりに達するまで F10 キーを押して、コードを 1 行ずつステップ実行します。 次に示すように、中かっこ文字 (}
) が強調表示されています。
次のセクションでは、DeviceAdd コードが実行された後の変数の状態を確認します。
次のコマンドを使用して、既存のブレークポイントを変更できます。
command | 説明 |
---|---|
bl |
ブレークポイントを一覧表示します。 |
bc |
リストからブレークポイントをクリアします。 すべてのブレークポイントをクリアするには、 を使用 bc * します。 |
bd |
ブレークポイントを無効にします。 すべてのブレークポイントを無効にするには、 を使用 bd * します。 |
be |
ブレークポイントを有効にします。 すべてのブレークポイントを有効にするには、 を使用 be * します。 |
または、WinDbg UI でブレークポイントを変更することもできます。
メモリの場所にアクセスしたときに発生するブレークポイントを設定することもできます。 (アクセス時に ba
中断) コマンドを使用し、次の構文を使用します。
ba <access> <size> <address> {options}
オプション | 説明 |
---|---|
e |
execute: CPU がアドレスから命令をフェッチする場合 |
r |
読み取り/書き込み: 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)。 このコマンドは、呼び出しの実行が呼び出されたルーチンに入る点を除いて、ステップオーバーに似ています。
- ステップ アウト (Shift + F11)。 このコマンドにより、呼び出し履歴内の現在のルーチンまたは現在の場所との間で実行が実行され、終了します。 このコマンドは、ルーチンが十分に見られた場合に便利です。
詳細については、「 WinDbg でのソース コードのデバッグ」を参照してください。
変数と呼び出し履歴を表示する
このセクションでは、変数と呼び出し履歴に関する情報を表示します。
このラボでは、前に説明したプロセスを使用して AddDevice ルーチンで停止していることを前提としています。 ここに示す出力を表示するには、必要に応じて、前述の手順を繰り返します。
ホスト システムで変数を表示するには、ローカルメニュー項目の表示>を使用してローカル変数を表示します。
グローバル変数アドレスの場所を見つけるには、「」と入力 ? <variable name>
します。
特定のフレームのすべてのローカル変数の名前と値を表示するには、次のコマンドを dv
入力します。
0: kd> dv
Driver = 0x00001fff`7ff9c838
DeviceInit = 0xffffd001`51978190
status = 0n0
呼び出し履歴は、プログラム カウンターの現在の場所に至った関数呼び出しのチェーンです。 呼び出し履歴の最上位関数は現在の関数で、次の関数は現在の関数を呼び出した関数です。
呼び出し履歴を表示するには、 コマンドを k*
使用します。
command | 説明 |
---|---|
kb |
スタックと最初の 3 つのパラメーターを表示します。 |
kp |
スタックとパラメーターの完全な一覧を表示します。 |
kn |
スタックの横にフレーム情報を表示できます。 |
ホスト システムで、呼び出し履歴を使用できるようにする場合は、[呼び出し履歴の表示>] を選択して表示します。 ウィンドウの上部にある列を選択して、追加情報の表示を切り替えます。
中断状態の
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) が、後でエコー DeviceAdd
ドライバー関数を呼び出したドライバー フレームワーク コード (WDF) を呼び出したプラグ アンド プレイ コード (PnP) に呼び出されたことを示しています。
プロセスとスレッドを表示する
このセクションでは、カーネル モードで実行されているプロセスとスレッドに関する情報を表示します。
プロセス
!プロセス デバッガー拡張機能を使用して、プロセス情報を表示または設定できます。 ブレークポイントを設定して、サウンドの再生時に使用されるプロセスを調べます。
ホスト システムで、 コマンドを
dv
入力して、ルーチンに関連付けられているロケール変数をEchoEvtIo
調べます。0: kd> dv ECHO!EchoEvtIo* ECHO!EchoEvtIoQueueContextDestroy ECHO!EchoEvtIoWrite ECHO!EchoEvtIoRead
を使用
bc *
して、前のブレークポイントをクリアします。0: kd> bc *
次のコマンドを使用して、ルーチンに
EchoEvtIo
シンボル ブレークポイントを設定します。0: kd> bm ECHO!EchoEvtIo* 2: aade5490 @!”ECHO!EchoEvtIoQueueContextDestroy” 3: aade55d0 @!”ECHO!EchoEvtIoWrite” 4: aade54c0 @!”ECHO!EchoEvtIoRead”
ブレークポイントを一覧表示して、ブレークポイントが正しく設定されていることを確認します。
0: kd> bl 1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197] 0001 (0001) ECHO!EchoEvtIoQueueContextDestroy ...
「」と入力
g
して、コードの実行を再開します。0: kd> g
ターゲット システムで、ターゲット システムで
EchoApp.exe
ドライバー テスト プログラムを実行します。ホスト システムでは、テスト アプリを実行すると、ドライバーの I/O ルーチンが呼び出されます。 この呼び出しによりブレークポイントが起動し、ターゲット システムでのドライバー コードの実行が停止します。
Breakpoint 2 hit ECHO!EchoEvtIoWrite: fffff801`0bf95810 4c89442418 mov qword ptr [rsp+18h],r8
コマンドを使用して、
!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」を参照してください。
!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 ...
このラボの後半で使用 するechoapp.exe に関連付けられているプロセス ID を記録します。 後で使用するために、Ctrl + C キーを押してアドレスをコピー バッファーにコピーすることもできます。
_____(echoapp.exe プロセス アドレス)
デバッガーに必要に応じて を入力
g
し、echoapp.exeの実行 が 完了するまでコードを前方に実行します。 読み取りおよび書き込みイベントのブレークポイントに何度もヒットします。 echoapp.exeが完了したら、Ctrl + ScrLk (Ctrl + Break) を押してデバッガーに中断します。コマンドを
!process
使用して、別のプロセスを実行していることを確認します。 ここに示す出力では、Image 値が System のプロセスは 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 が実行されていたことを示しています。
コマンドを
!process
使用して、前に記録した echoapp.exe に関連付けられているプロセス ID を確認します。 この例 で示した プロセス アドレスの例ではなく、前に記録したechoapp.exeプロセス アドレスを指定します。0: kd> !process ffffe0007e6a7780 TYPE mismatch for process object at 82a9acc0
echoapp.exe プロセスが実行されなくなったため、プロセス オブジェクトは使用できなくなります。
Threads
スレッドを表示および設定するコマンドは、プロセスのコマンドと似ています。 !thread コマンドを使用してスレッドを表示します。 現在のスレッドを設定するには、.thread を使用します。
ホスト システムで、デバッガーに「」と入力
g
して、ターゲット システムでのコード実行を再開します。ターゲット システムで、EchoApp.exe ドライバー テスト プログラムを実行します。
ホスト システムでは、ブレークポイントがヒットし、コードの実行が停止します。
Breakpoint 4 hit ECHO!EchoEvtIoRead: aade54c0 55 push ebp
実行中のスレッドを表示するには、「 !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メモします。 これは、テスト アプリに関連付けられているスレッドを確認していることを示します。
コマンドを使用して、
!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
コマンドを
!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 キーを使用して検索できます。コマンドを使用して、
!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 ...
2 つのプロセスに関連付けられている最初のスレッド アドレスをここに記録します。
Cmd.exe: _______
EchoApp.exe: _______
コマンドを使用して、
!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 に関連付けられているスレッドであり、実行中の状態です。
コマンドを使用して、
!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 に関連付けられて、待機状態です。
待機しているスレッドのスレッド アドレス CMD.exe 指定して、コンテキストをその待機スレッドに変更します。
0: kd> .Thread ffffe0007cf34880 Implicit thread is now ffffe000`7cf34880
コマンドを
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 (Registers)」を参照してください。
レジスタの内容を表示すると、アセンブリ言語コードの実行やその他のシナリオでステップ実行するときに役立ちます。 アセンブリ言語の逆アセンブリの詳細については、「 注釈付き x86 逆アセンブリ 」および「 注釈付き x64 逆アセンブリ」を参照してください。
レジスタの内容については、 x86 アーキテクチャと x64 アーキテクチャ に関 するページを参照してください。
WinDbg セッションを終了する
デバッガーをアタッチしたまま、ターゲットで作業する場合は、 を使用して bc *
ブレークポイントをクリアし、ターゲット コンピューターがホスト コンピューター デバッガーへの接続を試みないようにします。 次に、 コマンドを g
使用して、ターゲット コンピューターをもう一度実行します。
デバッグ セッションを終了するには、ホスト システムでデバッガーに割り込み、(Quit and Detach) コマンドを qd
入力するか、メニューから [ デバッグの停止 ] を選択します。
0: kd> qd
詳細については、「 WinDbg でデバッグ セッションを終了する」を参照してください。
Windows デバッグ リソース
詳細については、Windows デバッグに関するページを参照してください。 これらの書籍の一部では、Windows Vista などの以前のバージョンの Windows を使用していますが、説明されている概念はほとんどのバージョンの Windows に適用できます。
書籍
- Advanced Windows Debugging(Mario Hewardt、Daniel Pravat 著)
- Windows デバッグの内部: Tarik Soulami による Windows® のデバッグとトレース戦略の実用的なガイド
- Windows Internals by Pavel Yosifovich、Alex Ionescu、Mark Russinovich、David ソロモン
ビデオ
トレーニング ベンダー