使用 LINQ 搭配調試程序物件
LINQ 語法可以搭配調試程序物件使用,以搜尋及操作數據。 使用 LINQ 語法搭配 dx 命令,相較於使用調試程式命令,可提供更一致的體驗。 不論您要查看哪一個調試程式對象,輸出和選項都一致。 LINQ 查詢可讓您詢問問題,例如「執行最多線程的前 5 個進程為何?」。
調試程式物件會投影到根目錄在 「調試程式」的命名空間中。 進程、模組、線程、堆疊、堆疊框架和局部變數全都可用於LINQ查詢。
LINQ 在概念上類似於用來查詢資料庫的 結構化查詢語言 (SQL) (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 命令的詳細資訊,請參閱 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 鍵直到 ”[名稱] 隨即出現。 新增右括弧 「) 」,然後按 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 鍵直到 ”[長度] 隨即出現。 新增右括弧 「) 」,然後按 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
您可以使用 移除變數。刪除。
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# 匿名類型語法 (新的 { ... } 來完成) 。 如需匿名類型的詳細資訊,請參閱 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 的每個物件。
投影方法
。扁平化 ( [KeyProjectorMethod] ) :接受容器的輸入容器 (樹狀結構) ,並將它壓平合併成具有樹狀結構中每個元素的單一容器。 如果提供選擇性的按鍵投影機方法,樹狀結構會被視為密鑰的容器,這些密鑰本身是容器,而且這些密鑰是由對投影方法的呼叫所決定。
。選取 [ ( KeyProjectorMethod ) :傳回新的 物件集合,其中包含在輸入集合中的每個物件上呼叫投影機方法的結果。
群組方法
。GroupBy ( KeyProjectorMethod, [KeyComparatorMethod] ) :藉由將輸入集合中的所有物件分組為與呼叫按鍵投影機方法所決定的相同索引鍵,以傳回新的集合集合集合。 您可以提供選擇性的比較子方法。
聯結 (InnerCollection、外部索引鍵選取器方法、內部索引鍵選取器方法、結果選取器方法[ComparatorMethod]) :根據索引鍵選取器函式聯結兩個序列,並擷取值的配對。 您也可以指定選擇性比較子方法。
交集 (InnerCollection, [ComparatorMethod]) :傳回集合交集,這表示出現在兩個集合中每個集合中的專案。 您也可以指定選擇性比較子方法。
Union (InnerCollection, [ComparatorMethod]) :傳回集合聯集,這表示出現在兩個集合之一中的唯一元素。 您也可以指定選擇性比較子方法。
數據集方法
包含 (物件 [ComparatorMethod]) :判斷序列是否包含指定的專案。 您可以提供選擇性比較子方法,每當專案與序列中的項目進行比較時,就會呼叫此方法。
Distinct ([ComparatorMethod]) :從集合中移除重複的值。 您可以提供選擇性的比較子方法,以便每次必須比較集合中的物件時呼叫。
除了 innerCollection ([ComparatorMethod]) :傳回集合差異,這表示未出現在第二個集合中的一個集合元素。 您可以指定選擇性比較子方法。
Concat (InnerCollection) :串連兩個序列以形成一個序列。
排序方法
。OrderBy ( KeyProjectorMethod, [KeyComparatorMethod] ) :根據輸入集合中每個物件上呼叫索引鍵投影方法所提供的索引鍵,以遞增順序排序集合。 您可以提供選擇性的比較子方法。
。OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod] ) :根據輸入集合中每個物件呼叫索引鍵投影方法所提供的索引鍵,以遞減順序排序集合。 您可以提供選擇性的比較子方法。
匯總方法
Count () :傳回集合中項目數目的方法。
Sum ([ProjectionMethod]) :計算集合中值的總和。 可以選擇性地指定投影機方法,以在總和發生之前轉換元素。
Skip 方法
略過 (Count) :略過序列中指定位置的專案。
SkipWhile (PredicateMethod) :除非元素不符合條件,否則會略過以述詞函式為基礎的元素。
Take 方法
取得 (計數) :將元素佔用到序列中指定的位置。
TakeWhile (PredicateMethod) :採用以述詞函式為基礎的元素,直到元素不符合條件為止。
比較方法
SequenceEqual (InnerCollection,[ComparatorMethod]) :藉由以成對方式比較元素,判斷兩個序列是否相等。 您可以指定選擇性比較子。
錯誤處理方法
AllNonError (PredicateMethod) :傳回集合的所有非錯誤專案是否符合指定的條件。
FirstNonError ([PredicateMethod]) :傳回不是錯誤的集合的第一個專案。
LastNonError ([PredicateMethod]) :傳回不是錯誤的集合的最後一個專案。
其他方法
。所有 ( PredicateMethod ) :傳回在輸入集合中每個元素上呼叫指定述詞方法的結果是否為 true。
。任何 ( PredicateMethod ) :傳回在輸入集合中任何專案上呼叫指定述詞方法的結果是否為 true。
。第一個 ( [PredicateMethod] ) :傳回集合中的第一個專案。 如果傳遞選擇性述詞,則會傳回集合中呼叫述詞傳回 true 的第一個專案。
。上次 ( [PredicateMethod] ) :傳回集合中的最後一個專案。 如果傳遞選擇性述詞,則會傳回集合中呼叫述詞傳回 true 的最後一個專案。
Min ([KeyProjectorMethod]) :傳回集合的最小元素。 您可以指定選擇性投影機方法來投影每個方法,再與其他方法進行比較。
Max ([KeyProjectorMethod]) :傳回集合的最大元素。 您可以指定選擇性投影機方法來投影每個方法,再與其他方法進行比較。
單一 ([PredicateMethod]) :傳回清單中唯一 (的專案,如果集合包含一個以上的專案) ,則傳回錯誤。 如果指定述詞,則會傳回滿足該述詞的單一元素,如果有多個元素滿足該述詞 (,則函式會傳回錯誤,而不是) 。
自變數的簽章
KeyProjectorMethod : ( obj => 任意索引鍵 ) | 取得集合的物件,並從該對象傳回索引鍵。 |
KeyComparatorMethod: ( (a、b) => 整數值 ) | 接受兩個索引鍵並比較它們傳回: ( b ) ,則為 < -1 如果 ( a == b) ,則為 0 ( b ) > |
PredicateMethod: ( obj => 布爾值 ) | 取得集合的物件,並根據該物件是否符合特定準則傳回 true 或 false。 |
支援的 LINQ 語法 - 字串操作
所有字串物件都有下列投影到其中的方法,讓它們可供使用:
查詢相關方法 & 屬性
。包含 OtherString ) ( :傳回布爾值,指出輸入字串是否包含 OtherString。
。EndsWith ( OtherString ) :傳回布爾值,指出輸入字串是否以 OtherString 結尾。
Length:傳回字串長度的屬性。
。StartsWith ( OtherString ) :傳回布爾值,指出輸入字串是否以 OtherString 開頭。
。Substring ( StartPos, [Length] ) :傳回輸入字串內的子字元串,從指定的起始位置開始。 如果提供選擇性長度,傳回的子字串將會是指定的長度;否則,它會移至字串結尾。
其他方法
。IndexOf ( OtherString ) :傳回輸入字串內第一次出現 OtherString 的索引。
。LastIndexOf ( OtherString ) :傳回輸入字串內最後一次出現的 OtherString 索引。
格式化方法
。PadLeft ( TotalWidth ) :視需要在字串左側新增空格,以將字串的總長度帶入指定的寬度。
。PadRight ( TotalWidth ) :視需要在字串右側新增空格,以將字串的總長度帶入指定的寬度。
。拿掉 startPos、[Length] ) ( :從輸入字元串中移除字元,從指定起始位置開始。 如果提供選擇性長度參數,則會移除該數目的字元數;否則,將會移除字串結尾的所有字元。
。取代 ( SearchString、ReplaceString ) :以指定的 ReplaceString 取代輸入字串內出現的每個 SearchString。
字串物件投影
除了直接投影到字串物件的方法之外,任何本身具有字串轉換的物件都有下列投影到它的方法,讓它方法可供使用:
。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查詢使用的內建調試程序物件如何用來偵錯即插即用物件。
檢視所有裝置
使用裝置樹狀結構上的 [扁平化 ] 來檢視所有裝置。
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 命令。
卸除式 |
|
UniqueID |
|
SilentInstall |
|
RawDeviceOk |
|
SurpriseRemovalOK |
|
如需 CapabilityFlags 的詳細資訊,請參閱 DEVICE_CAPABILITIES。