windbg 调试器简明手册——第 7 章——调试器命令——第 2 节——命令标记 (Token)

目录

1.  命令分隔符(Separator)(分号——;)

1.1  格式

1.2  参数

1.3  说明

2.  块分割符(Block Delimiter)(花括号(卷括号(curly bracket))(大括号(brace))——{})

2.1  格式

2.2  其它信息

2.3  说明

3.  别名解释器(Alias Interpreter)(${})

3.1  格式

3.2  参数

3.2.1  别名

3.2.2  /d

3.2.3  /f

3.2.4  /n

3.2.5  /v

3.3  其它信息

3.4  说明

4.  注释指定符(Comment Specifier)($$)

4.1  格式

4.2  说明

5.  行注释指定符(Comment Line Specifier)(*)

5.1  格式

5.2  说明

6.  引入语句标记 .block

6.1  格式

6.2  说明

7.  中止语句标记 .break

7.1  格式

7.2  说明

8.  异常继续执行标记 .catch

8.1  格式

8.2  说明

9.  继续执行循环标记 .continue

9.1  格式

9.2  说明

10.  后条件循环命令标记 .do

10.1  格式

10.2  语法元素

10.3  说明

11.  条件分支标记 .else

11.1  格式

11.2  语法元素

12.  条件分支标记 .elsif

12.1  格式

12.2  语法元素

13.  循环命令标记  .for

13.1  格式

12.2  语法元素

12.3  说明

14.  循环命令标记  .foreach

14.1  格式

14.2  语法元素

14.3  说明

15.  条件标记  .if

15.1  格式

15.2  语法元素

16.  退出.catch块标记  .leave

16.1  格式

16.2  说明

17.  打印标记  .printf

17.1  格式

17.2  语法元素

17.3  说明

18.  循环命令标记  .while

18.1  格式

18.2  语法元素

18.3  说明


1.  命令分隔符(Separator)(分号——;)

1.1  格式

    分号(semicolon)字符(;)用于分隔单行命令中的多条命令。

Command1 ; Command2 [; Command3 ...]

1.2  参数

Command1 , Command2 ,…  为被执行的命令。

1.3  说明

命令从左到右依次执行。除非另有说明,否则同一行上的所有命令都指向当前线程。如果某个命令导致线程执行,则该行上的其余命令将延迟执行,直到该线程因调试事件而停止。

    少数命令后不能跟分号,因为它们会自动将剩余的整行内容作为参数。这些命令包括 as aS(设置别名),$< (运行脚本文件) 以及任何以 * (注释行说明符)开头的命令。

    以下是一个示例。此命令将当前程序执行到第 123 行,打印计数器的值,然后继续执行:

0:000> g :123 ; ? poi(counter); g

2.  块分割符(Block Delimiter)(花括号(卷括号(curly bracket))(大括号(brace))——{})

2.1  格式

    一对花括号({})用于在一个调试器命令内包裹一个语句块。

Statements { Statements } Statements

2.2  其它信息

关于调试器命令和控制流标记的更多信息,参见“使用调试器命令程序。”

2.3  说明

每一个命令块进入时,都会估算该块内的所有别名。如果在命令块内的某个位置更改了别名的值,则除非位于下级命令块内,否则后续的命令将不会使用新的别名值。

每个命令块必须以控制流标记开头。如果你希望创建一个专门用于估算别名的命令块,则应在其前面加上 .block 标记。

3.  别名解释器(Alias Interpreter)(${})

3.1  格式

    美元符号后跟一对大括号(${})用于计算指定的用户命名别名相关的各种值。

Text ${Alias} Text

Text ${/d:Alias} Text

Text ${/f:Alias} Text

Text ${/n:Alias} Text

Text ${/v:Alias} Text

3.2  参数

3.2.1  别名

         指定要展开或计算的别名。别名必须是用户命名的别名,或是 .foreach 标记使用的变量值。

3.2.2  /d

根据别名当前是否已定义,该值取值为 1 或 0。如果别名已定义,则 ${/d:Alias} 替换为 1;如果别名未定义,则 ${/d:Alias} 替换为 0。

3.2.3  /f

    如果别名已定义,则计算结果为别名的等效值。如果别名已定义,则 ${/f:Alias} 将替换为别名的等效值;如果别名未定义,则 ${/f:Alias} 将替换为空字符串。

3.2.4  /n

