共用方式為


使用 LINQ 搭配調試程序物件

LINQ 語法可以與偵錯器物件搭配使用,以搜尋及操作數據。 與使用調試程式命令相比,搭配 dx 命令使用 LINQ 語法可讓體驗更一致。 不論您要查看的調試程式對象為何,輸出和選項都一致。 LINQ 查詢可讓您詢問「執行最多線程的前 5 個進程為何?」之類的問題。

調試程式物件會投影到根目錄為 「Debugger」 的命名空間。 進程、模組、線程、堆疊、堆疊框架和局部變數全都可用於LINQ查詢。

LINQ 在概念上類似於用來查詢資料庫的結構化查詢語言 (SQL)。 您可以使用許多 LINQ 方法來搜尋、篩選和剖析偵錯數據。 使用 LINQ C# 方法語法。 如需 LINQ 和 LINQ C# 語法的詳細資訊,請參閱 C# 中的 LINQ 使用者入門

調試程序支援中使用的 LINQ 會使用 LINQ 的「方法語法」,而不是「查詢語法」。 您可以在 中找到LINQ (Language-Integrated Query) 差異的詳細數據。

LINQ 命令,例如下列命令可以搭配調試程序物件使用。 都。任何。計數。第一。扁平 化。GroupBy, 。最後。OrderBy, 。OrderByDescending, 。選取 與 。哪裡。 這些方法會遵循 C# LINQ 方法形式(盡可能接近)。

原生除錯器物件

原生調試程序物件代表調試程式環境的各種建構和行為。 調試程式物件的範例包括下列專案。

  • 會期
  • 線程/討論串
  • 程序處理/ 程序
  • 堆疊框架/堆疊框架
  • 局部變數
  • 模組/ 模組
  • 效用
  • 國家
  • 設定

您也可以使用 NatVis 搭配調試程式物件。 如需詳細資訊,請參閱 natVis 中的原生調試程序物件。 如需搭配 JavaScript 使用除錯程式物件的詳細資訊,請參閱 javaScript 延伸模組中的 原生調試程式物件。 如需使用C++和驅動程式物件的相關信息,請參閱 調試程式數據模型C++概觀

Dx 命令

如需使用 dx 命令的詳細資訊,請參閱 dx (顯示調試程序物件模型表達式)

開發 LINQ 查詢

開發 LINQ 調試程式對象查詢的其中一個方法是使用顯示的 DML 連結來探索數據模型,以先找出將在查詢中使用的調試程序物件。

在此範例中,我們想要在核心偵錯會話中顯示進程清單,以及每個進程的線程數目。

若要開始探索,我們可以使用 dx 命令來顯示最上層調試程序物件。

0: kd> dx Debugger
Debugger
    Sessions
    Settings
    State
    Utility

選取最上層主題之後,我們會判斷會話看起來最有趣,因此我們選取 DML 連結以顯示它包含 進程

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

然後,我們選取進一步查看特定程序,並看到與該程序相關聯的 執行緒 列表。 當我們針對其中一個進程選取 [線程] 時,我們會看到與該進程相關聯的所有線程都可供使用。

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
...

在我們的案例中,我們也需要線程數目。 因為有兩個字段,請使用 新的建立匿名類型,類似於 用戶定義變數中所述的 C# 匿名類型語法。

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

使用此命令時,‘dx’ 實際上不會再列印出名稱,因此請新增 -r2 (進行兩層級的遞迴)以顯示名稱和執行緒。

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』。 遞歸層級不需要指定,因為方格選項會適當地顯示數據行。 最後,將 『,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 查詢方法,而且適用於 Lambda 的參數。

例如,在調試程式中輸入下列文字(或複製並貼上)。 然後按下 TAB 鍵數次,以切換瀏覽各種可能的選項。

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

按 TAB 鍵直到 .Name 出現。 新增右括弧 “)”,然後按 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.

按下 TAB 鍵,直到 ".Length" 出現。 新增右括弧 “)”,然後按 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

用戶定義變數

