デバッガー オブジェクトでの LINQ の使用

LINQ 構文をデバッガー オブジェクトで使用すると、データを検索および操作できます。 dx コマンドで LINQ 構文を使用すると、デバッガー コマンドを使用する場合と比べてエクスペリエンスの一貫性が高くなります。 出力とオプションは、ユーザーが調べているデバッガー オブジェクトに関係なく、一貫性があります。 LINQ クエリを使用すると、"最も多くのスレッドを実行している上位 5 つのプロセスは何か?" などの質問をすることができます。

デバッガー オブジェクトは、"デバッガー" をルートとする名前空間に投影されます。 プロセス、モジュール、スレッド、スタック、スタック フレーム、およびローカル変数は、LINQ クエリですべて使用できます。

LINQ は概念的には、データベースのクエリの実行に使用される Structured Query Language (SQL) に似ています。 さまざまな LINQ メソッドを使用して、デバッグ データを検索、フィルター処理、解析できます。 LINQ C# メソッドの構文が使用されます。 LINQ と LINQ C# 構文の詳細については、「C# の LINQ の概要」を参照してください

デバッガーのサポートで使用される LINQ では、"クエリ構文" ではなく LINQ の "メソッド構文" が使用されます。 その違いの詳細については、LINQ (統合言語クエリ) を参照してください。

デバッガー オブジェクトでは、次のような LINQ コマンドを使用できます。 All、.Any、.Count、.First、.Flatten、.GroupBy、.Last、.OrderBy、.OrderByDescending、.Select、および .Where。 これらのメソッドは、(できるだけ忠実に) C# LINQ メソッド フォームに従います。

ネイティブ デバッガー オブジェクト

ネイティブ デバッガー オブジェクトは、デバッガー環境のさまざまなコンストラクトと動作を表します。 デバッガー オブジェクトの例には、次のようなものがあります。

  • Session
  • Threads/Thread
  • Processes/Process
  • Stack Frames/Stack Frame
  • Local Variables
  • Modules/Module
  • Utility
  • State
  • Settings

NatVis を使用してデバッガー オブジェクトを操作することもできます。 詳細については、「NatVis のネイティブ デバッガー オブジェクト」を参照してください。 JavaScript でのデバッガー オブジェクトの使用については、「JavaScript 拡張機能でのネイティブ デバッガー オブジェクト」を参照してください。 C++ およびドライバー オブジェクトの操作については、「デバッガー データ モデル C++ の概要」を参照してください。

Dxコマンド

ここで示す例では、dx コマンドを使用します。dx コマンドの操作の詳細については、「dx (デバッガー オブジェクト モデル式の表示)」を参照してください。

LINQ クエリの開発

LINQ デバッガー オブジェクト クエリを開発する方法の 1 つは、表示される DML リンクを使用してデータ モデルを探索し、クエリで使用されるデバッガー オブジェクトを最初に見つけることです。

この例では、カーネル デバッグ セッション内のプロセスの一覧と、そうしたプロセスのそれぞれについてスレッド数を表示します。

探索を開始するには、dx コマンドを使用して最上位のデバッガー オブジェクトを表示します。

0: kd> dx Debugger
Debugger
    Sessions
    Settings
    State
    Utility

最上位レベルのトピックを選択したら、Sessions が最も興味深く見えると判断し、DML リンクを選択して Processes が含まれていることを明らかにします。

0: kd> dx -r1 Debugger.Sessions[0]
Debugger.Sessions[0]                 : Remote KD: KdSrv:Server=@{<Local>},Trans=@{NET:Port=50005,Key=MyKey}
    Processes
    Id               : 0
    Attributes

次に、特定のプロセスを調べるためにさらに下を選択すると、そのプロセスに関連付けられている Threads が使用可能であることがわかります。 いずれかのプロセスに対して Threads を選択すると、そのプロセスに関連付けられているすべてのスレッドが使用可能になります。