如果别名当前已定义,则计算结果为别名。如果别名已定义,则 ${/n:Alias} 将替换为别名;如果别名未定义,则 ${/n:Alias} 不会被替换,而是保留其字面值 ${/n:Alias}。

3.2.5  /v

阻止任何别名求值。无论是否定义了别名,${/v:Alias} 始终保留其字面值 ${/v:Alias}。

3.3  其它信息

有关如何使用别名的说明,请参阅“使用别名”。

3.4  说明

如果未使用任何开关且别名已定义,则 ${Alias} 将替换为等效的别名。如果未使用任何开关且别名未定义,则 ${Alias} 始终保留其字面值 ${Alias}。

使用 ${ } 标记的一个优点是,即使别名与其他字符相邻,也会对其进行求值。如果没有此标记,调试器只会替换与其他标记之间以空格分隔的别名。

如前所述,在某些情况下,${ } 标记不会被替换,而是保留其字面值。这种情况发生在未使用任何开关且别名未定义时,发生在使用了 /n 开关且别名未定义时,以及始终发生在使用了 /v 开关时。在这些情况下,标记会保留其字面值,包括美元符号和大括号。因此,如果将其用作命令的参数,则会产生语法错误,除非该参数接受任意文本字符串。

         然而,有一个例外。如果你将 ${/v:Alias} 作为 as(设置别名) 或 aS(设置别名)命令的第一个参数,则此标记将视为单独的字符串 Alias,而不是字符串 ${/v:Alias}。这仅适用于 as , aS  和 ad 命令,并且仅在使用 /v 开关时有效——当 ${/n:Alias} 或 ${Alias} 保留其字面值时,此方法无效。

         Alias 必须是用户命名的别名或 .foreach  标记使用的变量值,而不是固定名称的别名。如果字符串 Alias 中包含固定名称的别名,则会在计算  ${ } 标记之前将其替换。

4.  注释指定符(Comment Specifier)($$)

4.1  格式

若命令开头出现两个美元符号($$),则该行的其余部分将视为注释,除非注释以分号结尾。

$$ [any text]

4.2  说明

$$ 标记的解析方式与其他调试器命令相同。因此,如果要在另一个命令后添加注释,必须在 $$ 标记前加上分号。

    $$ 标记之后的文本将被忽略,直到行尾或遇到分号为止。分号用于终止注释。分号之后的文本将作为标准命令进行解析。这与 *(注释行指定符)不同,* 会将行的剩余部分视为注释,即使存在分号。

    例如,以下命令将显示 eax 和 ebx,但不会显示 ecx:

0:000> r eax; $$ some text; r ebx; * more text; r ecx

以 * 或 $$ 标记开头的文本不会被处理。如果你正在执行远程调试,则在调试服务器中输入的注释不会显示在调试客户端中,反之亦然。如果你希望注释文本以所有人都可见的方式显示在调试器命令窗口中,则应使用 .echo(回显注释)。

5.  行注释指定符(Comment Line Specifier)(*)

5.1  格式

    如果星号(asterisk)(*)字符位于命令的开头,则该行的其余部分将视为注释,即使其后出现分号

* [any text]

5.2  说明

* 标记的解析方式与其他调试器命令相同。因此,如果要在另一个命令后添加注释,必须在 * 标记前加上分号。

    * 标记会导致该行剩余部分被忽略,即使其后出现分号也一样。这与 $$(注释指定符)不同,$$ 创建的注释可以用分号结束。

    例如,以下命令将显示 eax 和 ebx,但不会显示 ecx:

    0:000> r eax; $$ some text; r ebx; * more text; r ecx

    以 * 或 $$ 标记开头的文本不会处理。如果你正在执行远程调试,则在调试服务器中输入的注释不会显示在调试客户端中,反之亦然。如果你希望注释文本以所有人都可见的方式显示在调试器命令窗口中,则应使用 .echo (回显注释)。

6.  引入语句标记 .block

6.1  格式

    .block 标记不执行任何操作;它仅用于引入一个语句块。

Commands ; .block { Commands } ; Commands

有关使用新代码块计算别名的信息,请参阅“使用别名”和“as, aS(设置别名)”。

有关其他控制流标记及其在调试器命令程序中的使用信息,请参阅“使用调试器命令程序”。

6.2  说明

命令块用花括号括起来。输入每一个命令块时,块内所有别名都会执行。如果在命令块中修改了某个别名的值,那么之后的命令将不会使用新的别名值,除非它们位于子命令块中。

    每一个命令块必须以控制流标记开头。如果你只想创建一个用于执行别名的命令块,则应在其前面加上 .block 标记,因为该标记除了允许插入命令块之外没有其他作用。