使用者定義變數可以藉由在變數名稱前面加上 @$來定義。 使用者定義的變數可以指派給 dx 可以利用的任何專案,例如 Lambda、LINQ 查詢的結果等等。

您可以建立並設定用戶變數的值,如下所示。

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

函式物件 (Lambda 運算式)

許多用來查詢數據的方法都是根據在集合中跨物件重複執行使用者提供的函式的概念。 為了支持在偵錯器中查詢和操作數據的能力,dx 命令支援使用對等 C# 語法的 lambda 表達式。 Lambda 表達式是由 => 運算符的使用方式所定義,如下所示:

(參數)=>(結果)

若要查看 LINQ 與 dx 的使用方式,請嘗試這個簡單的範例,將 5 和 7 加在一起。

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

dx 命令會回應 Lambda 運算式,並顯示 12 的結果。

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

這個範例 Lambda 運算式會結合字串 「Hello」 和 「World」。

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

支援的 LINQ 語法 - 查詢方法

任何被 dx 定義為可迭代的物件(無論是原生陣列、有 NatVis 描述為容器的類型,或是調試器擴充物件)都會被映射上一系列的 LINQ(或同等 LINQ)方法。 這些查詢方法如下所述。 查詢方法自變數的簽章會列在所有查詢方法之後。

篩選方法

。其中 (PredicateMethod ):傳回新的 物件集合,其中包含輸入集合中傳回述詞方法傳回 true 的每個物件。

投影方法

Flatten([KeyProjectorMethod]):從樹形結構的容器中接受輸入,並將其平坦化為包含樹中所有元素的單一容器。 如果提供選用的按鍵投影機方法,樹狀結構會被視為密鑰的容器,這些密鑰本身是容器,而這些密鑰是由對投影方法的呼叫所決定。

。選取 [KeyProjectorMethod]:傳回新的物件集合,其中包含在輸入集合中的每個物件上呼叫投影機方法的結果。

群組方法

.GroupBy(KeyProjectorMethod, [KeyComparatorMethod]):透過呼叫鍵投射器方法來確定相同的鍵,將輸入集合中的所有物件進行分組,並返回一個新的集合。 可以提供一個選擇性的比較器方法。

Join (InnerCollection, Outer 鍵選取器方法, Inner 鍵選取器方法, Result 選取器方法, [ComparatorMethod]):根據鍵選取器方法聯結兩個序列,並提取值組。 您也可以指定一個可選的比較方法。

交集(InnerCollection, [ComparatorMethod]):傳回集合的交集,即出現在兩個集合中的共同元素。 也可以指定可選的比較器方法。

Union (InnerCollection, [ComparatorMethod]):傳回集合聯集,這表示出現在兩個集合之一中的唯一元素。 您也可以指定一個可選的比較子方法。

數據集方法

Contains (Object,[ComparatorMethod]):判斷序列是否包含指定的元素。 您可以提供一個選擇性的比較器方法,每次元素與序列中的項目進行比較時,這個方法都會被呼叫。

Distinct ([ComparatorMethod]):從集合中移除重複的值。 可以提供一個選擇性的比較器方法,以便在需要比較集合中的物件時呼叫。

Except(InnerCollection, [ComparatorMethod]):傳回集合的差異,也就是第一個集合中有而第二個集合中沒有的元素。 您可以指定可選的比較方法。

Concat (InnerCollection):串連兩個序列成為一個序列。

排序方法

.OrderBy(KeyProjectorMethod, [KeyComparatorMethod] ):根據在輸入集合中的每個物件上呼叫索引鍵投影方法所提供的索引鍵,按遞增順序對集合進行排序。 可以提供可選的比較方法。

。OrderByDescending (KeyProjectorMethod, [KeyComparatorMethod] ):根據在輸入集合中每個物件上呼叫索引鍵投影方法所提供的索引鍵,依遞減順序排序集合。 可以提供選擇性的比較器方法。

匯總方法

Count ():傳回集合中項目數的方法。

Sum ([ProjectionMethod]):計算集合中值的總和。 可以選擇性地指定投影機方法,以在總和發生之前轉換元素。

