LINQ 语法可以与调试器对象一起用于搜索和操作数据。 与使用调试器命令相比,将 LINQ 语法与 dx 命令一起使用可实现更一致的体验。 无论查看哪个调试器对象,输出和选项都是一致的。 使用 LINQ 查询可以提问"运行线程最多的前 5 个进程是什么?"等问题。

调试器对象将预计到以"Debugger"为根的命名空间中。 进程、模块、线程、堆栈、堆栈帧和局部变量都可用于 LINQ 查询。

LINQ 在概念上结构化查询语言 (SQL) 查询数据库的类。 可以使用许多 LINQ 方法搜索、筛选和分析调试数据。 使用 LINQ C# 方法语法。 有关 LINQ 和 LINQ C# 语法详细信息,请参阅在 C# 入门 LINQ 的用法

调试器支持中使用的 LINQ 使用 LINQ 的"方法语法",而不是"查询语法"。 可以在 LINQ 语言集成查询 ( 中查找有关差异的)

如下所示的 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
    

    对于我们的方案,我们还需要线程数。 由于有两个字段,因此使用 new 创建匿名类型,类似于下面用户定义的变量中所述的 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]) :基于键选择器函数联接两个序列并提取值对。 还可以指定可选的比较器方法。

    Intersect (InnerCollection, [ComparatorMethod]) : 返回集交集,这意味着出现在两个集合中每个集合中的元素。 还可以指定可选的比较器方法。

    Union (InnerCollection, [ComparatorMethod]) :返回集联合,这意味着出现在两个集合之一中的唯一元素。 还可以指定可选的比较器方法。

    数据集方法

    包含 (对象 [ComparatorMethod]) :确定序列是否包含指定的元素。 提供可选的比较器方法,每次将元素与序列中的条目进行比较时,都将调用该方法。

    Distinct ([ComparatorMethod]) :从集合中删除重复值。 每次必须比较集合中的对象时,都可以提供一个可选的比较器方法来调用该方法。

    除了 (InnerCollection,[ComparatorMethod]) :返回集差异,这意味着一个集合的元素不会出现在第二个集合中。 可指定可选的比较器方法。

    Concat (InnerCollection) :连接两个序列以形成一个序列。

    .OrderBy ( KeyProjectorMethod, [KeyComparatorMethod] ) :根据对输入集合中每个对象调用键投影方法提供的键,按升序对集合进行排序。 提供可选的比较器方法。

    .OrderByDescending ( KeyProjectorMethod, [KeyComparatorMethod] ) :根据对输入集合中每个对象调用键投影方法提供的键,按降序对集合进行排序。 提供可选的比较器方法。

    Count () :返回集合中的元素数的方法。

    Sum ([ProjectionMethod]) :计算集合中值的总和。 可以选择指定一种投影仪方法,在求和之前转换元素。

    跳过 (计数) :将元素跳过至序列中的指定位置。

    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]) :返回列表中唯一的元素 (如果集合包含多个元素,则返回) 。 如果指定了谓词,则 返回满足该谓词的单个元素 (如果多个元素满足该谓词,则函数将返回错误) 。

    自变量的签名

    所有字符串对象都将以下方法预测到它们中,以便它们可供使用:

    查询相关方法 & 属性

    .包含 ( OtherString ) :返回一个布尔值,该值指示输入字符串是否包含 OtherString。

    .EndsWith ( OtherString ) :返回一个布尔值,该值指示输入字符串是否以 OtherString 结尾。

    Length:返回字符串长度的属性。

    .StartsWith ( OtherString ) :返回一个布尔值,该值指示输入字符串是否以 OtherString 开头。

    .StartPos ( [Length] 的 子字符串) :返回从给定起始位置开始的输入字符串中的子字符串。 如果提供了可选长度,则返回的子字符串的长度为指定长度;否则 , 将转到字符串的末尾。

    .IndexOf ( OtherString ) :返回输入字符串中 OtherString 第一个匹配项的索引。

    .LastIndexOf ( OtherString ) :返回输入字符串中 OtherString 的最后一个匹配项的索引。

    格式设置方法

    .PadLeft ( TotalWidth ) :在字符串左侧添加空格,使字符串的总长度调整为指定宽度。

    .PadRight ( TotalWidth ) :在字符串右侧添加空格,使字符串的总长度调整为指定宽度。

    .删除 ( StartPos,[Length] ) :从输入字符串中删除字符,从开始位置开始指定位置。 如果提供了可选的 length 参数,将删除该字符数;否则 – 将删除字符串末尾的所有字符。

    .将 ( SearchString,ReplaceString ) :将输入字符串中每次出现的 SearchString 替换为指定的 ReplaceString。

    字符串对象投影

    除了直接投射到字符串对象上的方法外,本身具有字符串转换的任何对象还具有以下方法,使其可供使用:

    .ToDisplayString ( ) :返回 对象的字符串转换。 这是字符串转换,将在对象的 dx 调用中显示。 可以提供格式设置说明器来设置 ToDisplayString 的输出格式。 有关详细信息,请参阅调试器中的 C++ Visual Studio说明符

    以下示例演示了格式说明符的使用。

    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                          = (+) 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>)
    

    例如,若要查看具有非零问题代码的设备,请使用此命令。 这提供与"!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) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0) @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x10) != 0)
    [0x0] : SWD\PRINTENUM{2F8DBBB6-F246-4D84-BB1D-AA8761353885} [0x1] : SWD\PRINTENUM{F210BC77-55A1-4FCA-AA80-013E2B4083 78} [0x2] :SWD\PRINTENUM{07940A8E-11F4-46C3-B714-7FF9B87738F8} [0x3] : DISPLAY\Default_Monitor\61a097cd80UID5527112&&& (monitor)

    UniqueID

    dbgcmd 0:kd> dx -r1 @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x40) != 0) @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (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) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x80) != 0) @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (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) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x100) != 0) @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (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) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0) @$cursession。Devices.DeviceTree.Flatten (n => n.Children) 。其中 (n => (n.DeviceNodeObject.CapabilityFlags & 0x200) != 0)
    [0x0] : SWD\MMDEVAPI\MicrosoftGSWavetableSynth [0x1] : SWD\IP_TUNNEL_VBUS\IP_TUNNEL_DEVICE_ROOT [0x2] : SWD\PRINTENUM\PrintQueues ...

  •