7.  中止语句标记 .break

7.1  格式

    .break 标记的作用类似于 C 语言中的 break 关键字。

.for (...) { ... ; .if (Condition) .break ; ...}

.while (...) { ... ; .if (Condition) .break ; ...}

.do { ... ; .if (Condition) .break ; ...} (...)

7.2  说明

.break 标记可以用于任何 .for.while .do 循环中。

    由于没有与 C 语言的 goto 语句等效的控制流标记,通常会在 .if 条件语句中使用 .break 标记,如上面的语法示例所示。但是,这并非强制要求。

8.  异常继续执行标记 .catch

8.1  格式

.catch 标记用于防止程序在发生错误时终止。

它的行为与 C++ 中的 catch (捕获异常)关键字不同。

8.2  说明

.catch 标记后跟大括号,大括号内包含一个或多个命令。

    如果 .catch 代码块中的某个命令产生错误,则会显示该错误信息,忽略大括号内的所有剩余命令,并从右大括号后的第一个命令继续执行

    如果不使用 .catch,则错误将终止整个调试器命令程序。

    可以使用 .leave 退出 .catch 代码块。

9.  继续执行循环标记 .continue

9.1  格式

    .continue 标记的行为类似于 C 语言中的 continue 关键字。

.for (...) { ... ; .if (Condition) .continue ; ... }

.while (...) { ... ; .if (Condition) .continue ; ... }

.do { ... ; .if (Condition) .continue ; ... } (...)

9.2  说明

.continue标记可以用于任何 .for.while .do 循环中。

由于没有与 C 语言的 goto 语句等效的控制流标记,通常会在 .if 条件语句中使用 .continue 标记,如上面的语法示例所示。但是,这并非强制要求。

10.  后条件循环命令标记 .do

10.1  格式

.do 标记的行为类似于 C 语言中的 do 关键字,只是在条件之前不使用单词“while”。

.do { Commands } (Condition)

10.2  语法元素

(1) Commands

指定一个或多个命令,只要条件为真,这些命令就会重复执行——但至少会执行一次。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

(2) Condition

指定一个条件。如果该条件的计算结果为零,则视为假;否则视为真。条件是否包含在括号中是可选的。条件必须是一个表达式,而不是调试器命令。它将由默认表达式求值器(MASM 或 C++) 进行求值。有关详细信息,请参阅“数值表达式语法”。

10.3  说明

    .break .continue 标记可用于退出或重新开始命令块。

11.  条件分支标记 .else

11.1  格式

.else 标记的行为类似于 C 语言中的 else 关键字。

.if (Condition) { Commands } .else { Commands }

.if (Condition) { Commands } .elsif (Condition) { Commands } .else { Commands }

11.2  语法元素

Commands

指定一个或多个将根据条件执行的命令。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

12.  条件分支标记 .elsif

12.1  格式

.elsif 标记的行为类似于 C 语言中的 else if 关键字组合。

.if (Condition) { Commands } .elsif (Condition) { Commands }

.if (Condition) { Commands } .elsif (Condition) { Commands } .else { Commands }

12.2  语法元素

(1)  条件:

    指定一个条件。如果该条件的计算结果为零,则视为假;否则视为真。条件是否包含在括号中是可选的。条件必须是一个表达式,而不是调试器命令。它将由默认表达式求值器( MASM 或 C++ )进行求值。有关详细信息,请参阅“数值表达式语法”。

(2)  命令:

指定一个或多个将根据条件执行的命令。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

13.  循环命令标记  .for

13.1  格式

    .for 标记的行为类似于 C 语言中的 for 关键字,只是多个递增命令必须用分号分隔,而不是用逗号分隔。

.for (InitialCommand ; Condition ; IncrementCommands) { Commands }

12.2  语法元素

(1)  InitialCommand

指定循环开始前要执行的命令。只允许指定一个初始命令。

(2)  Condition

指定一个条件。如果该条件的计算结果为零,则视为假;否则视为真。条件是否包含在括号中是可选的。条件必须是一个表达式,而不是调试器命令。它将由默认表达式求值器( MASM 或 C++)进行求值。有关详细信息,请参阅“数值表达式语法”。

(3)  IncrementCommands

指定在每次循环结束时要执行的一个或多个命令。如果要使用多个递增命令,请用分号分隔它们,但不要用大括号将它们括起来。

