cc682/NetRoc/小喂
http://netroc682.spaces.live.com/
命令关键字部分也直接使用了小喂翻译的文档。新版本WinDbg文档中更新过的部分作了一些修改,另外有部分语句也有少量更改。非常感谢小喂的共享。他的主页在
http://www.ztssoft.com/
命令关键字
本节论述在调试命令和元命令中使用的各种关键字。
这些记号包括:
; (命令分隔符)
{ } (块分隔符)
${ } (别名解释器)
$$ (注释说明符)
* (注释行说明符)
.block
.break
.catch
.continue
.do
.else
.elsif
.for
.foreach
.if
.leave
.printf
.while
; (命令分隔符)
分号( ; )字符常被用来分隔单行上多个命令。
语法
Command1 ; Command2 [; Command3 ...]
参数
Command1, Command2, ...
被执行的命令。
注释
命令从左往右顺序执行。除非另有说明,一行上的所有命令都和当前线程有关。如果某个命令导致线程恢复执行,该行剩下的命令都将推迟执行,直到线程停在一个调试事件上。
少部分命令后不能跟分号,因为它们会把行中剩下的全部内容都当成参数。包括as (Set Alias)、 $< (Run Script File)、$>< (Run Script File),以及任何以* (Comment Line Specifier)关键字打头的命令。
这有一个例子。执行当前程序到源码行 123 处,打印 counter 的值,然后继续执行:
0:000> g `:123`; ? poi(counter); g
{ } (块分隔符)
一对大括号( { } )常被用来括住调试器命令程序中的一段语句。
语法
Statements { Statements } Statements
注释
进入每个语句块时,会计算该语句块中的所有别名值。如果你在语句块中某个位置修改了别名的值,接下来的命令不会使用别名的新值,除非它们处在下级语句块中。
每个块都必须跟在流程控制记号后面。如果你只是为了计算别名想建立一个块,应该带上.block关键字前缀。
附加信息
对于调试器命令程序和流程控制记号,请看使用调试器命令程序。
${ } (别名解释器)
一个美元符号带一对大括号( ${ } )计算和指定的用户命名别名相关的各类值。
语法
Text ${Alias} Text
Text ${/d:Alias} Text
Text ${/f:Alias} Text
Text ${/n:Alias} Text
Text ${/v:Alias} Text
参数
Alias
指定要展开和求值的别名名称。Alias 必须是用户命名的别名或者 .foreach关键字中使用的变量值。
/d
根据别名当前是否已经定义计算出1或者0。如果别名已经定义,${/d:Alias} (译注:原文这里是 ${/v:Alias})被替换为 1;如果别名没有定义,${/d:Alias} (译注:原文这里是 ${/v:Alias})被替换为 0。
/f
如果别名当前已定义则等同于计算别名。如果别名已经定义,${/f:Alias} 被替换为等价的别名;如果别名没有定义,${/f:Alias} 被替换为空字符串。
/n
如果别名当前已定义则计算别名的名称。如果别名已经定义,${/n:Alias} 被替换为别名名称;如果别名没有定义,${/n:Alias} 保留它字面上的值不替换。
/v
禁止对任何别名求值。不论别名是否已经定义,${/v:Alias} 总是保持它字面上的值。
注释
如果没有使用开关选项且别名当前已定义,${Alias} 被替换为等价的别名。如果没有使用开关选项且别名没有定义,${Alias}总是保持它字面上的值。
使用 ${ } 记号的一个优点是,如果和其它字符紧挨着也会对别名求值。没有这个记号,调试器只对那些和其它关键字隔开的别名求值。
和说明一样,有一些情况下 ${ } 记号不会被替换为任何值而保持它字面上的值。这会发生在没有使用开关选项且别名没有定义时,以及使用了 /n 开关选项且别名没有定义时,以及使用了 /v 开关选项时。在这些情况下,该记号保持它字面上的值,包括美元符号和大括号。所以,如果作为命令参数,将导致语法错误,除非这个参数接受任意文本串。
但是这有一个例外。如果你使用 ${/v:Alias}作为 as (Set Alias)或者aS (Set Alias)命令的第一个参数,该关键字被当成单独的 Alias 字符串,而不是 ${/v:Alias}字符串。这只是对 as、aS 和 ad 命令起作用,也仅当使用了 /v 开关选项时 - 使用 ${/n:Alias}或者${Alias}当它们保持字面上的值时不起作用。
别名必须是用户命名的别名或者 .foreach 记号中使用的变量值 - 不是一个固定名称的别名。如果在字符串 Alias 中有一个固定名称的别名,会在计算 ${ } 记号前被替换掉。
附加信息
关于如果使用别名的说明,请看使用别名。
$$ (注释说明符)
如果命令开头出现两个美元符号( $$ ),则该行剩下的部分被当成注释,除非碰到分号。
语法
$$ [any text]
注释
$$ 和其他任何调试器命令一样被解析。因此,如果要在其它命令后创建一条注释,必须在$$之前添加一个分号。
$$ 关键字使得后面的文本被忽略掉,直到行末或者碰到分号。分号结束注释;分号后的文本被解析为标准的命令。这和* (Comment Line Specifier)不同,它会把行中剩下的部分都当成注释,即使里面有分号。
例如,下例将显示 eax 和 ebx,但不显示 ecx:
0:000> r eax; $$ some text; r ebx; * more text; r ecx
以 * 或者 $$ 记号为前缀的文本不能通过任何方式处理。如果你正进行远程调试,调试服务器上输入的注释在调试客户端上看不到,反过来则不一样。如果你希望通过一个对所有方都可见的方法使得注释文本显示在调试命令窗口,你应该使用.echo (Echo Comment)。
* (注释行说明符)
如果命令开头带星号( * )字符,则行中剩下的部分被当成注释,即使中间有分号。
语法
* [any text]
注释
*关键字像其它所有命令一样被解析。因此如果要在其它命令之后创建注释,必须在*关键字前加上一个分号。
*关键字将导致行中剩余部分被忽略掉,即使出现分号。这和$$ (Comment Specifier)不同,它所创建的注释会被分号截断。
例如,下面的命令将显示 eax 和 ebx,但不会显示 ecx:
0:000> r eax; $$ some text; r ebx; * more text; r ecx
以 * 或者 $$ 记号为前缀的文本不能通过任何方式处理。如果你正进行远程调试,调试服务器上输入的注释在调试客户端上看不到,反过来则不一样。如果你希望通过一个对所有方都可见的方法使得注释文本显示在调试命令窗口,你应该使用.echo (Echo Comment)。
.block
.block 关键字不执行任何动作;只是用来引入一个语句块。
语法
Commands ; .block { Commands } ; Commands
注释
由大括号括住每个语句块。当进入每个语句块时,所有块中的别名都被重新计算。如果你在块中某个命令处修改了别名的值,往下的命令不会使用新的别名值,除非它们处在一个下属子语句块中。
每个语句块应该以一个流程控制关键字打头。如果你希望创建一个语句块只是为了计算别名,你应该带上 .block 关键字作为该语句块的前缀,因为这个关键字除了引入一个语句块之外不会有什么影响。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.break
.break 关键字的行为和 C 语言中 break 关键字一样。
语法
.for (...) { ... ; .if (Condition) .break ; ... }
.while (...) { ... ; .if (Condition) .break ; ... }
.do { ... ; .if (Condition) .break ; ... } (...)
注释
.break 记号可以被用在任何 .for、.while或者.do循环中。
因为没有和 C 语言中 goto 语句等效的流程控制关键字,你将会在 .if条件中经常用到 .break 关键字,就像上面的语法例子显示的形式。但是,.break 关键字也不是必须的。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.catch
.catch 关键字通常用来避免错误发生时程序被中止。
它和 C++ 中的 catch 关键字的行为不一样。
语法
Commands ; .catch { Commands } ; Commands
注释
.catch 关键字后面跟由大括号括住的一条或多条命令。
如果 .catch 块中某条命令发生错误,则显示错误消息,忽略该块中剩下的命令,从大括号后面的第一条命令恢复执行。
如果没有使用 .catch,一个错误将会中止整个调试器命令程序的执行。
你可以使用.leave从一个 .catch 块中跳出来。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.continue
.continue 关键字的行为和 C 语言中的 continue 关键字一样。
语法
.for (...) { ... ; .if (Condition) .continue ; ... }
.while (...) { ... ; .if (Condition) .continue ; ... }
.do { ... ; .if (Condition) .continue ; ... } (...)
注释
.continue 记号可以被用在任何.for、.while或者.do循环中。
因为没有和 C 语言中 goto 语句等效的流程控制符,你将会在 .if条件中经常用到 .continue 记号,就像上面的语法例子显示的形式。但是,.continue 记号也不是必须的。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.do
除了在条件前没有使用 "while" 关键字之外,.do 记号的行为和 C 语言中的 do 关键字一样。
语法
.do { Commands } (Condition)
语法项
Commands
指定一条或多条命令,当条件为真时会被重复执行 - 但至少会执行一次。即使只包含一条命令,该命令块都需要用花括号括住。多个命令间用分号隔开,结束花括号前的最后一条命令不需要带分号。
Condition
指定条件。如果计算后结果为零,则被当成假,否则为真。把 Condition 用圆括号括住是可选的。Condition 必须是一个表达式,而不是一个调试器命令。将使用缺省的表达式求解器(MASM or C++)对其求值。详细请看数值表达式语法。
注释
.break和 .continue关键字可被用来退出或者重头开始 Commands 语句块。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.else
.else 关键字的行为和 C 语言中的 else 关键字一样。
语法
.if (Condition) { Commands } .else { Commands }
.if (Condition) { Commands } .elsif (Condition) { Commands } .else { Commands }
语法项
Commands
指定一条或多条命令,将被有条件的执行。即使只包含一条命令,该命令块都需要用花括号括住。多个命令间用分号隔开,结束花括号前的最后一条命令不需要带分号。
附加信息
需要其它流程控制记号的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.elsif
.elsif 关键字和 C 语言中的 else if 组合关键字的行为一样。
语法
.if (Condition) { Commands } .elsif (Condition) { Commands }
.if (Condition) { Commands } .elsif (Condition) { Commands } .else { Commands }
语法项
Condition
指定条件。如果计算后结果为零,则被当成假,否则为真。把 Condition 用圆括号括住是可选的。Condition 必须是一个表达式,而不是一个调试器命令。将使用缺省的表达式求解器(MASM or C++)对其求值。详细数值表达式语法。
Commands
指定一条或多条命令,将被有条件地执行。即使只包含一条命令,该命令块都需要用花括号括住。多个命令间用分号隔开,结束花括号前的最后一条命令不需要带分号。
附加信息
需要其它流程控制符的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.for
.for 关键字的行为和 C 语言中的 for 关键字一样,只有一点不同,多个增量命令之间必须用分号隔开,而不是用逗号。
语法
.for (InitialCommand ; Condition ; IncrementCommands) { Commands }
语法项
InitialCommand
指定循环开始前执行的命令。只允许单个的初始化命令 。
Condition
指定条件。如果计算后结果为零,则被当成假,否则为真。把 Condition 用圆括号括住是可选的。Condition 必须是一个表达式,而不是一个调试器命令。将使用缺省的表达式求解器(MASM or C++)对其求值。详细请看数值表达式语法。
IncrementCommands
指定一条或多条命令,在单次循环结束时执行。如果想要执行多条增量命令,需要用分号把它们隔开,不需要用花括号括住。
Commands
指定一条或多条命令,当条件为真时会被重复执行。即使只包含一条命令,该命令块都需要用花括号括住。多个命令间用分号隔开,结束花括号前的最后一条命令不需要带分号。
注释
如果在增量命令中就可以做完所有工作,你完全可以忽略 Commands 部分,简单的使用一对花括号就行。
这有一个带多条增量命令的 .for 语句的例子:
0:000> .for (r eax=0; @eax < 7; reax=eax+1; rebx=ebx+1) { .... }
.break和.continue关键字可用来退出或者重头开始 Commands 语句块。
附加信息
需要其它流程控制符的信息以及它们在调试器命令程序中的用法,请看使用调试器命令程序。
.foreach
.foreach 关键字分析一个或多个命令的输出并将该输出中每一个值作为另一个或多个命令的输入。
语法
.foreach [Options] ( Variable { InCommands } ) { OutCommands }
.foreach [Options] /s ( Variable "InString" ) { OutCommands }
.foreach [Options] /f ( Variable "InFile" ) { OutCommands }
语法项
Options
可以是下面选项的任意组合:
/pS InitialSkipNumber
使得开头的一些符号被调过。InitialSkipNumber 指定不传递给OutCommands 的输出关键字的数量。
/ps SkipNumber
每次执行命令时都会跳过一些符号。每次将符号传递给OutCommands 之后,SkipNumber 个数的符号都会被忽略。
Variable
指定一个变量名。该变量用来保存InCommands 字符串中的每次输出,因此传递给OutCommands 的参数中可以通过名字引用Variable 。可以使用任何字母数字的字符串,但是并不建议使用可以当作有效的16进制数字或调试器命令的字符串。如果Variable 使用的名字碰巧和已存在的全局变量、局部变量或别名相同,它们的值不会受.foreach 命令的影响。
InCommands
指定要解析输出的一个或多个命令;结果会传递给OutCommands 。InCommands 的输出不会显示出来。
InString
和/s 一起使用。指定一个要解析的字符串;结果会传递给OutCommands 。
InFile
和/f 一起使用。指定要解析的文本文件;结果会传递给OutCommands 。文件名InFile 必须用引号括起来。
OutCommands
指定每条标记(token)要执行的一个或多个命令。任何时候Variable 都会被替换为当前标记。
注意 当Variable出现在OutCommands 中时,必须前后带有空格。如果有其它任何文本相邻 — 即使是一个圆括号 — 就不会被当前标记替换,除非使用${ } (Alias Interpreter)关键字。
注释
当InCommands 的输出、InString 字符串或InFile 被解析时,任何数量的空格、tab符或回车都将会被当作单个分隔符。文本被分隔成的小片段被用来替换OutCommands 中的Variable 。
这里有一个使用.foreach 语句的示例,对文件myfile.txt 中找到的每条标记都会使用dds 命令:
0:000> .foreach /f ( place "g:\myfile.txt") { dds place }
/pS 和/ps标志用来仅将特定的标记传递给指定的OutCommands。例如,下面的语句将跳过myfile.txt 文件中的前两个标记并将第三个传递给dds。传递了每个标记之后,都会跳过四个标记。所以结果就是dds使用的标记是第3、8、13、18和23,等等:
0:000> .foreach /pS 2 /ps 4 /f ( place "g:\myfile.txt") { dds place }
使用.foreach 关键字的更多示例,查看调试器命令程序示例。
附加信息
其它流程控制符的信息以及它们在调试器命令程序中的用法,查看使用调试器命令程序。
.if
.if关键字的行为和C中的if类似。
语法
.if (Condition) { Commands }
.if (Condition) { Commands } .else { Commands }
.if (Condition) { Commands } .elsif (Condition) { Commands }
.if (Condition) { Commands } .elsif (Condition) { Commands } .else { Commands }
语法项
Condition
指定一个条件。如果求值为0,则作为假;否则为真。把Condition用圆括号括起来是可选的。Condition必须是一个表达式而不是调试器命令。它将会使用默认的表达式求值器(MASM或C++)来计算。详细信息,查看数值表达式语法。
Commands
指定用于条件执行的一条或多条命令。该命令块必须用大括号括起来,即使只有一条命令。多条命令需要用分号分隔,但是反的大括号前面的最后一条指令后面必须要跟分号。
附加信息
其它流程控制符的信息以及它们在调试器命令程序中的用法,查看使用调试器命令程序。
.leave
.leave关键字用来退出一个.catch块。
语法
.catch { ... ; .if (Condition) .leave ; ... }
注释
当.leave关键字在.catch块中时,程序从该块中退出,并继续执行反大括号后的第一条命令。
由于没有C中的goto 语句这样的控制流符号,通常像上面的语法示例中一样在.if中使用.leave 关键字。但是这并不是必须的。
附加信息
其它流程控制符的信息以及它们在调试器命令程序中的用法,查看使用调试器命令程序。
.printf
.printf 关键字和C中的printf 语句类似。
语法
.printf "FormatString" [Arguments ...]
语法项
FormatString
指定printf中的格式化字符串。一般来说,转义字符和C中完全一样。对于浮点转义字符,如果没有使用l 修饰符,64位参数会被当作32位浮点数。
支持%p 转义字符,但是它表示目标虚拟地址空间中的一个指针。它不能包含任何修饰符并且使用调试器的内部地址格式。支持下面这些转义字符:
字符
|
参数类型
|
参数
|
打印出的文本
|
%p
|
ULONG64
|
目标的虚拟地址空间中的指针
|
指针的值
|
%N
|
DWORD_PTR (32位或64位,由主控机的架构决定。
|
目标的虚拟地址空间中的指针
|
指针的值。(和标准C的%p字符一样。)
|
%I
|
ULONG64
|
任何64位值
|
指定的值。如果大于0xFFFFFFFF作为64位地址显示,否则作为32位地址显示。
|
%ma
|
ULONG64
|
目标虚拟地址空间中以NULL结尾的ASCII字符串地址。
|
指定的字符串。
|
%mu
|
ULONG64
|
目标虚拟地址空间中以NULL结尾的Unicode字符串地址。
|
指定的字符串。
|
%msa
|
ULONG64
|
目标虚拟地址空间中的ANSI_STRING结构地址。
|
指定的字符串。
|
%msu
|
ULONG64
|
目标虚拟地址空间中的UNICODE_STRING结构地址。
|
指定的字符串。
|
%y
|
ULONG64
|
目标虚拟地址空间中的调试器符号的地址。
|
包含指定符号的名字的字符串(和偏移量(displacement),如果有的话)。
|
%ly
|
ULONG64
|
目标虚拟地址空间中的调试器符号的地址。
|
包含指定符号的名字的字符串(和偏移量(displacement),如果有的话),和任何可用的源码行信息。
|
Arguments
指定printf的格式化字符串的参数。参数的个数应该和FormatString 中的转义字符数量匹配。每个参数都是一个使用默认表达式求值器(MASM 或C++)进行计算的表达式。详细信息,查看数值表达式语法。
附加信息
其它流程控制符的信息以及它们在调试器命令程序中的用法,查看使用调试器命令程序。
.while
.while关键字的行为和C中的while关键字类似。
语法
.while (Condition) { Commands }
语法项
Condition
指定一个条件。如果它的值为0则作为真;否则为假。把Condition用圆括号括起来是可选的。Condition 必须是一个表达式而不是调试器命令。它将会使用默认的表达式求值器(MASM 或C++)进行求值。详细信息,查看数值表达式语法。
Commands
指定当条件为真时会重复执行的一条或多条命令。该命令块必须使用大括号括起来,即使只有一条命令。多个命令之间用分号分隔,但是反的大括号之前的最后一条命令之后不用跟分号。
注释
.break 和.continue 关键字可以退出或从头执行Commands 语句块。
附加信息
其它流程控制符的信息以及它们在调试器命令程序中的用法,查看使用调试器命令程序。