调试通用驱动程序
来源:互联网 发布:哭 知乎 编辑:程序博客网 时间:2024/06/05 06:36
调试通用驱动程序 - 分步(Echo 内核模式)
本实验中引入了 WinDbg 内核调试器。 WinDbg 用于调试 Echo 内核模式的示例驱动程序代码。
实验目标
本实验包含以下练习:引入调试工具、介绍常见调试命令、阐述断点的用法,以及演示调试扩展的用法。
在本实验中,使用实时内核调试连接,以了解以下内容:
- 使用 Windows 调试器命令
- 使用标准命令(调用堆栈、变量、线程、IRQL)
- 使用高级驱动程序调试命令 (!commands)
- 使用符号
- 在实时调试中设置断点
- 查看调用堆栈
- 显示即插即用设备树
- 处理线程和进程上下文
用户模式 - 应用程序和子系统在用户模式下的计算机上运行。用户模式下运行的进程将在其虚拟地址空间内执行此操作。限制这些进程获得对系统许多部分的直接访问权限,包括系统硬件、未被分配使用的内存和系统中可能有损系统整体性的其他部分。因为在用户模式下运行的进程将有效地与系统和其他用户模式进程隔离开来,所以它们不会干扰这些资源。
内核模式 - 内核模式是一种操作系统和特权程序在其中运行的处理器访问模式。内核模式代码有权访问系统的任何部分,且不像用户模式代码那样受到限制。它能够获得对运行在用户模式或内核模式中的任何其他进程的任何部分的访问权限。 许多核心操作系统功能和硬件设备驱动器均可在内核模式下运行。
本实验将重点介绍内核模式调试,因为它是用于调试多种设备驱动程序的方法。
此次练习将介绍用户模式和内核模式调试期间常用的调试命令。该练习还将介绍内核模式调试所使用的调试扩展(有时称为“!commands”)。
实验设置
你将需要以下硬件来完成该实验。
- 一台运行 Windows 10 的台式机(主机)
- 一台运行 Windows 10 的台式机(目标计算机)
- 一根网络交叉电缆或一个网络集线器以及多根网络电缆,用于连接这两台电脑
- 对 Internet 的访问权限,以下载符号文件
你将需要以下软件来完成此实验。
- Windows 10 SDK
- Windows 10 WDK
- Visual Studio 2015
- Windows 10 的 Echo 驱动程序示例
本实验包括以下十一个部分。
- 第 1 部分:连接到内核模式 WinDbg 会话
- 第 2 部分:内核模式调试命令和技巧
- 第 3 部分:下载和生成 KMDF 通用 Echo 驱动程序
- 第 4 部分:在目标计算机系统上安装 KMDF Echo 驱动程序示例
- 第 5 部分:使用 WinDbg 显示驱动程序相关信息
- 第 6 部分:显示即插即用设备树的相关信息
- 第 7 部分:使用断点和源代码
- 第 8 部分:查看变量和调用堆栈
- 第 9 部分:显示进程和线程
- 第 10 部分:IRQL、寄存器和结束 WinDbg 会话
- 第 11 部分:Windows 调试资源
第 1 部分:连接到内核模式 WinDbg 会话
在第 1 部分中,你将在主机和目标计算机系统上配置网络调试。
在本实验中,电脑需配置为使用以太网网络连接,以供进行内核调试。
本实验使用两台电脑。Windows 调试器在“主机”系统上运行,而 KMDF Echo 驱动程序在“目标计算机”系统上运行。
图示左侧的“主机”通过交叉以太网电缆连接到右侧的“目标计算机”。
本实验中的步骤假设你使用的是网络交叉电缆,不过如果你直接将主机和目标计算机插入网络集线器中,也可进行该实验。
为了与内核模式应用程序配合使用以及使用 Windbg,建议使用 KDNET over Ethernet 传输。有关如何使用以太网传输协议的信息,请参阅 WinDbg 入门(内核模式)。有关设置目标计算机的详细信息,请参阅准备用于手动部署驱动程序的计算机和通过网络电缆手动设置内核模式调试。
使用交叉以太网电缆配置内核模式调试
按照后续步骤,在目标计算机系统上启用内核模式调试。
<- 在主机系统上
- 1. 在主机系统上打开命令提示符,并键入 ipconfig 以确定其 IP 地址。复制
C:\>ipconfigWindows IP ConfigurationEthernet adapter Ethernet: Connection-specific DNS Suffix . : Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b%3 Autoconfiguration IPv4 Address. . : 169.182.1.1 Subnet Mask . . . . . . . . . . . : 255.255.0.0 Default Gateway . . . . . . . . . :
2. 记录主机系统的 IP 地址:______________________________________
-> 在目标计算机系统上
3. 在目标计算机系统上打开命令提示符,并使用 ping 命令确定这两个系统之间的网络连接性。用你之前记录的主机计算机系统的 IP 地址来替代示例输出中所示的地址。
复制C:\> ping 169.182.1.1Pinging 169.182.1.1 with 32 bytes of data:Reply from 169.182.1.1: bytes=32 time=1ms TTL=255Reply from 169.182.1.1: bytes=32 time<1ms TTL=255Reply from 169.182.1.1: bytes=32 time<1ms TTL=255Reply from 169.182.1.1: bytes=32 time<1ms TTL=255Ping statistics for 169.182.1.1: Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),Approximate round trip times in milli-seconds: Minimum = 0ms, Maximum = 1ms, Average = 0ms
通过完成以下步骤,在目标计算机系统上启用内核模式调试。
- 1. 在目标计算机上,以管理员身份打开“命令提示符”窗口。输入此命令以启动调试。复制
C:\> bcdedit /set {default} DEBUG YES
- 2. 键入此命令以启用测试签名。复制
C:\> bcdedit /set TESTSIGNING ON
- 3. 键入以下命令以设置主机系统的 IP 地址。使用你之前记录的主机系统的 IP 地址,而非示例中所示的地址。复制
C:\> bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:1.2.3.4
- 4. 键入此命令以确认 dbgsettings 均已正确设置。复制
C:\> bcdedit /dbgsettingskey 1.2.3.4debugtype NEThostip 169.168.1.1port 50000dhcp YesThe operation completed successfully.
防火墙和调试器
如果你收到一条来自防火墙的弹出式消息,并且如果你希望使用调试器,请解除所需网络类型的锁定。
<- 在主机系统上
- 1. 在主计算机上,以管理员身份打开“命令提示符”窗口。转到 WinDbg.exe 目录。 使用 x64 版本的 WinDbg.exe,它来自于作为 Windows 工具包安装的一部分进行安装的 Windows WDK。复制
C:\> Cd C:\Program Files(x86)\Windows Kits\10.0\Debuggers\x64
- 2. 使用以下命令启动具有远程用户调试功能的 WinDbg。密钥值和端口值须与我们之前使用 BCDEdit 在目标计算机系统上设置的值匹配。复制
WinDbg –k net:port=50000,key=1.2.3.4
-> 在目标计算机系统上
重新启动目标计算机系统。
<- 在主机系统上
在一到两分钟内,调试输出应该会显示在主机系统上。
“调试器命令”窗口是 WinDbg 中的主要调试信息窗口。您可在此窗口中输入调试器命令并查看命令输出。
“调试器命令”窗口分为两个窗格。在窗口底部的较小窗格(命令输入窗格)中键入命令,在窗口顶部的较大窗格中查看命令输出。
在命令输入窗格中,使用向上键和向下键以滚动显示历史命令。命令显示后,你可以编辑它或按 ENTER 运行它。
第 2 部分:内核模式调试命令和技巧
在第 2 部分中,将使用调试命令来显示有关目标计算机系统的信息。
-> 在主机系统上
支持带有 .prefer_dml 的调试器标记语言 (DML)
一些调试命令将显示采用调试器标记语言的文本,以便你可以通过在其上单击快速收集更多信息。
- 1. 在 WinDBg 中使用 Ctrl+Break (Scroll Lock) 以进入到正在目标计算机系统运行的代码。目标计算机系统可能需要一些时间来进行响应。
- 2. 键入以下命令,以在调试器命令窗口中启用 DML。复制
0: kd> .prefer_dml 1DML versions of commands on by default
使用 .hh 以获取帮助
你可以使用 .hh 命令访问参考命令帮助。
- 3. 键入以下命令,以查看 .prefer_dml 的参考命令帮助。复制
0: kd> .hh .prefer_dml
- 调试器帮助文件将显示有关 .prefer_dml 命令的帮助。
设置调试掩码
- 4. 键入以下命令,以更改默认调试位掩码,以便来自目标计算机系统的所有调试消息都显示在调试器中。复制
0: kd> !ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
在目标计算机系统上显示 Windows 的版本
- 5. 通过在 WinDbg 窗口中键入 vertarget (Show Target Computer Version) 命令,从而在目标计算机系统上显示详细的版本信息。复制
0: kd> vertargetWindows 10 Kernel Version 9926 MP (4 procs) Free x64Product: WinNt, suite: TerminalServer SingleUserTSBuilt by: 9926.0.amd64fre.fbl_awesome1501.150119-1648Machine Name: ""Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)System Uptime: 0 days 01:31:58.931
列出加载的模块
- 6. 通过在 WinDbg 窗口中键入 lm (List Loaded Modules) 命令来显示加载的模块,你可以验证是否正在使用正确的内核模式进程。复制
0: Kd> lmstart end module namefffff801`09200000 fffff801`0925f000 volmgrx (no symbols) fffff801`09261000 fffff801`092de000 mcupdate_GenuineIntel (no symbols) fffff801`092de000 fffff801`092ec000 werkernel (export symbols) werkernel.sysfffff801`092ec000 fffff801`0934d000 CLFS (export symbols) CLFS.SYSfffff801`0934d000 fffff801`0936f000 tm (export symbols) tm.sysfffff801`0936f000 fffff801`09384000 PSHED (export symbols) PSHED.dllfffff801`09384000 fffff801`0938e000 BOOTVID (export symbols) BOOTVID.dllfffff801`0938e000 fffff801`093f7000 spaceport (no symbols) fffff801`09400000 fffff801`094cf000 Wdf01000 (no symbols) fffff801`094d9000 fffff801`09561000 CI (export symbols) CI.dll...
- 7. 要请求特定模块的详细信息,请使用所示的 v(详细)选项。复制
0: Kd> lm v m tcpipBrowse full module liststart end module namefffff801`09eeb000 fffff801`0a157000 tcpip (no symbols) Loaded symbol image file: tcpip.sys Image path: \SystemRoot\System32\drivers\tcpip.sys Image name: tcpip.sys Browse all global symbols functions data Timestamp: Sun Nov 09 18:59:03 2014 (546029F7) CheckSum: 00263DB1 ImageSize: 0026C000 Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4Unable to enumerate user-mode unloaded modules, Win32 error 0n30
- 8. 由于我们尚未设置符号路径和加载的符号,因此调试器中提供了有限的信息。
第 3 部分:下载和生成 KMDF 通用 Echo 驱动程序
在第 3 部分中,将下载和生成 KMDF 通用 Echo 驱动程序。
在使用 WinDbg 时,你通常会用到自己的驱动程序代码。要熟悉 WinDbg 操作,请使用 KMDF 模板“Echo”示例驱动程序。若提供源代码,则更易于用户理解显示在 WinDbg 中的信息。此外,该示例还将用于演示如何逐句通过本机内核模式代码。这项技术对调试复杂的内核模式代码问题十分有价值。
若要下载和生成 Echo 示例音频驱动程序,请完成以下步骤。
从 GitHub 下载并解压缩 KMDF Echo 示例
你可以使用浏览器,在此处通过 GitHub 查看 Echo 示例:
https://github.com/Microsoft/Windows-driver-samples/tree/97cf5197cf5b882b2c689d8dc2b555f2edf8f418/general/echo/kmdf
你可以在此处读取该示例:
https://github.com/Microsoft/Windows-driver-samples/blob/97cf5197cf5b882b2c689d8dc2b555f2edf8f418/general/echo/kmdf/ReadMe.md
你可以在此处浏览所有的通用驱动程序示例:
https://github.com/Microsoft/Windows-driver-samples
KMDF Echo 示例位于 general 文件夹中。
a.对于本实验,我们将以压缩文件的形式下载通用驱动程序示例。
https://github.com/Microsoft/Windows-driver-samples/archive/master.zip
b. 将 master.zip 文件下载到本地硬盘驱动器中。
c. 右键单击 Windows-driver-samples-master.zip,然后选择“全部解压缩”。指定新的文件夹,或浏览到一个现有文件夹以存储已解压缩的文件。例如,你可以将 C:\DriverSamples\ 指定为要在其中解压缩文件的新文件夹。
d.解压缩文件后,请导航到以下子文件夹。
C:\DriverSamples\general\echo\kmdf
在 Visual Studio 中打开驱动程序解决方案
在 Microsoft Visual Studio 中,依次单击“文件”>“打开”>“项目/解决方案...”,然后导航到包含已解压缩文件的文件夹(例如,C:\DriverSamples\general\echo\kmdf)。双击kmdfecho 解决方案文件以打开它。
在 Visual Studio 中,找到“解决方案资源管理器”。(如果尚未打开,请从“视图”菜单中选择“解决方案资源管理器”。)在“解决方案资源管理器”中,你可以看到一个具有三个项目的解决方案。
设置示例的配置和平台
在“解决方案资源管理器”中,右键单击“解决方案‘kmdfecho’(3 个项目)”,然后选择“配置管理器”。请确保配置和平台设置与四个项目相同。默认情况下,在所有这些项目中都将配置设置为 "Win10 Debug",而将平台设置为 "Win64"。如果你对其中一个项目做了任何配置和/或平台更改,则必须对剩余三个项目做相同的更改。
设置运行时库
设置运行时库 - 将运行时库的版本从 DLL 版本更改为非 DLL 版本。如果没有此设置,则必须将 MSVC 运行时单独安装到目标计算机。
检查驱动程序签名
打开 Echo 驱动程序的属性页,并确保“驱动程序签名”>“签名模式”已设置为“测试签名”。之所以必须这样做,是因为 Windows 要求对驱动程序进行签名。
使用 Visual Studio 生成示例
在 Visual Studio 中,依次单击“生成”>“生成解决方案”。
如果一切正常,生成窗口将显示一条消息,指示所有这三个项目均已成功生成。
查找生成的驱动程序文件
在文件资源管理器中,导航到包含该示例的已解压缩文件的文件夹。例如,如果 C:\DriverSamples\general\echo\kmdf 是你前面指定的文件夹所在的路径,则导航至该路径。在该文件夹内,已编译的驱动程序文件的位置会有所不同,具体取决于“配置管理器”中选定的配置和平台设置。例如,如果让默认设置保持不变,则编译的驱动程序文件将针对 64 位调试版保存到名为 \x64\Debug 的文件夹中。
导航到包含 Autosync 驱动程序的生成文件的文件夹:
C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug。该文件夹应包含以下文件:
文件 说明 Echo.sys驱动程序文件。
Echo.inf包含安装驱动程序所需信息的信息 (INF) 文件。
此外,还将生成 echoapp.exe 文件,可在此处找到它:C:\DriverSamples\general\echo\kmdf\exe\x64\Debug
文件 说明 EchoApp.exe命令提示符可执行测试文件,用于与 echo.sys 驱动程序通信。
- 找到 USB 便携驱动器或设置网络共享,以将生成的驱动程序文件和测试 EchoApp 从主机复制到目标计算机系统。
在下一部分中,将代码复制到目标计算机系统中,然后安装和测试驱动程序。
第 4 部分:在目标计算机系统上安装 KMDF Echo 驱动程序示例
在第 4 部分中,你将使用 Devcon 来安装 Echo 示例驱动程序。
-> 在目标计算机系统上
安装驱动程序的计算机称为“目标计算机”或“测试计算机”。通常,此类计算机独立于开发和生成驱动程序包的计算机。开发和生成驱动程序的计算机称为“主计算机”。
将驱动程序包移至目标计算机并安装该驱动程序的过程称为“部署”驱动程序。可自动或手动部署示例 Echo 驱动程序。
手动部署驱动程序之前,必须通过打开测试签名准备目标计算机。还需要在 WDK 安装中找到 DevCon 工具。完成该操作后,你便可以随时运行生成的驱动程序示例了。
通过执行以下步骤在目标计算机系统上安装驱动程序。
准备目标计算机
以管理员身份打开命令提示符窗口。然后,输入以下命令:
- bcdedit /set TESTSIGNING ON
重新启动目标计算机。
- bcdedit /set TESTSIGNING ON
<- 在主机系统上
导航至 WDK 安装中的 Tools 文件夹,并找到 DevCon 工具。例如,查找以下文件夹:
- C:\Program Files (x86)\Windows Kits\10.0\Tools\x64\devcon.exe
在目标计算机上为生成的驱动程序包创建文件夹(例如,C:\EchoDriver)。从主计算机上前面描述的生成驱动程序包中复制所有文件,并将这些文件都保存到在目标计算机上创建的文件夹中。
在主计算机系统上找到 .cer 证书,该证书位于与该计算机上包含生成驱动程序文件的文件夹相同的文件夹中。在目标计算机上,右键单击证书文件,并单击“安装”,然后按照提示安装测试证书。
如果你需要有关设置目标计算机的更详细的说明,请参阅准备用于手动部署驱动程序的计算机。
-> 在目标计算机系统上
安装驱动程序
以下说明向你演示了如何安装和测试示例驱动程序。下面是关于将用于安装驱动程序的 devcon 工具的一般语法:
- devcon install <INF file> <hardware ID>
安装此驱动程序时需使用的 INF 文件为 echo.inf。该 inf 文件包含用于安装 echo.sys 的硬件 ID。对于 Echo 示例,硬件 ID 为root\ECHO。
在目标计算机上,以管理员身份打开“命令提示符”窗口。导航到你的驱动程序包文件夹,然后输入以下命令:
- devcon install echo.inf root\ECHO
如果你收到一条错误消息,指示 devcon 未被识别,请尝试将该路径添加到 devcon 工具。例如,如果将它复制到名为C:\Tools 的文件夹中,请尝试使用以下命令:
- C:\tools\devcon install echo.inf root\ECHO
此时将显示一个对话框,指示测试驱动程序为未签名的驱动程序。请单击“Install this driver anyway”以继续操作。
有关更详细的说明,请参阅配置计算机以进行驱动程序部署、测试和调试。
成功安装示例驱动程序后,可随时对其进行测试。
在设备管理器中查看驱动程序
1. 在目标计算机的“命令提示符”窗口中,输入 devmgmt 以打开“设备管理器”。在“设备管理器”的“视图”菜单上,选择“依类型排序设备”。在设备树的“示例设备”节点中,找到示例 WDF Echo 驱动程序。
测试驱动程序
2. 通过键入 echoapp 启动测试 Echo 应用,以确认该驱动程序可正常运行。
复制C:\Samples\KMDF_Echo_Sample> echoappDevicePath: \\?\root#sample#0005#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a}Opened device successfully512 Pattern Bytes Written successfully512 Pattern Bytes Read successfullyPattern Verified successfully30720 Pattern Bytes Written successfully30720 Pattern Bytes Read successfullyPattern Verified successfully
第 5 部分:使用 WinDbg 显示有关驱动程序的信息
在第 5 部分中,将设置符号路径,并使用内核调试器命令来显示有关 KMDF Echo 示例驱动程序的信息。
通过执行以下步骤查看驱动程序相关信息。
<- 在主机系统上
如果已关闭调试器,可在管理员命令提示符窗口中,使用以下命令重新打开它。
复制WinDbg -k net:port=50000,key=1.2.3.4
- 使用 Ctrl+Break (Scroll Lock) 以进入正在目标计算机系统上运行的代码。
设置符号路径
- 要在 WinDbg 环境中将符号路径添加到 Microsoft 符号服务器,请使用 .symfix 命令。复制
0: kd> .symfix
- 若要添加本地符号位置以便使用本地符号,请依次使用 .sympath+ 和 .reload /f 来添加路径。复制
0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf0: kd> .reload /f
注意 带有 /f 强制选项的 .reload 命令可用于删除指定模块的所有符号信息,以及重新加载这些符号。在某些情况下,此命令还可用于自行重新加载或卸载模块。
0:000> dvUnable to enumerate locals, HRESULT 0x80004005Private symbols (symbols.pri) are required for locals.Type “.hh dbgerr005” for details.
符号服务器
有多种方法可用于符号的使用。在许多情况下,在需要使用符号时,均可将电脑配置为从 Microsoft 提供的符号服务器访问它们。本演练假设使用此方法。如果你所在环境中的符号位于其他位置,请修改相关步骤以使用该位置。有关其他信息,请参阅符号存储区和符号服务器。
理解源代码符号要求
要执行源调试,必须生成二进制文件的已检查(调试)版本。编译器将创建符号文件(.pdb 文件)。这些符号文件会向调试器显示二进制指令响应源行的方式。这些实际源文件本身必须也能够访问调试器。
符号文件不包含源代码文本。对于调试而言,链接器最好不优化您的代码。如果代码已经优化,则更难以进行源调试和访问本地变量,有时几乎不可能进行。如果你无法查看本地变量或源行,请设置以下生成选项:
set COMPILE_DEBUG=1set ENABLE_OPTIMIZER=0
在调试器的命令区域中键入下列内容,以显示有关 Echo 驱动程序的信息:
复制0: kd> lm m echo* vBrowse full module liststart end module namefffff801`4ae80000 fffff801`4ae89000 ECHO (private pdb symbols) C:\Samples\KMDF_ECHO_SAMPLE\echo.pdb Loaded symbol image file: ECHO.sys Image path: \SystemRoot\system32\DRIVERS\ECHO.sys Image name: ECHO.sys...
有关信息,请参阅 lm。
- 因为我们之前设置了 prefer_dml =1,所以某些输出的元素是可单击的热链接。 单击调试输出中的浏览所有全局符号链接,以显示有关以字母“a”开头的项目符号的信息。复制
0: kd> x /D Echo!a*
事实上,Echo 示例不包含以“a”开头的任何符号,因此,若要显示以 Echo 开头的 Echo 驱动程序相关联的所有符号相关信息,请键入 x ECHO!Echo*。
复制0: kd> x ECHO!Echo*fffff801`0bf95690 ECHO!EchoEvtIoQueueContextDestroy (void *)fffff801`0bf95000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)fffff801`0bf95ac0 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)fffff801`0bf9b120 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)...
有关信息,请参阅 x (Examine Symbols)。
- !lmi 扩展显示有关某个模块的详细信息。键入 !lmi echo。输出应与如下所示的文本类似。复制
0: kd> !lmi echoLoaded Module Info: [echo] Module: ECHO Base Address: fffff8010bf94000 Image Name: ECHO.sys…
- 5. 使用 !dh 扩展来显示标头信息,如下所示。复制
0: kd> !dh echoFile Type: EXECUTABLE IMAGEFILE HEADER VALUES 14C machine (i386) 6 number of sections54AD8A42 time date stamp Wed Jan 07 11:34:26 2015...
第 6 部分:显示即插即用设备树的相关信息
在第 6 部分中,将显示有关 Echo 示例设备驱动程序的信息,以及它位于即插即用设备树中的哪个位置。
即插即用设备树中设备驱动程序的相关信息可用于疑难解答。 例如,如果设备驱动程序未常驻在设备树中,则该设备驱动程序的安装可能存在问题。
有关设备节点调试扩展的详细信息,请参阅 !devnode。
<- 在主机系统上
若要查看即插即用设备树中的所有设备节点,请输入 !devnode 0 1 命令。
复制0: kd> !devnode 0 1Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30)DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50 InstancePath is "HTREE\ROOT\0" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50 InstancePath is "ROOT\volmgr\0000" ServiceName is "volmgr" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0……
通过使用 Ctrl+F 在生成的输出中进行搜索,查找名为 echo 的设备驱动程序。
应加载 Echo 设备驱动程序。使用 !devnode 0 1 echo 命令,以显示与 Echo 设备驱动程序相关联的即插即用信息,如下所示。
复制0: Kd> !devnode 0 1 echoDumping IopRootDeviceNode (= 0xffffe0007b725d30)DevNode 0xffffe0007b71a630 for PDO 0xffffe0007b71a960 InstancePath is "ROOT\SAMPLE\0000" ServiceName is "ECHO" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d)…
上一命令中显示的输出包含与驱动程序正在运行的实例相关联的 PDO,在本例中为 0xffffe0007b71a960。输入 !devobj<PDO address> 命令,以在电脑上显示与 Echo 设备驱动程序相关联的即插即用信息。使用 !devnode 显示在电脑上的 PDO 地址,而不是使用此处所示的地址。
复制0: kd> !devobj 0xffffe0007b71a960Device object (ffffe0007b71a960) is for: 0000000e \Driver\PnpManager DriverObject ffffe0007b727e60Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040Dacl ffffc102c9b36031 DevExt 00000000 DevObjExt ffffe0007b71aab0 DevNode ffffe0007b71a630 ExtensionFlags (0x00000800) DOE_DEFAULT_SD_PRESENTCharacteristics (0x00000180) FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPENAttachedDevice (Upper) ffffe000801fee20 \Driver\ECHODevice queue is not busy.
显示在 !devnode 0 1 命令中的输出包含与驱动程序正在运行的实例相关联的 PDO 地址,在本例中为 0xffffe0007b71a960。输入!devstack<PDO address> 命令,以显示与设备驱动程序相关联的即插即用信息。使用 !devnode 显示在电脑上的 PDO 地址,而不是使用如下所示的地址。
复制0: kd> !devstack 0xffffe0007b71a960 !DevObj !DrvObj !DevExt ObjectName ffffe000801fee20 \Driver\ECHO ffffe0007f72eff0 > ffffe0007b71a960 \Driver\PnpManager 00000000 0000000e!DevNode ffffe0007b71a630 : DeviceInst is "ROOT\SAMPLE\0000" ServiceName is "ECHO"
输出显示,我们有一个非常简单的设备驱动程序堆栈。Echo 驱动程序是 PnPManager 节点的子节点。PnPManager 是根节点。
\Driver\ECHO \Driver\PnpManager
此图展示了一个更复杂的设备节点树。
第 7 部分:使用断点和源代码
在第 7 部分中,将设置断点并逐句通过内核模式源代码。
使用命令设置断点
为了能逐句通过代码并实时检查变量值,需启用断点并设置源代码的路径。
断点用于在某一特定的代码行处停止代码执行。然后,你可以从该断点处继续向前执行代码,以调试该特定的代码段。
若要使用调试命令设置断点,请使用以下 b 命令之一:
bp
设置断点,卸载其所在模块时将激活该断点。
bu
设置断点,卸载模块时无法解析该断点,重新加载模块时重新启用该断点。
bm
为符号设置断点。此命令将适当使用 bu 或 bp,并允许使用通配符 * 在所有相匹配(例如,一个类中的所有方法)的每一个符号上设置断点。
有关详细信息,请参阅调试参考文档中的在 WinDbg 中进行源代码调试。
<- 在主机系统上
使用 WinDbg UI 以确认在当前 WinDbg 会话中已启用“调试”>“源模式”。
通过键入以下命令,将本地代码位置添加到源路径。
复制.srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
通过键入以下命令,将本地符号位置添加到符号路径。
复制.sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
我们将使用 x 命令来检查与 Echo 驱动程序相关联的符号,以确定要用于断点的函数名称。 我们可以使用通配符或 Ctrl+F 来查找DeviceAdd 的函数名称。
复制0: kd> x ECHO!EchoEvt*8b4c7490 ECHO!EchoEvtIoQueueContextDestroy (void *)8b4c7000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)8b4c7820 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)8b4cb0e0 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)8b4c75d0 ECHO!EchoEvtIoWrite (struct WDFQUEUE__ *, struct WDFREQUEST__ *, unsigned int)8b4cb170 ECHO!EchoEvtDeviceAdd (struct WDFDRIVER__ *, struct …
上面的输出显示,Echo 驱动程序的 DeviceAdd 方法即为 ECHO!EchoEvtDeviceAdd。
此外,我们可以通过查看源代码,来查找断点所需的函数名称。
使用 bm 命令设置断点,该命令使用驱动程序名称,后跟要在其中设置断点的函数名称(例如 AddDevice),用感叹号隔开。我们将使用AddDevice 监控驱动程序的加载进度。
复制0: kd> bm ECHO!EchoEvtDeviceAdd 1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
注意你可以将不同的语法与设置变量结合使用,例如,<module>!<symbol>、<class>::<method>、‘<file.cpp>:<line number>’,或多次跳过 <condition> <#>。 有关详细信息,请参阅WinDbg 和其他 Windows 调试器中的条件断点。
列出当前断点以确认断点已通过键入 bl 命令进行设置。
复制0: kd> bl1 e fffff801`0bf9b1c0 0001 (0001) ECHO!EchoEvtDeviceAdd
“e”指示断点数字为 1 时将触发。
通过键入 g (Go) 命令,在目标计算机系统上重新启动代码执行。
-> 在目标计算机系统上
在 Windows 中,使用“设备管理器”图标或输入 mmc devmgmt.msc,即可打开设备管理器。在“设备管理器”中,展开“示例”节点。
右键单击 KMDF Echo 驱动程序条目,然后从菜单中选择“禁用”。
再次右键单击 KMDF Echo 驱动程序条目,然后从菜单中选择“启用”。
<- 在主机系统上
启用驱动程序时,应触发 AddDevice 调试断点,并且应暂停目标计算机系统上驱动程序代码的执行。命中断点时,该执行应在AddDevice 例程开始处停止。调试命令输出将显示“Breakpoint 1 hit”。
通过键入 p 命令或按 F10 逐行通过代码,直至到达以下 AddDevice 例程的末尾处。括号字符“}”将突出显示,如下所示。
- 在下一部分中,我们将在执行 DeviceAdd 代码后,检查变量状态。
修改断点状态
可使用以下命令修改现有断点:
bl
列出断点。
bc
从列表中清除断点。使用 bc * 可清除所有断点。
bd
禁用断点。使用 bd * 可禁用所有断点。
be
启用断点。使用 be * 可启用所有断点。
或者,你可以通过在 WinDbg 中依次单击“编辑”>“断点”来修改断点。请注意,断点对话框仅适用于现有断点。必须从命令行设置新断点。
设置内存访问断点
还可以设置在访问内存时触发的断点。使用 ba(在访问时中断)命令及以下语法。
ba <access> <size> <address> {options}
e
执行(当 CPU 从地址获得一条指令时)
r
读/写(当 CPU 读取或写入地址时)
w
写(当 CPU 写入地址时)
请注意,在任意给定时间内你只能设置四个数据断点,由你来确保正确对齐数据,否则将不会触发断点(即,字必须以能被 2 整除的地址结尾,双字必须以能被 4 整除的地址结尾,四字必须以能被 0 或 8 整除的地址结尾)
例如,要在特定内存地址上设置读/写断点,可以使用如下命令。
ba r 4 0x0003f7bf0
从“调试器命令”窗口逐句通过代码
可以使用以下命令逐句通过代码。括号内显示关联的键盘快捷键:
中断 (Ctrl+Break) - 只要系统正在运行且与 WinDbg 通信,该命令便会中断系统(内核调试器中的快捷键顺序是 Ctrl+C)。
运行到光标处(F7 或 Ctrl+F10)– 将光标置于源窗口或反汇编窗口中要中断执行的位置,然后按 F7,代码执行将运行到此处。请注意,如果代码执行流未到达光标所指示位置(例如,未执行 IF 语句),WinDbg 将不会中断,因为代码执行未到达所指示位置。
运行 (F5) – 运行直到遇到断点或发生如错误检查之类的事件。
单步执行 (F10) – 此命令以逐条通过语句或逐个通过指令的方式来执行代码。如果遇到调用,代码执行不进入被调用例程即可忽略调用。(如果编程语言是 C 或 C++ 且 WinDbg 在源模式下,则可使用“调试”>“源模式”开启或关闭源模式。)
跳入 (F11) – 除调用执行不进入已调用例程外,该命令类似 step-over。
跳出 (Shift+F11) – 该命令使执行从当前例程(调用堆栈中的当前位置)运行并退出。如果例程太多,此命令将很有用。
有关详细信息,请参阅调试参考文档中的在 WinDbg 中进行源代码调试。
第 8 部分:查看变量和调用堆栈
在第 8 部分中,将显示有关变量和调用堆栈的信息。
本实验假定你已使用前面所述的流程停止在 AddDevice 例程处。若要查看此处的输出显示,请重复前面所述的步骤(如果需要)。
<- 在主机系统上
显示变量
使用“查看”>“本地”菜单项,以显示本地变量。
全局变量
可通过键入 <variable name> 找到全局变量地址的位置。
本地变量
通过键入 dv 命令,可针对给定框架显示所有本地变量的名称和值。
0: kd> dv Driver = 0x00001fff`7ff9c838 DeviceInit = 0xffffd001`51978190 status = 0n0
Callstacks
调用堆栈是已引导到程序计数器的当前位置的函数调用链。调用堆栈上的顶部函数是当前函数,下一个函数是调用了当前函数的函数,依此类推。
要显示调用堆栈,请使用 k* 命令:
kb
显示堆栈和前三个参数。
kp
显示堆栈和参数的完整列表。
kn
允许你查看堆栈及其旁边的框架信息。
<- 在主机系统上
1. 如果希望调用堆栈一直可用,可通过依次单击“查看”>“调用堆栈”查看它。单击窗口顶部的列以切换附加信息的显示。
2. 使用 kn 命令,以显示在中断状态下调试示例适配器代码时的调用堆栈。
3: kd> kn# Child-SP RetAddr Call Site00 ffffd001`51978110 fffff801`0942f55b ECHO!EchoEvtDeviceAdd+0x66 [c:\Samples\kmdf echo sample\c++\driver\autosync\driver.c @ 138]01 (Inline Function) --------`-------- Wdf01000!FxDriverDeviceAdd::Invoke+0x30 [d:\wbrtm\minkernel\wdf\framework\shared\inc\private\common\fxdrivercallbacks.hpp @ 61]02 ffffd001`51978150 fffff801`eed8097d Wdf01000!FxDriver::AddDevice+0xab [d:\wbrtm\minkernel\wdf\framework\shared\core\km\fxdriverkm.cpp @ 72]03 ffffd001`51978570 fffff801`ef129423 nt!PpvUtilCallAddDevice+0x35 [d:\9142\minkernel\ntos\io\pnpmgr\verifier.c @ 104]04 ffffd001`519785b0 fffff801`ef0c4112 nt!PnpCallAddDevice+0x63 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 7397]05 ffffd001`51978630 fffff801`ef0c344f nt!PipCallDriverAddDevice+0x6e2 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 3390]...
该调用堆栈显示,内核 (nt) 已调入即插即用代码 (PnP) 中,并且已调用驱动程序框架代码 (Wdf),该框架代码随后调用了 Echo 驱动程序的 DeviceAdd 函数。
第 9 部分:显示进程和线程
进程
在第 9 部分中,将显示有关内核模式下运行的进程和线程的信息。
可使用 !process 调试器扩展,显示或设置进程信息。我们将通过设置断点来检查播放声音时所使用的进程。
<- 在主机系统上
键入 dv 命令,以检查与 EchoEvtIo 例程相关联的区域设置变量。
复制0: kd> dv ECHO!EchoEvtIo*ECHO!EchoEvtIoQueueContextDestroyECHO!EchoEvtIoWriteECHO!EchoEvtIoRead
- 使用 bc * 清除之前的断点。复制
0: kd> bc *
3. 使用以下命令,在 EchoEvtIo 例程上设置符号断点。
复制0: kd> bm ECHO!EchoEvtIo* 2: aade5490 @!”ECHO!EchoEvtIoQueueContextDestroy” 3: aade55d0 @!”ECHO!EchoEvtIoWrite” 4: aade54c0 @!”ECHO!EchoEvtIoRead”
列出断点以确认断点已正确进行设置。
复制0: kd> bl1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197] 0001 (0001) ECHO!EchoEvtIoQueueContextDestroy...
键入 g 命令以重新启动代码执行。
复制0: kd> g
-> 在目标计算机系统上
在目标计算机系统上运行 EchoApp.exe 驱动程序测试程序。
<- 在主机系统上
当测试应用运行时,将调用驱动程序中的 I/O 例程。此操作将触发断点,并且将暂停目标计算机系统上驱动程序代码的执行。
复制Breakpoint 2 hitECHO!EchoEvtIoWrite:fffff801`0bf95810 4c89442418 mov qword ptr [rsp+18h],r8
使用 !process 命令,以显示运行 echoapp.exe 时所涉及到的当前进程。
复制0: kd> !processPROCESS ffffe0007e6a7780 SessionId: 1 Cid: 03c4 Peb: 7ff7cfec4000 ParentCid: 0f34 DirBase: 1efd1b000 ObjectTable: ffffc001d77978c0 HandleCount: 34. Image: echoapp.exe VadRoot ffffe000802c79f0 Vads 30 Clone 0 Private 135.Modified 5.Locked 0. DeviceMap ffffc001d83c6e80 Token ffffc001cf270050 ElapsedTime 00:00:00.052 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 33824 QuotaPoolUsage[NonPagedPool] 4464 Working Set Sizes (now,min,max) (682, 50, 345) (2728KB, 200KB, 1380KB) PeakWorkingSetSize 652 VirtualSize 16 Mb PeakVirtualSize 16 Mb PageFaultCount 688 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 138 THREAD ffffe00080e32080 Cid 03c4.0ec0 Teb: 00007ff7cfece000 Win32Thread: 0000000000000000 RUNNING on processor 1
输出显示了当命中驱动程序写入事件上的断点时,该进程与正在运行的 echoapp.exe 相关联。有关详细信息,请参阅 !process。
- 使用 !process 0 0 显示所有进程的汇总信息。在输出中,使用 Ctrl+F 查找与 echoapp.exe 图像相关联的进程相同的进程地址。在下面显示的示例中,进程地址是 ffffe0007e6a7780。复制
...PROCESS ffffe0007e6a7780 SessionId: 1 Cid: 0f68 Peb: 7ff7cfe7a000 ParentCid: 0f34 DirBase: 1f7fb9000 ObjectTable: ffffc001cec82780 HandleCount: 34. Image: echoapp.exe...
记录与 echoapp.exe 相关联的进程 ID,以供稍后在本实验中使用。 也可以使用 CTRL+C,将该地址复制到复制缓冲区以供以后使用。
_____________________________________________________(echoapp.exe 进程地址)
根据需要,在调试器中输入 g 以运行代码,直至 echoapp.exe 完成运行。它将多次命中读取和写入事件中的断点。在 echoapp.exe 完成运行后,按 Ctrl+ScrLk (Ctrl+Break) 即可进入调试器。
使用 !process 命令以确认你现在运行的是其他进程。在下面显示的输出中,进程中 System 的映像值不同于Echo 的映像值。
复制1: kd> !processPROCESS ffffe0007b65d900 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 001ab000 ObjectTable: ffffc001c9a03000 HandleCount: 786. Image: System VadRoot ffffe0007ce45930 Vads 14 Clone 0 Private 22. Modified 131605. Locked 64. DeviceMap ffffc001c9a0c220 Token ffffc001c9a05530 ElapsedTime 21:31:02.516...
上面的输出显示了当我们暂停操作系统的运行时,系统进程 ffffe0007b65d900 仍在运行。
现在,可使用 !process 命令尝试观察你之前记录的与 echoapp.exe 相关联的进程 ID。提供你之前记录的 echoapp.exe 进程地址,而非下面示例中所示的进程地址。
复制0: kd> !process ffffe0007e6a7780TYPE mismatch for process object at 82a9acc0
该进程对象不再可用,因为 echoapp.exe 进程已不再运行。
线程
查看和设置线程的命令与查看和设置进程的命令非常类似。 使用 !thread 命令查看线程。使用 .thread 设置当前线程。
<- 在主机系统上
在调试器中输入 g,以在目标计算机系统上重新启动代码执行。
-> 在目标计算机系统上
在目标计算机系统上运行 EchoApp.exe 驱动程序测试程序。
<- 在主机系统上
将命中断点,且代码执行将暂停。
复制Breakpoint 4 hitECHO!EchoEvtIoRead:aade54c0 55 push ebp
要查看正在运行的线程,请键入 !thread。应显示类似以下内容的信息:
复制0: kd> !threadTHREAD ffffe000809a0880 Cid 0b28.1158 Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0IRP List: ffffe0007bc5be10: (0006,01f0) Flags: 00060a30 Mdl: 00000000Not impersonatingDeviceMap ffffc001d83c6e80Owning Process ffffe0008096c900 Image: echoapp.exe...
请注意,映像名称为 echoapp.exe,其指示我们正在查看与测试应用相关联的线程。
4. 使用 !process 命令,以确定这是否是与 echoapp.exe 相关联的进程中正在运行的唯一线程。 请注意,该进程中正在运行的线程的线程数与使用 !thread 命令显示的正在运行的线程数相同。
复制0: kd> !processPROCESS ffffe0008096c900 SessionId: 1 Cid: 0b28 Peb: 7ff7d00df000 ParentCid: 0f34 DirBase: 1fb746000 ObjectTable: ffffc001db6b52c0 HandleCount: 34. Image: echoapp.exe VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135.Modified 8.Locked 0. DeviceMap ffffc001d83c6e80 Token ffffc001cf5dc050 ElapsedTime 00:00:00.048 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 33824 QuotaPoolUsage[NonPagedPool] 4464 Working Set Sizes (now,min,max) (681, 50, 345) (2724KB, 200KB, 1380KB) PeakWorkingSetSize 651 VirtualSize 16 Mb PeakVirtualSize 16 Mb PageFaultCount 686 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 138 THREAD ffffe000809a0880 Cid 0b28.1158 Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
使用 !process 0 0 command 找到两个相关的进程的进程地址,并在此处记录这两个进程地址。
Cmd.exe:____________________________________________________________
EchoApp.exe:_______________________________________________________
复制0: kd> !process 0 0 …PROCESS ffffe0007bbde900 SessionId: 1 Cid: 0f34 Peb: 7ff72dfa7000 ParentCid: 0c64 DirBase: 19c5fa000 ObjectTable: ffffc001d8c2f300 HandleCount: 31. Image: cmd.exe…PROCESS ffffe0008096c900 SessionId: 1 Cid: 0b28 Peb: 7ff7d00df000 ParentCid: 0f34 DirBase: 1fb746000 ObjectTable: ffffc001db6b52c0 HandleCount: 34. Image: echoapp.exe…
注意 也可以通过使用 !process 0 17 来显示有关每个进程的详细信息。此命令的输出可能会很耗时。此输出可使用 Ctrl+F 进行搜索。使用 !process 命令,以列出电脑上正在运行的这两个进程的进程信息。提供 !process 0 0 输出中的进程地址,而非下面所示的地址。
此示例输出中的进程 ID 是你之前记录的 cmd.exe 进程 ID。请注意,此进程 ID 的映像名称是 cmd.exe。
复制0: kd> !process ffffe0007bbde900PROCESS ffffe0007bbde900 SessionId: 1 Cid: 0f34 Peb: 7ff72dfa7000 ParentCid: 0c64 DirBase: 19c5fa000 ObjectTable: ffffc001d8c2f300 HandleCount: 31. Image: cmd.exe VadRoot ffffe0007bb8e7b0 Vads 25 Clone 0 Private 117. Modified 20. Locked 0. DeviceMap ffffc001d83c6e80 Token ffffc001d8c48050 ElapsedTime 21:33:05.840 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 24656 QuotaPoolUsage[NonPagedPool] 3184 Working Set Sizes (now,min,max) (261, 50, 345) (1044KB, 200KB, 1380KB) PeakWorkingSetSize 616 VirtualSize 2097164 Mb PeakVirtualSize 2097165 Mb PageFaultCount 823 MemoryPriority FOREGROUND BasePriority 8 CommitCharge 381 THREAD ffffe0007cf34880 Cid 0f34.0f1c Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable ffffe0008096c900 ProcessObject Not impersonating...
此示例输出中的进程 ID 是你之前记录的 echoapp.exe 进程 ID。
复制0: kd> !process ffffe0008096c900PROCESS ffffe0008096c900 SessionId: 1 Cid: 0b28 Peb: 7ff7d00df000 ParentCid: 0f34 DirBase: 1fb746000 ObjectTable: ffffc001db6b52c0 HandleCount: 34. Image: echoapp.exe VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0. DeviceMap ffffc001d83c6e80 Token ffffc001cf5dc050 ElapsedTime 00:00:00.048 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 33824 QuotaPoolUsage[NonPagedPool] 4464 Working Set Sizes (now,min,max) (681, 50, 345) (2724KB, 200KB, 1380KB) PeakWorkingSetSize 651 VirtualSize 16 Mb PeakVirtualSize 16 Mb PageFaultCount 686 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 138 THREAD ffffe000809a0880 Cid 0b28.1158 Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0 IRP List: ffffe0007bc5be10: (0006,01f0) Flags: 00060a30 Mdl: 00000000 Not impersonating...
在此处记录与这两个线程相关联的第一个线程地址。
Cmd.exe:____________________________________________________
EchoApp.exe:_________________________________________________
使用 !Thread 命令来显示有关当前线程的信息。
复制0: kd> !ThreadTHREAD ffffe000809a0880 Cid 0b28.1158 Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0IRP List: ffffe0007bc5be10: (0006,01f0) Flags: 00060a30 Mdl: 00000000Not impersonatingDeviceMap ffffc001d83c6e80Owning Process ffffe0008096c900 Image: echoapp.exeAttached Process N/A Image: N/A...
正如预期的那样,当前线程为与 echoapp.exe 相关联的线程且正处于运行状态。
使用 !Thread 命令,以显示有关与 cmd.exe 进程相关联的线程的信息。提供你之前记录的线程地址。
复制0: kd> !Thread ffffe0007cf34880THREAD ffffe0007cf34880 Cid 0f34.0f1c Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable ffffe0008096c900 ProcessObjectNot impersonatingDeviceMap ffffc001d83c6e80Owning Process ffffe0007bbde900 Image: cmd.exeAttached Process N/A Image: N/AWait Start TickCount 4134621 Ticks: 0Context Switch Count 4056 IdealProcessor: 0 UserTime 00:00:00.000KernelTime 00:00:01.421Win32 Start Address 0x00007ff72e9d6e20Stack Init ffffd0015551dc90 Current ffffd0015551d760Base ffffd0015551e000 Limit ffffd00155518000 Call 0Priority 14 BasePriority 8 UnusualBoost 3 ForegroundBoost 2 IoPriority 2 PagePriority 5Child-SP RetAddr : Args to Child : Call Siteffffd001`5551d7a0 fffff801`eed184fe : fffff801`eef81180 ffffe000`7cf34880 00000000`fffffffe 00000000`fffffffe : nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]ffffd001`5551d8e0 fffff801`eed17f79 : ffff03a5`ca56a3c8 000000de`b6a6e990 000000de`b6a6e990 00007ff7`d00df000 : nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]ffffd001`5551d980 fffff801`eecea340 : ffffd001`5551da18 00000000`00000000 00000000`00000000 00000000`00000388 : nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]...
该线程与 cmd.exe 相关联且正处于等待状态。
提供等待线程 CMD.exe 的线程地址,以更改该等待线程的上下文。
复制0: kd> .Thread ffffe0007cf34880Implicit thread is now ffffe000`7cf34880
使用 k 命令,查看与等待线程相关联的调用堆栈。
复制0: kd> k *** Stack trace for last set context - .thread/.cxr resets it # Child-SP RetAddr Call Site00 ffffd001`5551d7a0 fffff801`eed184fe nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]01 ffffd001`5551d8e0 fffff801`eed17f79 nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]02 ffffd001`5551d980 fffff801`eecea340 nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]03 ffffd001`5551da00 fffff801`ef02e642 nt!KeWaitForSingleObject+0x2c0 [d:\9142\minkernel\ntos\ke\wait.c @ 683]...
调用堆栈元素(如 KiCommitThreadWait)指示该线程未按预期方式运行。
有关线程和进程的详细信息,请参阅 MSDN 上的以下参考部分:
线程和进程
更改上下文
第 10 部分:IRQL、寄存器和结束 WinDbg 会话
查看已保存的 IRQL
在第 10 部分中,将显示 IRQL 以及寄存器的内容。
<- 在主机系统上
中断请求级别 (IRQL) 用于管理中断服务的优先级。每个处理器都有一个 IRQL 设置,可用于提高或降低线程的优先级。在处理器的 IRQL 设置优先级或更低的优先级上发生的中断将被屏蔽,且不会干扰当前操作。在高于处理器的 IRQL 设置的优先级上发生的中断优先于当前操作。在调试器中断发生之前,!irql 扩展将在目标计算机的当前处理器上显示中断请求级别 (IRQL)。当目标计算机进入调试器时,IRQL 将更改,不过调试器中断发生前的有效 IRQL 将被保存且由 !irql 显示。
0: kd> !irqlDebugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)
查看寄存器
<- 在主机系统上
使用 r (Registers) 命令,以针对当前处理器上的当前线程显示寄存器的内容。
0: kd> rrax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620 r8=000000000000003e r9=ffffe00167a4a000 r10=000000000000001er11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0r14=0000000000000001 r15=0000000000000000iopl=0 nv up ei pl nz na pe nccs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000202nt!DbgBreakPointWithStatus:fffff803`bb757020 cc int 3
或者,你可以通过依次单击“查看”>“寄存器”来显示寄存器的内容。 有关详细信息,请参阅 r (Registers)。
当逐句通过汇编语言代码执行以及处于其他应用场景中时,查看寄存器的内容将会非常有用。有关汇编语言反汇编的详细信息,请参阅带有批注的 x86 反汇编和带有批注的 x64 反汇编。
有关寄存器的内容的信息,请参阅 x86 体系结构和 x64 体系结构。
结束 WinDbg 会话
<- 在主机系统上
要结束用户模式调试会话,请将调试器返回至休眠模式,并将目标应用程序设置为再次运行,输入 qd(退出和分离)命令。
请务必使用 g 命令以让目标计算机运行代码,以便可对其进行使用。使用 bc * 清除任何断点也是一个好办法,这样目标计算机便不会中断,并尝试连接到主计算机调试器。
0: kd> qd
有关详细信息,请参阅调试参考文档中的在 WinDbg 中结束调试会话。
第 11 部分:Windows 调试资源
Windows 调试提供附加信息。 请注意,某些手册将使用旧版 Windows(例如其示例中使用的是 Windows Vista),不过所讨论的概念适用于大多数版本的 Windows。
书籍
Advanced Windows Debugging,作者:Mario Hewardt 和 Daniel Pravat
Inside Windows Debugging: A Practical Guide to Debugging and Tracing Strategies in Windows®,作者:Tarik Soulami
Windows Internals,作者:Mark E. Russinovich、David A. Solomon 和 Alex Ionescu
视频
Defrag Tools 电视节目 WinDbg 第 13-29 集 http://channel9.msdn.com/Shows/Defrag-Tools
培训供应商:
OSRhttps://www.osr.com/
相关主题
- 标准调试技巧
- 专业调试技巧
- Windows 调试入门
- 调试通用驱动程序
- 如何调试驱动程序
- 驱动程序调试技术
- WinDBG调试驱动程序步骤
- windbg 源码调试 驱动程序
- 驱动程序的调试
- softice调试驱动程序
- 调试驱动程序的入口
- 驱动程序调试笔记
- Linux驱动程序调试
- 使用Softice调试驱动程序
- Linux驱动程序调试方法
- LINUx 驱动程序printk 调试
- 调试设备驱动程序
- devmem2 驱动程序调试工具
- linux设备驱动程序调试
- 驱动程序调试常用方法
- USB 通用父驱动程序 (Usbccgp.sys)
- Tinkphp采用ORM架构,ORM采用AR模式(一个ar类对应一个表)
- ECMAScript 6学习总结(1)——ECMAScript 6入门简介
- fsockopen开打很慢的原因-完善DZ的dfopen函数
- Python将Mysql分表数据按小时增量装载到Hive示例
- Linux逻辑卷管理LVM详解
- 调试通用驱动程序
- 如何衡量angular工程师水平
- ReCentOs_7.2 with Redis
- 关于android设置dp与px
- Tolua使用笔记二:lua与C#的函数,变量交互方法
- vue 改端口问题
- Android防止内存泄漏的八种方法(下)
- 计算机网络部分的面试常考点,参考书籍:《计算机网络》第五版 谢希仁
- 点击空白处让弹窗隐藏