デバッグ メッセージの読み取りとフィルター処理
DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, および KdPrintEx ルーチンは、指定した条件下でカーネル デバッガーにメッセージを送信します。 この手順により、優先度の低いメッセージをフィルターで除外できます。
Note
Microsoft Windows Server 2003 およびそれ以前のバージョンの Windows では、DbgPrint および KdPrint ルーチンは無条件にカーネル デバッガーにメッセージを送信します。 Windows Vista 以降のバージョンの Windows では、DbgPrintEx や KdPrintEx など、これらのルーチンは条件付きでメッセージを送信します。 使用している Windows のバージョンに関係なく、DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, および KdPrintEx を使用する必要があります。これらのルーチンを使用すると、メッセージの送信条件を制御できるためです。
デバッグメッセージをフィルタリングするには
デバッガーに送信するメッセージごとに、ドライバーのコードで DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, または KdPrintEx を使用します。 適切なコンポーネント名を ComponentId パラメーターに渡し、このメッセージの重大度または性質を反映する値を Level パラメーターに渡します。 メッセージ自体は、printf と同じ構文を使用して、Format パラメーターと引数パラメーターに渡されます。
適切なコンポーネント フィルター マスクの値を設定します。 各コンポーネントには異なるマスクがあります。 マスク値は、そのコンポーネントのどのメッセージが表示されるかを示します。 コンポーネント フィルター マスクは、レジストリ エディターを使用してレジストリに設定するか、カーネル デバッガーを使用してメモリに設定できます。
カーネル デバッガーをコンピューターに接続します。 ドライバーがメッセージを DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, または KdPrintEx に渡すたびに、ComponentId および Level に渡される値が、対応するコンポーネント フィルター マスクの値と比較されます。 これらの値が特定の基準を満たしている場合、メッセージはカーネル デバッガーに送信されて表示されます。 それ以外の場合、メッセージは送信されません。
Note
このページでの DbgPrintEx への参照はすべて、KdPrintEx, vDbgPrintEx, および vDbgPrintExWithPrefix に同様に適用されます。
コンポーネント名の確認
各コンポーネントには個別のフィルター マスクがあります。 これにより、デバッガーは各コンポーネントのフィルターを個別に構成できるようになります。
各コンポーネントは、コンテキストに応じてさまざまな方法で参照されます。 DbgPrintEx の ComponentId パラメーターでは、コンポーネント名に「DPFLTR_」という接頭辞と「_ID」という接尾辞が付けられます。 レジストリでは、コンポーネント フィルター マスクはコンポーネント自体と同じ名前を持ちます。 デバッガーでは、コンポーネント フィルター マスクには「Kd_」という接頭辞と「_Mask」という接尾辞が付けられます。
すべてのコンポーネント名の完全なリスト (DPFLTR_XXXX_ID 形式) は、Microsoft Windows Driver Kit (WDK) ヘッダー dpfilter.h にあります。 これらのコンポーネント名のほとんどは、Windows および Microsoft が作成したドライバー用に予約されています。
独立系ハードウェア ベンダー用に予約されているコンポーネント名が 6 つあります。 ドライバーの出力と Windows コンポーネントの出力が混在しないようにするには、次のコンポーネント名のいずれかを使用する必要があります。
コンポーネント名 | ドライバーの種類 |
---|---|
IHVビデオ | ビデオ ドライバー |
IHVAUDIO | オーディオドライバー |
IHVネットワーク | ネットワーク ドライバー |
IHVSストリーミング | カーネルストリーミングドライバー |
IHVバス | バス運転手 |
IHVドライバー | 他のタイプのドライバー |
たとえば、ビデオ ドライバーを作成している場合は、DbgPrintEx の ComponentId パラメーターとして DPFLTR_IHVVIDEO_ID を使用し、レジストリで値名 IHVVIDEO を使用し、デバッガーで Kd_IHVVIDEO_Mask を参照します。
DbgPrint および KdPrint によって送信されるすべてのメッセージは、DEFAULT コンポーネントに関連付けられます。
正しいレベルの選択
DbgPrintEx ルーチンの Level パラメータは DWORD 型です。 重要度ビットフィールドを決定するために使用されます。 Level パラメーターとこのビット フィールドの間の接続は、Level のサイズによって異なります。
Level が 0 ~ 31 の数値に等しい場合、ビット シフトとして解釈されます。 重要度ビット フィールドは値 1<< レベルに設定されます。 したがって、レベルに 0 ~ 31 の値を選択すると、ビット フィールドに 1 つのビットが設定されることになります。 Level が 0 の場合、ビット フィールドは 0x00000001 に相当し、Level が 31 の場合、ビット フィールドは 0x80000000 に相当します。
Level が 32 から 0xFFFFFFFF までの数値である場合、重要度ビット フィールドは Level 自体の値に設定されます。
したがって、ビット フィールドを 0x00004000 に設定する場合は、レベルを 0x00004000 または単に 14 として指定できます。 完全にゼロのビット フィールドを含め、特定のビット フィールド値はこのシステムでは使用できないことに注意してください。
次の定数は、レベルの値を設定するのに役立ちます。 これらは、Microsoft Windows Driver Kit (WDK) ヘッダー dpfilter.h および Windows SDK ヘッダー ntrtl.h で定義されています。
#define DPFLTR_ERROR_LEVEL 0
#define DPFLTR_WARNING_LEVEL 1
#define DPFLTR_TRACE_LEVEL 2
#define DPFLTR_INFO_LEVEL 3
#define DPFLTR_MASK 0x80000000
Level パラメーターを使用する簡単な方法の 1 つは、常に 0 ~ 31 の値を使用することです。つまり、ビット 0、1、2、3 を DPFLTR_XXXX_LEVEL によって与えられる意味で使用し、他のビットを選択した意味に使用します。
Level パラメーターを使用するもう 1 つの簡単な方法は、常に明示的なビット フィールドを使用することです。 この方法を選択した場合、値 DPFLTR_MASK とビット フィールドの OR を計算することができます。 これにより、誤って 32 未満の値を使用することがなくなります。
ドライバーに Windows のメッセージ レベルの使用方法との互換性を持たせるには、重大なエラーが発生した場合にのみ重要度ビット フィールドの最下位ビット (0x1) を設定する必要があります。 32 未満のレベル値を使用している場合、これは DPFLTR_ERROR_LEVEL に相当します。 このビットが設定されている場合、ドライバーが実行されているコンピューターに誰かがカーネル デバッガーを接続するたびに、メッセージが表示されることになります。
警告、トレース、および情報レベルは、適切な状況で使用する必要があります。 他のビットは、役立つと思われる目的に自由に使用できます。 これにより、さまざまな種類のメッセージを選択的に表示または非表示にすることができます。
DbgPrintEx および KdPrintEx によって送信されるすべてのメッセージは、レベルが DPFLTR_INFO_LEVEL に等しい DbgPrint および KdPrint メッセージと同様に動作します。 言い換えれば、これらのメッセージには重要度ビット フィールドの 3 番目のビットが設定されています。
コンポーネントフィルターマスクの設定
コンポーネント フィルター マスクを設定するには 2 つの方法があります。
コンポーネント フィルター マスクには、レジストリ キー HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter でアクセスできます。 レジストリ エディタを使用して、このキーを作成するか開きます。 このキーの下に、目的のコンポーネントの名前を大文字で含む値を作成します。 コンポーネント フィルター マスクとして使用する DWORD 値と同じ値に設定します。
カーネル デバッガがアクティブな場合、シンボルKd_XXXX_Mask に格納されているアドレスを逆参照することによって、コンポーネント フィルタ マスク値にアクセスできます。ここで、XXXX は目的のコンポーネント名です。 WinDbg または KD で dd (DWORD の表示) コマンドを使用してこのマスクの値を表示したり、ed (DWORD の入力) コマンドを使用して新しいコンポーネント フィルター マスクを入力したりできます。 シンボルが曖昧になる危険性がある場合は、このシンボルを nt!Kd_XXXX_Mask として指定するとよいでしょう。
レジストリに保存されているフィルター マスクは、起動時に有効になります。 デバッガーによって作成されたフィルター マスクはすぐに有効になり、Windows が再起動されるまで保持されます。 レジストリに設定された値はデバッガによって上書きできますが、システムが再起動されると、コンポーネント フィルタ マスクはレジストリで指定された値に戻ります。
WIN2000 と呼ばれるシステム全体のマスクもあります。 これはデフォルトでは 0x1 に等しくなりますが、他のすべてのコンポーネントと同様にレジストリまたはデバッガを通じて変更できます。 フィルタリングが実行されると、まず各コンポーネント フィルタ マスクと WIN2000 マスクの論理和が計算されます。 これは特に、マスクが一度も指定されていないコンポーネントはデフォルトで 0x1 になることを意味します。
メッセージの表示基準
DbgPrintEx がカーネル モード コードで呼び出されると、Windows は Level で指定されたメッセージ重要度ビット フィールドと ComponentId で指定されたコンポーネントのフィルター マスクを比較します。
Note
Level パラメータが 0 ~ 31 の場合、重要度ビットフィールドは 1 <<Level に等しいことを思い出してください。 ただし、レベル パラメータが 32 以上の場合、重要度ビットフィールドは単純にレベルと等しくなります。
Windows は、重要度ビット フィールドとコンポーネント フィルター マスクに対して AND 演算を実行します。 結果がゼロ以外の場合、メッセージはデバッガーに送信されます。
デバッグフィルターの例
最後の起動前に、Debug Print Filter キーに次の値を作成したとします。
IHVVIDEO、DWORD 0x2 に等しい値
IHVBUS、DWORD 0x7FF に等しい
ここで、カーネル デバッガーで次のコマンドを発行します。
kd> ed Kd_IHVVIDEO_Mask 0x8
kd> ed Kd_IHVAUDIO_Mask 0x7
この時点で、IHVVIDEO コンポーネントのフィルター マスクは 0x8、IHVAUDIO コンポーネントのフィルター マスクは 0x7、IHVBUS コンポーネントのフィルター マスクは 0x7FF になります。
ただし、これらのマスクは WIN2000 システム全体のマスク (通常は 0x1 に等しい) と自動的に論理和演算されるため、IHVVIDEO マスクは事実上 0x9 に等しくなります。 実際、フィルタ マスクがまったく設定されていないコンポーネント (IHVSTREAMING や DEFAULT など) のフィルタ マスクは 0x1 になります。
ここで、さまざまなドライバーで次の関数呼び出しが発生すると仮定します。
DbgPrintEx( DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID, 7, "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID, DPFLTR_MASK | 0x10, "Third message.\n");
DbgPrint( "Fourth message.\n");
最初のメッセージの Level パラメーターは DPFLTR_INFO_LEVEL (3) に等しいです。 これは 32 未満であるため、ビット シフトとして扱われ、重要度ビット フィールドは 0x8 になります。 この値は、有効な IHVVIDEO コンポーネント フィルター マスク 0x9 と AND 演算され、ゼロ以外の結果が得られます。 したがって、最初のメッセージがデバッガに送信されます。
2 番目のメッセージの Level パラメータは 7 です。 繰り返しますが、これはビット シフトとして処理され、重要度ビット フィールドは 0x80 になります。 次に、これと IHVAUDIO コンポーネント フィルター マスク 0x7 の AND 演算が行われ、結果は 0 になります。 したがって、2 番目のメッセージは送信されません。
3 番目のメッセージの Level パラメーターは DPFLTR_MASK | に等しいです。 0x10。 これは 31 より大きいため、重要度ビット フィールドはレベルの値、つまり 0x80000010 に設定されます。 次に、これと IHVBUS コンポーネント フィルター マスク 0x7FF の AND 演算が行われ、ゼロ以外の結果が得られます。 したがって、3 番目のメッセージがデバッガに送信されます。
4 番目のメッセージは、DbgPrintEx ではなく DbgPrint に渡されました。 Windows Server 2003 およびそれ以前のバージョンの Windows では、このルーチンに渡されるメッセージは常に送信されます。 Windows Vista 以降のバージョンの Windows では、このルーチンに渡されるメッセージには常にデフォルトのフィルターが与えられます。 重要度ビット フィールドは 1<< DPFLTR_INFO_LEVEL、つまり 0x00000008 に等しくなります。 このルーチンのコンポーネントは DEFAULT です。 DEFAULT コンポーネント フィルター マスクを設定していないため、値は 0x1 になります。 これを重要度ビット フィールドと AND 演算すると、結果は 0 になります。 したがって、4 番目のメッセージは送信されません。
DbgPrint バッファとデバッガ
DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint, または KdPrintEx ルーチンがデバッガーにメッセージを送信すると、フォーマットされた文字列が DbgPrint バッファーに送信されます。 GFlags の Buffer DbgPrint Output オプションを使用してこの表示を無効にしない限り、このバッファーの内容はデバッガー コマンド ウィンドウにすぐに表示されます。
ローカル カーネル デバッグ中、およびこの表示が無効になっているその他の場合、DbgPrint バッファの内容は、!dbgprint 拡張コマンドを使用することによってのみ表示できます。
DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint, または KdPrintEx を 1 回呼び出した場合、送信される情報は 512 バイトのみです。 512 バイトを超える出力は失われます。 DbgPrint バッファ自体は、Windows の無料ビルドでは最大 4 KB のデータを保持でき、Windows のチェック ビルドでは最大 32 KB のデータを保持できます。 Windows Server 2003 以降のバージョンの Windows では、KDbgCtrl ツールを使用して DbgPrint バッファのサイズを変更できます。 このツールは、Windows 用デバッグ ツールの一部です。
Note
チェック ビルドは、Windows 10 バージョン 1803 以前の古いバージョンの Windows で使用することができました。 Driver Verifier や GFlags などのツールを使用して、新しいバージョンの Windows のドライバー コードをチェックします。
ComponentId と Level の値が原因でメッセージがフィルターで除外された場合、そのメッセージはデバッグ接続を介して送信されません。 したがって、デバッガでこのメッセージを表示する方法はありません。