跳過方法

Skip(Count):略過序列中達到指定位置前的元素。

SkipWhile (PredicateMethod):在元素不符合條件之前,會根據述詞函式略過元素。

取用方法

Take (Count):擷取序列中直到指定位置的元素。

TakeWhile (PredicateMethod):接受以述詞函式為基礎的元素,直到元素不符合條件為止。

比較方法

SequenceEqual (InnerCollection, [ComparatorMethod]):藉由以配對方式比較元素來判斷兩個序列是否相等。 您可以指定選擇性的比較子。

錯誤處理方法

AllNonError (PredicateMethod):傳回集合中所有非錯誤元素是否符合指定條件。

FirstNonError ([PredicateMethod]):傳回集合中不是錯誤的第一個元素。

LastNonError ([PredicateMethod]):傳回集合中最後一個非錯誤的元素。

其他方法

.All(PredicateMethod):判斷對輸入集合中每個元素呼叫指定述詞方法的結果是否全為 true。

。Any (PredicateMethod):傳回在輸入集合中任何元素上呼叫指定述詞方法的結果是否為 true。

.First ( [PredicateMethod] ):傳回集合中的第一個元素。 如果傳遞選擇性謂詞,則會傳回集合中呼叫謂詞傳回 true 的第一個元素。

.Last([PredicateMethod]):傳回集合中的最後一個元素。 如果傳遞可選述詞,則返回集合中呼叫述詞返回 true 的最後一個元素。

Min([KeyProjectorMethod]):傳回集合的最小元素。 您可以指定選擇性投影機方法來投影每個方法,然後再將其與其他方法進行比較。

Max([KeyProjectorMethod]):傳回集合的最大元素。 您可以指定選擇性投影機方法來投影每個方法,然後再將其與其他方法進行比較。

Single([PredicateMethod]):從清單中返回唯一的元素(如果集合包含多個元素,則引發錯誤)。 當指定條件時,傳回滿足該條件的單一元素(如果有超過一個元素滿足條件,則函式會傳回錯誤)。

自變數的 簽章

KeyProjectorMethod: (obj => 任意鍵) 取得集合的物件,並從該對象傳回索引鍵。
KeyComparatorMethod: ((a, b) => 整數值) 接收兩個鍵並比較它們,然後返回結果:

-1 if (a < b)

0 if (a == b)

1 如果 ( a > b )

PredicateMethod:(obj => 布爾值) 從集合中選取一個物件,然後根據該物件是否符合特定準則,傳回 true 或 false。

支援的 LINQ 語法 - 字串操作

所有字串物件都會投影下列方法,使其可供使用:

查詢相關方法 & 屬性

。Contains ( OtherString ):傳回布爾值,指出輸入字串是否包含 OtherString。

。EndsWith (OtherString):傳回布爾值,指出輸入字串是否以 OtherString 結尾。

Length:傳回字串長度的屬性。

。StartsWith (OtherString ):傳回布爾值,指出輸入字串是否以 OtherString 開頭。

。子字串 (StartPos, [Length] ):傳回輸入字串內的子字串,從指定的起始位置開始。 如果提供選擇性長度,傳回的子字串將會是指定的長度;否則, 它會移至字串的結尾。

其他方法

。IndexOf (OtherString):傳回輸入字串中第一次出現 OtherString 的索引。

。LastIndexOf (OtherString):傳回輸入字串中最後一次出現的 OtherString 索引。

格式化方法

。PadLeft (TotalWidth ):視需要在字元串左邊新增空格,以將字串的總長度帶入指定的寬度。

。PadRight (TotalWidth ):視需要在字串右側新增空格,以將字串的總長度帶入指定的寬度。

:Remove(StartPos, [Length]):從輸入字串中去除字元,從指定的起始位置開始。 如果提供選擇性的 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                          = (+) Resources = (+) 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>)

例如,若要檢視具有非零問題程式代碼的裝置,請使用此命令。 這提供類似 「!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 延伸模組中的原生調試程式物件