五、源文件行语法
可以将源文件行号指定为MASM表达式的全部或部分。这些数字计算出与该源代码行对应的可执行代码的偏移量。不能使用源代码行作为C++表达式的一部分。必须用重音符(`)将源文件和行号表达式括起来。以下示例显示源文件行号的完整格式。
`[[Module!]Filename][:LineNumber]`
如果有多个文件具有相同的文件名,则文件名应包括整个目录路径和文件名。此目录路径应该是编译时使用的路径。如果只提供文件名或路径的一部分,并且存在多个匹配项,则调试器将使用找到的第一个匹配项。如果省略了文件名,调试器将使用与当前程序计数器对应的源文件。除非在行号前面加上0x,否则行号将作为十进制数读取,而不考虑当前的默认基数。如果省略了linenumber,表达式将计算出与源文件对应的可执行文件的初始地址。除非发出.lines(切换源行支持)命令或在启动windbg时包含-lines命令行选项,否则不会在cdb中计算源行表达式。
六、地址和地址范围语法
在调试器中有几种指定地址的方法。地址始终是虚拟地址,除非文档专门指明另一种地址。在用户模式下,调试器根据当前进程的页目录解释虚拟地址。在内核模式下,调试器根据进程上下文指定的进程页目录解释虚拟地址。还可以直接设置用户模式地址上下文。
6.1、地址模式和段支持
在基于x86的平台上,CDB和KD支持以下寻址模式。这些模式通过前缀来区分。
前缀 | 名称 | 地址类型 |
---|---|---|
% |
平坦 |
32 位地址 (也 16 位选择器,指向 32 位段) 和 64 位系统上的 64 位地址。 |
& |
virtual 86 |
实模式地址。 基于 x86 的仅。 |
# |
纯 |
实模式地址。 基于 x86 的仅。 |
普通模式和虚拟模式86的区别在于普通16位地址使用段值作为选择器,并查找段描述符。但一个虚拟的86地址不使用选择器,而是直接映射到较低的1 MB中。如果通过不是当前默认模式的寻址模式访问内存,则可以使用地址模式前缀覆盖当前地址模式。
6.2、地址参数
地址参数指定变量和函数的位置。下表说明了可以在CDB和KD中使用的各种地址的语法和含义。
语法 | 含义 |
---|---|
offset |
虚拟内存空间,含对应于当前的执行模式的类型中的绝对地址。 例如,如果当前的执行模式是 16 位,偏移量为 16 位。 如果执行模式是 32 位分段,偏移量为 32 位分段。 |
&[[段:]] 偏移量 |
实际地址。 基于 x86 和基于 x64 的。 |
%segment:[[ offset]] |
分段的 32 位或 64 位地址。 基于 x86 和基于 x64 的。 |
%[[偏移量]] |
一个绝对地址 (32 位或 64 位) 的虚拟内存空间中。 基于 x86 和基于 x64 的。 |
name[[ +|− ]] offset |
一个平面 32 位或 64 位地址。 名称可以是任何符号。 偏移量指定的偏移量。 此偏移量可以是任何其前缀表示的地址模式。 无前缀指定默认模式地址。 您可以指定偏移量为正 (+) 或负值 (−)。 |
使用dg (Display Selector)命令查看段描述符信息。在MASM表达式中,还可以使用POI运算符取消对任何指针的引用。例如,如果地址0x00123456处的指针指向地址位置0x004200,则以下两个命令是等效的。
0:000> dd 420000 0:000> dd poi(123456)
在C++表达式中,指针就像C++中的指针一样。然而,数字被解释为整数。如果必须遵从实际数字,则必须首先对其进行强制转换,如下例所示
0:000> dd *( (long*) 0x123456 )
一些伪寄存器还保存着公共地址,例如当前程序计数器位置。还可以通过指定原始源文件名和行号来指示应用程序中的地址。
6.3、地址范围
0x00001000 0x00001007
要通过地址和对象计数指定地址范围,请指定地址参数、字母L(大写或小写)和值参数。地址指定起始地址。该值指定要检查或显示的对象数。对象的大小取决于命令。例如,如果对象大小为1字节,下面的示例是8字节的范围,从地址0x0001000开始。
0x00001000 L8
但是,如果对象大小是一个双字(32位或4字节),则以下两个范围分别给出一个8字节的范围。
0x00001000 0x00001007 0x00001000 L2
指定值还有两种其他方法(lsize范围说明符):
- L?大小(带问号)表示与l size相同,除了l?大小删除了调试器的自动范围限制。通常,范围限制为256 MB,因为较大的范围是印刷错误。如果要指定大于256 MB的范围,必须使用L?大小语法。
- L-size(带连字符)指定以给定地址结尾的长度大小范围。例如,8000000 L20指定从0x8000000到0x800001F的范围,8000000 L-20指定从0x7fffffffe0到0x7fffffffff的范围。
一些要求地址范围的命令接受一个地址作为参数。在这种情况下,命令使用一些默认的对象计数来计算范围的大小。通常,地址范围是最终参数的命令允许使用这种语法。
七、线程操作语法
许多调试器命令的参数都是线程标识符。波浪线(~)出现在线程标识符之前。
线程标识符可以是以下值之一:
线程标识符 | 描述 |
---|---|
~. |
当前线程。 |
~# |
导致当前异常或调试事件的线程。 |
~* |
此进程中的所有线程。 |
~数量 |
其索引的线程数。 |
~~[TID] |
其线程 ID 是在线程TID。 (括号是必需的和不能添加第二个波形符和左大括号之间有空格)。 |
~[表达式] |
线程的线程 ID 是到整数数值表达式解析。 |
在内核模式下控制线程
八、进程操作语法
许多调试器命令的参数都是进程标识符。一个竖条(|)出现在进程标识符之前。进程标识符可以是以下值之一。
进程标识符 | 描述 |
---|---|
|. |
当前进程。 |
|# |
引起当前异常或调试事件的进程。 |
|* |
所有进程。 |
|数量 |
进程的第几数。 |
|~[PID] |
进程的进程 ID PID。 (括号是必需的和不能添加颚化符 (~) 和左大括号之间有空格)。 |
|[Expression] |
其进程 ID 的整数进程数值表达式解析。 |
系统标识符 | 描述 |
---|---|
||. |
当前系统 |
||# |
导致当前异常或调试事件系统。 |
||* |
所有系统。 |
||ddd |
系统其序号ddd。 |
||1:1:017> || 0 User mini dump: c: otepad.dmp . 1 User mini dump: c:paint.dmp # 2 User mini dump: c:calc.dmp
注意,在一起调试活动目标和转储目标时会有一些复杂的情况,因为对于每种调试类型,命令的行为都不同。例如,如果在当前系统是转储文件时使用g(go)命令,则调试器将开始执行,但不能重新进入调试器,因为break命令不被识别为对转储文件调试有效。
0: kd>
使用~s(更改当前处理器)命令在处理器之间切换,如下例所示。
0: kd> ~1s 1: kd>
现在正在调试的计算机中的第二个处理器。
如果遇到中断而无法理解堆栈跟踪,则可能需要更改多处理器系统上的处理器。中断可能发生在其他处理器上。
||[Expression]
在这种语法中,方括号是必需的,表达式表示任何解析为与处理器ID对应的整数的数值表达式。在下面的示例中,处理器根据用户定义的伪寄存器的值进行更改。
||[@$t0]
示例
1: kd> 2k
下面的示例使用r(registers)命令显示处理器3的EAX寄存器。
1: kd> 3r eax
1: kd> 3r eax=808080
10.3、断点
在内核调试期间,bp、bu、bm(设置断点)和ba(访问中断)命令适用于多处理器计算机的所有处理器。例如,如果当前处理器是三个,则可以输入以下命令在someaddress处放置断点。
1: kd> bp SomeAddress
然后,在该地址执行的任何处理器(不仅是处理器一个)都会导致断点陷阱。
10.4、显示处理器信息