(4)  Commands

指定一个或多个命令,只要条件为真,这些命令就会重复执行。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

12.3  说明

    如果所有工作都由递增命令完成,则可以完全省略条件,只需使用空的大括号即可。

    以下是一个包​​含多个递增命令的 .for 循环示例:

0:000> .for (r eax=0; @eax < 7; r eax=@eax+1; r ebx=@ebx+1) { .... }

.break .continue 标记可用于退出或重新开始命令块。

14.  循环命令标记  .foreach

14.1  格式

    .foreach 标记解析一个或多个调试器命令的输出,并将此输出中的每个值用作一个或多个附加命令的输入。

.foreach [Options] ( Variable  { InCommands } ) { OutCommands }

.foreach [Options] /s ( Variable  "InString" ) { OutCommands }

.foreach [Options] /f ( Variable  "InFile" ) { OutCommands }

14.2  语法元素

    选项可以是以下选项的任意组合:

(1)  /pS  初始跳跃数(InitialSkipNumber)

导致跳过一些初始标记。InitialSkipNumber 指定不会传递给指定 OutCommands 的输出标记的数量。

(2)  /ps   跳跃数(SkipNumber)

每次处理命令时,都会重复跳过某些标记。每次将标记传递给指定的 OutCommands 后,都会忽略 SkipNumber 值所指定的标记数量。

(3)  Variable 

    指定一个变量名。此变量将用于保存 InCommands 字符串中每个命令的输出;你可以在传递给 OutCommands 的参数中按名称引用此变量。可以使用任何字母数字字符串,但不建议使用可以作为有效十六进制数或调试器命令的字符串。如果变量名恰好与现有的全局变量、局部变量或别名匹配,则它们的值不会受到 .foreach 命令的影响。

(4)  InCommands

指定一个或多个命令,这些命令的输出将被解析;解析得到的标记将传递给 OutCommands。InCommands 的输出不会显示。

(5)  InString

与 /s 一起使用。指定要解析的字符串;解析结果将传递给 OutCommands。

(6)  InFile

与 /f 一起使用。指定要解析的文本文件;解析结果将传递给 OutCommands。InFile 文件名必须用引号括起来。

(7)  OutCommands

指定一个或多个将针对每个标记执行的命令。每当出现变量字符串时,它都会被当前标记替换。

注意:当字符串“Variable”出现在 OutCommands 中时,它必须用空格包围。如果它与任何其他文本(即使是括号)相邻,则不会被当前标记值替换,除非你使用 ${ }(别名解释器)标记。

14.3  说明

当解析 InCommands、InString 字符串或 InFile 文件的输出时,任意数量的空格、制表符或回车符都视为单个分隔符。解析得到的每段文本都会在 OutCommands 中替换 Variable。

    以下是一个 .foreach 语句的示例,该语句对 myfile.txt 文件中的每个标记使用 dds 命令:

0:000> .foreach /f ( place "g:\myfile.txt") { dds place }

/pS 和 /ps 标志可用于仅将特定标记传递给指定的 OutCommand。例如,以下语句将跳过 myfile.txt 文件中的前两个标记,然后将第三个标记传递给 dds。每传递一个标记,它就会跳过四个标记。结果是,dds 将处理第 3,8,13,18 和 23 个标记,依此类推:

0:000> .foreach /pS 2 /ps 4 /f ( place "g:\myfile.txt") { dds place }

15.  条件标记  .if

15.1  格式

.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 }

15.2  语法元素

(1)  Condition

指定一个条件。如果该条件的计算结果为零,则视为假;否则视为真。条件是否包含在括号中是可选的。条件必须是一个表达式,而不是调试器命令。它将由默认表达式求值器(MASM 或 C++)进行求值。有关详细信息,请参阅“数值表达式语法”。

(2)  Commands

指定一个或多个将根据条件执行的命令。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

16.  退出.catch块标记  .leave

16.1  格式

.leave 标记用于退出 .catch 代码块。

    .catch { ... ; .if (Condition) .leave ; ... }

16.2  说明

当在 .catch 代码块中遇到 .leave 标记时,程序会退出该代码块,并从右大括号后的第一个命令继续执行。

    由于没有与 C 语言的 goto 语句等效的控制流标记,通常情况下,你会将 .leave 标记放在 .if 条件语句中,如上面的语法示例所示。然而,这并非强制要求。

17.  打印标记  .printf

17.1  格式