0: kd> dx -r1 Debugger.Sessions[0].Processes[1428].Threads
Debugger.Sessions[0].Processes[1428].Threads
    [0x598]          : <Unable to get stack trace> [Switch To]
    [0x1220]         : <Unable to get stack trace> [Switch To]
    [0x6f8]          : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To]
    [0x128c]         : <Unable to get stack trace> [Switch To]
    [0x27e4]         : nt!KiSwapContext+0x76 (fffff806`4466a186)  [Switch To] 

これで、プロセスに関連付けられているスレッドの数を表示するために必要なデータがデバッガー オブジェクト モデルで使用できることがわかりました。

LINQ クエリを少し短くするために、このトピックで後述するシステム定義変数を使用して、現在のセッションに関連付けられているプロセスを表示します。

0: kd> dx @$cursession.Processes
@$cursession.Processes                
    [0x0]            : Idle [Switch To]
    [0x4]            : System [Switch To]
    [0x90]           : Registry [Switch To]
...

次に、select ステートメントを追加します。 最初に、[名前] フィールドを指定します。

0: kd> dx @$cursession.Processes.Select(p => p.Name)
@$cursession.Processes.Select(p => p.Name)                
    [0x0]            : Idle
    [0x4]            : System
    [0x90]           : Registry
...

このシナリオでは、スレッドの数も必要です。 2 つのフィールドがあるため、ユーザー定義変数で後述する C# の匿名型構文と同様に、new を使用して匿名型を作成します。

dx @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})

そのコマンドを使用すると、'dx' は実際に名前を出力しなくなるため、-r2 (2 レベルの再帰) を追加して Name と Threads を表示します。

dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})
@$cursession.Processes.Select(p => new {Name = p.Name, Threads = p.Threads})                
    [0x0]           
        Name             : Idle
        Threads         
    [0x4]           
        Name             : System
        Threads         
    [0x90]          
        Name             : Registry
        Threads       

この時点で、プロセスの名前とスレッドの一覧が表示されます。 ThreadCount を表示するには、Count() メソッドを使用します。

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()})                
    [0x0]           
        Name             : Idle
        ThreadCount      : 0x4
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0x90]          
        Name             : Registry
        ThreadCount      : 0x4
...

スレッドの数が多いプロセスを確認するには、OrderByDescending を使用して、スレッド数で一覧を並べ替えます。

0: kd> dx -r2 @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)
@$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount)                
    [0x4]           
        Name             : System
        ThreadCount      : 0xe7
    [0xa38]         
        Name             : svchost.exe
        ThreadCount      : 0x45
    [0x884]         
        Name             : MemCompression
        ThreadCount      : 0x3e

書式設定されたグリッドでレンダリングするには、「-r2」を「-g」に変更します。 グリッド オプションでは列が適切に表示されるため、再帰のレベルを指定する必要はありません。 最後に、出力の 10 進値に「,d」という書式指定子を追加します。

0: kd> dx -g @$cursession.Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count()}).OrderByDescending(p => p.ThreadCount),d
===========================================================================================
=            = Name                                                         = ThreadCount =
===========================================================================================
= [4]        - System                                                       - 231         =
= [2616]     - svchost.exe                                                  - 69          =
= [2180]     - MemCompression                                               - 62          =
= [968]      - explorer.exe                                                 - 61          =

デバッガー オブジェクトの例

この例は、最も多くのスレッドを実行している上位 5 つのプロセスを示しています。

0: kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5
Debugger.Sessions.First().Processes.Select(p => new { Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.ThreadCount),5 

: 
    [0x4]            : 
        Name             : <Unknown Image>
        ThreadCount      : 0x73
    [0x708]          : 
        Name             : explorer.exe
        ThreadCount      : 0x2d
    [0x37c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x2c
    [0x6b0]          : 
        Name             : MsMpEng.exe
        ThreadCount      : 0x22
    [0x57c]          : 
        Name             : svchost.exe
        ThreadCount      : 0x15
    [...]       

この例は、物理デバイス オブジェクトのドライバーの名前でグループ化した、プラグ アンド プレイ デバイス ツリー内のデバイスを示しています。 すべての出力が表示されるわけではありません。

kd> dx -r2 Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString())
Debugger.Sessions.First().Devices.DeviceTree.Flatten(n => n.Children).GroupBy(n => n.PhysicalDeviceObject->Driver->DriverName.ToDisplayString()) 

: 
    ["\"\\Driver\\PnpManager\""] : 
        [0x0]            : HTREE\ROOT\0
        [0x1]            : ROOT\volmgr\0000 (volmgr)
        [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
        [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
        [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
         ...  

Dx コマンド タブのオート コンプリート

コンテキスト TAB キーのオート コンプリートは LINQ クエリ メソッドを認識し、ラムダのパラメーターに対して機能します。

たとえば、次のテキストをデバッガーに入力します (またはコピーして貼り付けます)。 その後、Tab キーを数回押して、潜在的な入力補完を繰り返し行います。

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.

".Name" が表示されるまで Tab キーを押します。 終わりかっこの ")" を追加し、Enter キーを押してコマンドを実行します。

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name) : 
    [0x274]          : 
        Name             : winlogon.exe
        ThreadCount      : 0x4
    [0x204]          : 
        Name             : wininit.exe
        ThreadCount      : 0x2
    [0x6c4]          : 
        Name             : taskhostex.exe
        ThreadCount      : 0x8
         ...  

この例は、キー コンパレーター メソッドを使用した入力補完を示します。 キーは文字列であるため、代入では文字列メソッドが表示されます。

dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.

".Length" が表示されるまで Tab キーを押します。 終わりかっこの ")" を追加し、Enter キーを押してコマンドを実行します。

kd> dx -r2 Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length)
Debugger.Sessions.First().Processes.Select(p => new {Name = p.Name, ThreadCount = p.Threads.Count() }).OrderByDescending(p => p.Name, (a, b) => a.Length) : 
    [0x544]          : 
        Name             : spoolsv.exe
        ThreadCount      : 0xc
    [0x4d4]          : 
        Name             : svchost.exe
        ThreadCount      : 0xa
    [0x438]          : 
        Name             : svchost.exe

ユーザー定義変数

ユーザー定義変数は、変数名の前に $@ を付けることで定義できます。 ユーザー定義変数は、ラムダや、LINQ クエリの結果など、dx が利用できるあらゆるものに割り当てることができます。

次のようにユーザー変数の値を作成して設定できます。

kd> dx @$String1="Test String"

定義されたユーザー変数は、Debugger.State.UserVariables または $@vars を使用して表示できます。

kd> dx Debugger.State.UserVariables
Debugger.State.UserVariables : 
    mySessionVar     : 
    String1          : Test String

.Remove を使用して変数を削除できます。

kd> dx @$vars.Remove("String1")

この例は、Debugger.Sesssions を参照するユーザー変数を定義する方法を示しています。

kd> dx @$mySessionVar = Debugger.Sessions

その後、次に示すように、ユーザー定義変数を使用できます。

kd> dx -r2 @$mySessionVar 
@$mySessionVar   : 
    [0x0]            : Remote KD: KdSrv:Server=@{<Local>},Trans=@{COM:Port=\\.\com3,Baud=115200,Timeout=4000}
        Processes        : 
        Devices     

システム定義変数

次のシステム定義変数は、任意の LINQ dx クエリで使用できます。

  • $@cursession - 現在のセッション

  • $@curprocess - 現在のプロセス

  • $@curthread - 現在のスレッド

この例は、システム定義変数の使用方法を示しています。

kd> dx @$curprocess.Threads.Count()
@$curprocess.Threads.Count() : 0x4
kd> dx -r1 @$curprocess.Threads
@$curprocess.Threads : 
    [0x4adc]         : 
    [0x1ee8]         : 
    [0x51c8]         : 
    [0x62d8]         : 
     ...

ユーザー定義変数 - 匿名型

この動的オブジェクトの作成は、C# の匿名型構文 (new { ... }) を使用して行われます。 匿名型の詳細については、「匿名型 (C# プログラミング ガイド)」を参照してください。 この例では、整数の文字列値を持つ匿名型を作成します。

kd> dx -r1 new { MyInt = 42, MyString = "Hello World" }
new { MyInt = 42, MyString = "Hello World" } : 
    MyInt            : 42
    MyString         : Hello World

関数オブジェクト (ラムダ式)

データのクエリに使用されるメソッドの多くは、コレクション内のオブジェクト間でユーザー指定の関数を繰り返し実行するという概念に基づいています。 デバッガーでデータのクエリと操作を行う機能をサポートするために、dx コマンドは同等の C# 構文を使用するラムダ式をサポートします。 ラムダ式は、=> 演算子の使用法によって次のように定義されます。

(引数) => (結果)

dx で LINQ がどのように使われるかを確認するため、この簡単な例を使って 5 と 7 を足してみてください。

kd> dx ((x, y) => (x + y))(5, 7) 

dx コマンドはラムダ式をエコーバックし、12 という結果を表示します。

((x, y) => (x + y))(5, 7)  : 12

次の例のラムダ式では、"Hello" と "World" という文字列を結合します。

kd> dx ((x, y) => (x + y))("Hello", "World")
((x, y) => (x + y))("Hello", "World") : HelloWorld

サポートされている LINQ 構文 - クエリ メソッド

dx が反復可能として定義するオブジェクト (ネイティブ配列、コンテナーとして記述された NatVis を持つ型、デバッガー拡張オブジェクトなど) には、一連の LINQ (または LINQ と同等の) メソッドが投影されます。 それらのクエリ メソッドについて、以下に説明します。 クエリ メソッドに対する引数のシグネチャは、すべてのクエリ メソッドの後に一覧表示されます。

フィルター処理メソッド

.Where ( PredicateMethod ): 述語メソッドが true を返した入力コレクション内のすべてのオブジェクトを含むオブジェクトの新しいコレクションを返します。

プロジェクション メソッド

.Flatten ( [KeyProjectorMethod] ): 複数のコンテナーからなる入力コンテナー (ツリー) を取得し、ツリー内のすべての要素を含む 1 つのコンテナーにフラット化します。 オプションのキー プロジェクター メソッドが指定されている場合、ツリーは、複数のキー (キー自体がコンテナーである) をまとめたコンテナーと見なされます。そして、それらのキーはプロジェクション メソッドの呼び出しによって決定されます。

.Select ( KeyProjectorMethod ): 入力コレクション内のすべてのオブジェクトでプロジェクター メソッドを呼び出した結果を含む、オブジェクトの新しいコレクションを返します。

グループ化メソッド

.GroupBy ( KeyProjectorMethod, [KeyComparatorMethod] ): キー プロジェクター メソッドの呼び出しによって決定されたものと同じキーを持つ入力コレクション内のすべてのオブジェクトをグループ化して、複数のコレクションをまとめた新しいコレクションを返します。 オプションのコンパレーター メソッドを指定できます。

Join (InnerCollection、外部キー セレクター メソッド、内部キー セレクター メソッド、結果セレクター メソッド、[ComparatorMethod]):キー セレクター関数に基づいて 2 つのシーケンスを結合し、値のペアを抽出します。 オプションのコンパレーター メソッドも指定できます。

Intersect (InnerCollection, [ComparatorMethod]): 積集合 (2 つのコレクションのそれぞれに出現する要素) を返します。 オプションのコンパレーター メソッドも指定できます。

Union (InnerCollection, [ComparatorMethod]): 和集合 (2 つのコレクションのどちらかに出現する一意の要素) を返します。 オプションのコンパレーター メソッドも指定できます。

データ設定メソッド

Contains (Object, [ComparatorMethod]): 指定した要素がシーケンスに含まれているかどうかを判断します。 要素がシーケンス内のエントリと比較されるたびに呼び出されるオプションのコンパレーター メソッドを指定できます。

Distinct ([ComparatorMethod]): コレクションから重複する値を削除します。 コレクション内のオブジェクトを比較する必要があるたびに呼び出されるよう、オプションのコンパレーター メソッドを指定できます。

Except (InnerCollection, [ComparatorMethod]): 差集合 (一方のコレクションにだけ存在し、もう一方のコレクションには出現しない要素) を返します。 オプションのコンパレーター メソッドを指定できます。

Concat (InnerCollection): 2 つのシーケンスを連結して 1 つのシーケンスを形成します。

並べ替えメソッド

.OrderBy ( KeyProjectorMethod, [KeyComparatorMethod] ): 入力コレクション内のすべてのオブジェクトに対してキー プロジェクション メソッドを呼び出し、指定されたキーに従ってコレクションを昇順で並べ替えます。 オプションのコンパレーター メソッドを指定できます。

.OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod] ): 入力コレクション内のすべてのオブジェクトに対してキー プロジェクション メソッドを呼び出し、指定されたキーに従ってコレクションを降順で並べ替えます。 オプションのコンパレーター メソッドを指定できます。

集計メソッド

Count (): コレクション内の要素の数を返すメソッド。

Sum ([ProjectionMethod]): コレクション内の値の合計を計算します。 必要に応じて、合計が行われる前に要素を変換するプロジェクター メソッドを指定できます。

スキップ メソッド

Skip (Count): シーケンス内の指定した位置まで要素をスキップします。

SkipWhile (PredicateMethod): 述語関数に基づき、条件を満たさない要素が出現する位置まで要素をスキップします。

取得メソッド

Take (Count): シーケンス内の指定した位置までの要素を取得します。

TakeWhile (PredicateMethod): 述語関数に基づき、条件を満たさない要素が出現する位置まで要素を取得します。

比較メソッド

SequenceEqual (InnerCollection, [ComparatorMethod]): ペア方式で要素を比較し、2 つのシーケンスが等しいかどうかを判断します。 オプションのコンパレーターを指定できます。

エラー処理メソッド

AllNonError (PredicateMethod): コレクションのエラー以外の全要素が指定された条件を満たすかどうかを返します。

FirstNonError ([PredicateMethod]): エラーではない、コレクションの最初の要素を返します。

LastNonError ([PredicateMethod]): エラーではない、コレクションの最後の要素を返します。

その他のメソッド

.All ( PredicateMethod ): 入力コレクション内のすべての要素に対して、指定された述語メソッドを呼び出した結果が true かどうかを返します。

.Any ( PredicateMethod ): 入力コレクション内のオプションの要素に対して、指定された述語メソッドを呼び出した結果が true かどうかを返します。

.First ( [PredicateMethod] ): コレクション内の最初の要素を返します。 オプションの述語が渡された場合は、述語の呼び出しで true が返されるコレクション内の最初の要素を返します。

.Last ( [PredicateMethod] ): コレクション内の最後の要素を返します。 オプションの述語が渡された場合は、述語の呼び出しで true が返されるコレクション内の最後の要素を返します。

Min([KeyProjectorMethod]): コレクションの最小要素を返します。 オプションのプロジェクター メソッドを指定し、他のメソッドとの比較前に各メソッドを投影することができます。

Max([KeyProjectorMethod]): コレクションの最大要素を返します。 オプションのプロジェクター メソッドを指定し、他のメソッドとの比較前に各メソッドを投影することができます。

Single([PredicateMethod]: リストから唯一の要素 (または、コレクションに複数の要素が含まれている場合はエラー) を返します。 述語が指定されている場合は、その述語を満たす 1 つの要素を返します (複数の要素がその述語を満たす場合、関数は代わりにエラーを返します)。

引数のシグネチャ

KeyProjectorMethod : ( obj => 任意のキー ) コレクションのオブジェクトを取得し、そのオブジェクトからキーを返します。
KeyComparatorMethod: ( (a, b) => 整数値 ) 2 つのキーを取得し、比較して次を返します。

-1 if ( a < b )

0 if ( a == b)

1 if ( a > b )

PredicateMethod: ( obj => ブール値 ) コレクションのオブジェクトを取得し、そのオブジェクトが特定の条件を満たしているかどうかに基づいて true または false を返します。

サポートされている LINQ 構文 - 文字列操作

すべての文字列オブジェクトには次のメソッドが投影され、使用できるようになっています。

クエリに関連するメソッドとプロパティ

.Contains ( OtherString ): 入力文字列に OtherString が含まれているかどうかを示すブール値を返します。

.EndsWith ( OtherString ): 入力文字列が OtherString で終わるかどうかを示すブール値を返します。

Length: 文字列の長さを返すプロパティ。

.StartsWith ( OtherString ): 入力文字列が OtherString で始まるかどうかを示すブール値を返します。

.Substring ( StartPos, [Length] ): 指定された開始位置から始まる入力文字列内の部分文字列を返します。 任意の長さを指定した場合、返される部分文字列は指定された長さになります。それ以外の場合は、文字列の末尾に移動します。

その他のメソッド

.IndexOf ( OtherString ): 入力文字列内で最初に出現する OtherString のインデックスを返します。

.LastIndexOf ( OtherString ): 入力文字列内で最後に出現する OtherString のインデックスを返します。

書式設定メソッド

.PadLeft ( TotalWidth ): 文字列の長さの合計を指定した幅にするために、必要に応じて文字列の左側にスペースを追加します。

.PadRight ( TotalWidth ): 文字列の長さの合計を指定した幅にするために、必要に応じて文字列の右側にスペースを追加します。

.Remove ( StartPos, [Length] ): 指定した開始位置から始まる入力文字列から文字を削除します。 任意の長さパラメーターを指定すると、その文字数は削除されます。それ以外の場合は、文字列の末尾までの文字がすべて削除されます。

.Replace ( SearchString, ReplaceString ): 入力文字列内で出現するすべての SearchString を、指定された ReplaceString に置き換えます。

文字列オブジェクトのプロジェクション

文字列変換を備えているオブジェクトは、文字列オブジェクトに直接投影されるメソッドのほかに、次のメソッドを自己投影して使用できるようにします。

.ToDisplayString ( ): オブジェクトの文字列変換を返します。 これは、オブジェクトの dx 呼び出しで表示される文字列変換です。 ToDisplayString の出力を書式設定する書式指定子を指定できます。 詳細については、「Visual Studio デバッガーでの C++ の書式指定子」を参照してください

書式指定子の使用例を次に示します。

kd> dx (10).ToDisplayString("d")
(10).ToDisplayString("d") : 10

kd> dx (10).ToDisplayString("x")
(10).ToDisplayString("x") : 0xa

kd> dx (10).ToDisplayString("o")
(10).ToDisplayString("o") : 012

kd> dx (10).ToDisplayString("b") 
(10).ToDisplayString("b")  : 0y1010

kd> dx ("some wchar string here").ToDisplayString("su") 
("some wchar string here").ToDisplayString("su")  : "some wchar string here"

kd> dx ("some wchar string here").ToDisplayString("sub") 
("some wchar string here").ToDisplayString("sub")  : some wchar string here

プラグ アンド プレイのデバッグの例

このセクションでは、LINQ クエリで使用される組み込みデバッガー オブジェクトを使用して、プラグ アンド プレイ オブジェクトをデバッグする方法について説明します。

すべてのデバイスを表示する

デバイス ツリーで Flatten を使用して、すべてのデバイスを表示します。

 1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
    [0x5]            : ROOT\spaceport\0000 (spaceport)
    [0x6]            : ROOT\KDNIC\0000 (kdnic)
    [0x7]            : ROOT\UMBUS\0000 (umbus)
    [0x8]            : ROOT\ACPI_HAL\0000
...

グリッドの表示

他の dx コマンドと同様に、コマンドの実行後にコマンドを選択して長押し (または右クリック) し、[グリッドとして表示] を選択するか、コマンドに "-g" を追加すると、結果のグリッド ビューを取得できます。

# 0: kd> dx -g @$cursession.Devices.DeviceTree.Flatten(n => n.Children)
=====================================================================================================================================================================================================================================================================================================================
# =                                                              = (+) DeviceNodeObject = InstancePath                                                 = ServiceName               = (+) PhysicalDeviceObject                                    = State                          = (+) Resoures = (+) Children       =
=====================================================================================================================================================================================================================================================================================================================
= [0x0] : HTREE\ROOT\0                                         - {...}                - HTREE\ROOT\0                                                 -                           - 0xffffb6075614be40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x1] : ROOT\volmgr\0000 (volmgr)                            - {...}                - ROOT\volmgr\0000                                             - volmgr                    - 0xffffb607561fbe40 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x2] : ROOT\BasicDisplay\0000 (BasicDisplay)                - {...}                - ROOT\BasicDisplay\0000                                       - BasicDisplay              - 0xffffb607560739b0 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
= [0x3] : ROOT\CompositeBus\0000 (CompositeBus)                - {...}                - ROOT\CompositeBus\0000                                       - CompositeBus              - 0xffffb607561f9060 : Device for "\Driver\PnpManager"        - DeviceNodeStarted (776)        - {...}        - [object Object]    =
...

状態別にデバイスを表示する

Where を使用して、特定のデバイスの状態を指定します。

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State <operator> <state number>)

たとえば、DeviceNodeStarted 状態のデバイスを表示するには、次のコマンドを使用します。

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State == 776)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ROOT\volmgr\0000 (volmgr)
    [0x2]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x3]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x4]            : ROOT\vdrvroot\0000 (vdrvroot)
...

未起動デバイスを表示する

DeviceNodeStarted 状態ではないデバイスを表示するには、次のコマンドを使用します。

1: kd>  dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.State != 776)                
    [0x0]            : ACPI\PNP0C01\1
    [0x1]            : ACPI\PNP0000\4&215d0f95&0
    [0x2]            : ACPI\PNP0200\4&215d0f95&0
    [0x3]            : ACPI\PNP0100\4&215d0f95&0
    [0x4]            : ACPI\PNP0800\4&215d0f95&0
    [0x5]            : ACPI\PNP0C04\4&215d0f95&0
    [0x6]            : ACPI\PNP0700\4&215d0f95&0 (fdc)
    [0x7]            : ACPI\PNP0C02\1
    [0x8]            : ACPI\PNP0C02\2

問題コード別にデバイスを表示する

特定の問題コードを持つデバイスを表示するには、DeviceNodeObject.Problem オブジェクトを使用します。

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem <operator> <problemCode>)

たとえば、0 以外の問題コードを持つデバイスを表示するには、次のコマンドを使用します。 これにより、"!devnode 0 21" と同様の情報が提供されます。

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem != 0)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

問題のないデバイスをすべて表示する

問題のないデバイスをすべて表示するには、次のコマンドを使用します。

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0)                
    [0x0]            : ROOT\volmgr\0000 (volmgr)
    [0x1]            : ROOT\BasicDisplay\0000 (BasicDisplay)
    [0x2]            : ROOT\CompositeBus\0000 (CompositeBus)
    [0x3]            : ROOT\vdrvroot\0000 (vdrvroot)
...

特定の問題があるデバイスをすべて表示する

0x16 という問題の状態を持つデバイスを表示するには、次のコマンドを使用します。

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.DeviceNodeObject.Problem == 0x16)                
    [0x0]            : HTREE\ROOT\0
    [0x1]            : ACPI\PNP0700\4&215d0f95&0 (fdc)

関数ドライバー別にデバイスを表示する

関数ドライバー別にデバイスを表示するには、次のコマンドを使用します。

dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName <operator> <service name>)

atapi などの特定の関数ドライバーを使用してデバイスを表示するには、次のコマンドを使用します。

1: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.ServiceName == "atapi")                
    [0x0]            : PCIIDE\IDEChannel\4&10bf2f88&0&0 (atapi)
    [0x1]            : PCIIDE\IDEChannel\4&10bf2f88&0&1 (atapi)

ブート開始ドライバーの一覧の表示

ブート開始ドライバーとして読み込まれた winload の一覧を表示するには、ユーザーが LoaderBlock にアクセスできる状況にあり、LoaderBlock が存在する十分に早い段階である必要があります。 たとえば、nt!IopInitializeBootDrivers 中など。 このコンテキストで停止するようにブレークポイントを設定できます。

1: kd> g
Breakpoint 0 hit
nt!IopInitializeBootDrivers:
8225c634 8bff            mov     edi,edi

?? コマンド を使用してブート ドライバー構造を表示します。

1: kd> ?? LoaderBlock->BootDriverListHead
struct _LIST_ENTRY
 [ 0x808c9960 - 0x808c8728 ]
   +0x000 Flink            : 0x808c9960 _LIST_ENTRY [ 0x808c93e8 - 0x808a2e18 ]
   +0x004 Blink            : 0x808c8728 _LIST_ENTRY [ 0x808a2e18 - 0x808c8de0 ]

Debugger.Utility.Collections.FromListEntry デバッガー オブジェクトを使用し、nt!_LIST_ENTRY 構造体の開始アドレスを使用してデータを表示します。

1: kd> dx Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")
Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")                
    [0x0]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x1]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x2]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x3]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x4]            [Type: _BOOT_DRIVER_LIST_ENTRY]
    [0x5]            [Type: _BOOT_DRIVER_LIST_ENTRY]
...

-g オプションを使用して、データのグリッド ビューを作成します。

dx -r1 -g Debugger.Utility.Collections.FromListEntry(*(nt!_LIST_ENTRY *)0x808c9960, "nt!_BOOT_DRIVER_LIST_ENTRY", "Link")

機能別にデバイスを表示する

DeviceNodeObject.CapabilityFlags オブジェクトを使用して、機能別にデバイスを表示します。

dx -r1 @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & <flag>) != 0)

次の表は、一般的なデバイス機能フラグを持つ dx コマンドの使用方法をまとめたものです。

リムーバブル

dbgcmd 0: kd> dx -r1 $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0) $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0)
[0x0] : SWD\PRINTENUM{2F8DBBB6-F246-4D84-BB1D-AA8761353885} [0x1] : SWD\PRINTENUM{F210BC77-55A1-4FCA-AA80-013E2B408378} [0x2] : SWD\PRINTENUM{07940A8E-11F4-46C3-B714-7FF9B87738F8} [0x3] : DISPLAY\Default_Monitor\6&1a097cd8&0&UID5527112 (monitor)

UniqueID

dbgcmd 0: kd> dx -r1 $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0) $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

SilentInstall

dbgcmd 0: kd> dx -r1 $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0) $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : ROOT\volmgr\0000 (volmgr) [0x2] : ROOT\spaceport\0000 (spaceport) ...

RawDeviceOk

dbgcmd 0: kd> dx -r1 $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0) $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0)
[0x0] : HTREE\ROOT\0 [0x1] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x2] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT ...

SurpriseRemovalOK

dbgcmd 0: kd> dx -r1 $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0) $@cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0)
[0x0] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x1] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT [0x2] : SWD\PRINTENUM\PrintQueues ...

CapabilityFlags の詳細については、DEVICE_CAPABILITIES を参照してください。

参照

dx (デバッガー オブジェクト モデル式の表示)

NatVis のネイティブ デバッガー オブジェクト

JavaScript 拡張機能のネイティブ デバッガー オブジェクト