.printf 标记的行为类似于 C 语言中的 printf 语句。

.printf [/D] [Option] "FormatString" [, Argument , ...]

17.2  语法元素

(1)  /D

指定格式字符串包含调试器标记语言(DML)。

(2)  Option

(仅限 WinDbg)指定 WinDbg 应将 FormatString 解释为哪种类型的文本消息。WinDbg 为每种调试器命令窗口消息类型分配背景色和文本颜色;选择其中一个选项将使消息以相应的颜色显示。默认情况下,文本显示为普通级别的消息。

可获得的选项如下表:

选项

消息类型

选项对话框中颜色标题

/od

调试

调试级别命令窗口

/oD

调试提示

调试提示级别的命令窗口

/oe

错误

错误级别的命令窗口

/on

普通

普通级别命令窗口

/op

提示

提示级别命令窗口

/oP

提示级别

提示级别命令窗口

/os

符号

符号消息级别命令窗口

/ov

详细信息

详细级别的命令窗口

/ow

警告

警告级别命令窗口

(3)  FormatString

指定格式字符串,类似于 printf 函数。通常,转换字符的工作方式与 C 语言完全相同。对于浮点转换字符,除非使用 l 修饰符,否则 64 位参数会被解释为 32 位浮点数。

    可以添加“I64”修饰符来指示值应解释为 64 位。例如,“%I64x”可用于打印 64 位十六进制数。

支持 %p 转换字符,但它表示目标虚拟地址空间中的指针。它不能带有任何修饰符,并且使用调试器的内部地址格式化。除了标准的 printf 风格格式说明符之外,还支持以下附加转换字符。

字符

参数类型

参数

打印文体

%p

ULONG64

目标虚拟地址空间中的指针。

指针值

%N

DWORD_PTR

(3264位,取决于主机架构)

主机虚拟地址空间中的指针。

指针的值。(这相当于标准的 C 语言 %p 字符。)

%ma

ULONG64

目标虚拟地址空间中以 NULL 结尾的 ASCII 字符串的地址。

具体字符串

%mu

ULONG64

目标虚拟地址空间中以 NULL 结尾的 Unicode 字符串的地址。

具体字符串

%msa

ULONG64

目标虚拟地址空间中 ANSI_STRING 结构的地址。

具体字符串

%msu

ULONG64

目标虚拟地址空间中 UNICODE_STRING 结构的地址。

具体字符串

%y

ULONG64

调试器符号在目标虚拟地址空间中的地址。

包含指定符号名称(以及位移,如果有)的字符串。

%ly

ULONG64

调试器符号在目标虚拟地址空间中的地址。

包含指定符号名称(以及位移,如果有)以及任何可用源行信息的字符串。

(4)  Arguments

指定格式字符串的参数,类似于 printf 函数。指定的参数数量应与 FormatString 中的转换字符数相匹配。每个参数都是一个表达式,将由默认表达式求值器( MASM 或 C++ )进行求值。有关详细信息,请参阅数值表达式语法。

17.3  说明

默认情况下,您可以使用“选项”参数选择颜色设置,所有设置均为白底黑字。要充分利用这些选项,您必须先使用“视图”|“选项”打开“选项”对话框,然后更改调试器命令窗口消息的颜色设置。

    以下示例演示如何在格式字符串中包含 DML 标签。

.printf /D "Click <link cmd=\".chain /D\">here</link> to see extensions DLLs."


上图所示的输出结果包含一个链接,点击该链接即可执行 <link> 标签中指定的命令。下图显示了点击该链接后的结果。

有关 DML 标签的信息,请参阅 Windows 调试工具安装文件夹中的 dml.doc 文件。

18.  循环命令标记  .while

18.1  格式

    .while 标记的行为类似于 C 语言中的 while 关键字。

.while (Condition) { Commands }

18.2  语法元素

(1)  Condition

指定一个条件。如果该条件的计算结果为零,则视为假;否则视为真。条件是否包含在括号中是可选的。条件必须是一个表达式,而不是调试器命令。它将由默认表达式求值器( MASM 或 C++) 进行求值。有关详细信息,请参阅“数值表达式语法”。

(2)  Commands

指定一个或多个命令,只要条件为真,这些命令就会重复执行。即使此命令块仅包含一个命令,也必须用花括号括起来。多个命令之间应以分号分隔,但右花括号前的最后一个命令后不需要跟分号。

18.3  说明

.break .continue 标记可用于退出或重新开始命令块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值