NetRoc's Blog

N-Tech

 

WinDbg 文档翻译----14

cc682/NetRoc

http://netroc682.spaces.live.com/

调试器命令窗口

本节包含以下主题:

使用调试器命令

表达式求值

使用外壳命令

使用别名

使用脚本文件

使用调试器命令

使用调试器命令

对于KD或CDB来说,"调试器命令窗口"就是整个窗口。在窗口底部的提示符位置输入命令。如果命令有输出,则窗口显示这些输出并重新显示提示符。

对于WinDbg,"调试器命令窗口"指标题为"Command"的窗口。该窗口有两个部分:

  • 较小的,底部的部分用于输入命令。
  • 大的,上边的部分用来查看命令输出。

这个窗口始终在开始调试会话的时候就会打开。可以通过点击View菜单中的Command、按下ALT+1或者点击工具栏上的Command(Alt+1)按钮(1)来重新打开或者切换到该窗口。

可以通过按下上箭头和下箭头来滚动查看历史命令。当前面使用过的命令出现时,可以编辑并按下ENTER来执行这条命令(或者编辑过的命令)。光标不需要在行尾即可正常工作。

调试命令窗口提示符

进行用户模式调试时,调试命令窗口的提示符如下例中一样。

2:005>

上例中,2是当前进程号,005是当前线程号。

如果将调试器附加到不止一台计算机,在进程和线程号之前会有一个系统号。如下。

3:2:005>

这个例子中,3是当前系统号,2是当前进程号,005是当前线程号。

进行内核模式调试时,如果目标机只有一个处理器,提示符如下。

kd>

但是,如果目标机有多个处理器,当前处理器号会在提示符之前显示,如下。

0: kd> 

如果KD或CDB中没有提示符出现,或者WinDbg的调试器命令窗口不可用,说明调试器不能输入任何命令。但是,仍然可以使用KD和CDB的控制键,以及WinDbg的菜单命令和 快捷键

也可以使用.pcmd (设置提示命令) 命令为提示增加字符。

命令类型

WinDbg、KD和CDB支持各种命令。一些是各调试器共有的,一些只能在某些调试器中可用。

一些命令只工作在活动调试下,另有一些命令只在调试dump文件时有用。

一些命令只在用户模式调试可用,令一些只在内核模式调试有用。

一些命令仅在当目标运行在特定处理器上时才有用。关于这些命令和限制的详细信息,查看调试器命令

编辑、重复和取消命令

输入命令时可以使用标准编辑按键:

  • 用上下方向键查找先前的命令。
  • 使用空格、DELETE、INSERT 和左右方向键编辑当前命令。
  • 用ESC键清除当前行。

可以按下TAB键来自动完成文本输入。在任一款调试器中都可以在输入至少一个字符之后通过按下TAB来自动补完命令。重复按下TAB来循环所有的自动完成命令,或者按下SHIFT和TAB来反向循环。也可以在文本中使用通配符并通过TAB来展开成完整命令。例如,如果输入fo*!ba 并按下TAB,调试器将展开为所有名字以"fo"开头的模块中所有以"ba"开头的符号。又比如,可以通过键入!*prcb 并按下TAB来完成所有包含"prcb"的扩展命令。

当使用TAB自动完成时,如果文本片断以点号(.)开始,文本将会以点命令来匹配。如果以感叹号(!)开始,则以扩展命令来匹配。另外,文本还会和符号进行匹配。使用TAB来输入符号时,按下TAB完成代码和符号以及模块名。如果没有显式指定模块名,则用本地符号和模块来补完。如果给出了模块或者模块的模板,则会按所有匹配的符号来补完。

可以右键点击调试器命令窗口来自动将剪贴板中的内容粘贴到命令中。

命令的最大长度为4096个字符。但是,如果从内核调试其控制用户模式调试器,最大长度为512字符。

在CDB和KD中,按下ENTER会自动重复上一条命令。在WinDbg中,可以启用或禁用这个特性。关于该特性的更多信息,查看ENTER (重复上一条命令)

如果上一条命令产生了很上的输出并且想中断它,可以在CDB和KD中使用CTRL+C 。在WinDbg中,使用Debug | Break 或按下 CTRL+BREAK

在内核模式调试时,可以通过按下CTRL+C中断目标机的命令执行。

使用.cls (清除屏幕)命令清空调试器命令窗口的所有文本。该命令清除所有命令的历史记录。 在WinDbg中,可以使用Edit | Clear Command Output 命令或者在调试器命令窗口的快捷菜单中点击Clear command output来清除命令历史记录。

表达式语法

很多命令和扩展命令都接受表达式作为参数。调试器在执行命令之前先计算这些表达式的值。关于表达式的更多信息,查看表达式计算

别名

别名是用来避免重复键入复杂语句的文本宏。有两种类型的别名。更多信息,查看使用别名

自重复命令

使用如下命令来重复操作或条件执行其他命令:

关于每条命令的更多信息,查看各命令的说明。

控制滚动条

使用滚动条来查看之前的命令和它们的输出。

使用CDB和KD时,所有键盘输入都自动将调试器命令窗口置于窗口底部。

在WinDbg中,当命令产生输出或按下ENTER键时,文本显示都会自动滚动到底部。如果要禁用自动滚动,点击View菜单的Options 并清除Automatically scroll 选择框。

WinDbg文本特性

在WinDbg中,可以使用更多改变文本如何在调试器命令窗口中显示的特性。一些可以在WinDbg窗口中使用,一些可以在调试器命令窗口的快捷菜单中使用,也有一些可以在菜单图标上点击。

  • 快捷菜单的Word wrap命令打开或关闭自动换行。这个命令对所有窗口生效,而并不只是选择这条命令的窗口。由于很多命令和扩展命令都产生格式化的输出,所以一般不建议打开自动换行。
  • Edit | Add to Command Output 菜单命令在调试器命令窗口添加注释。快捷菜单的Add to command output 命令有相同作用。
  • 可以自定义调试器命令窗口的背景和字符颜色。可以为不同类型的文本指定不同颜色。例如,可以以某种颜色显示自动的寄存器输出,用另外一种颜色显示错误信息,再用第三种颜色显示DbgPrint信息。更多信息,查看View | Options
  • 可以使用所有WinDbg调试信息窗口的共有特性,例如自定义字体和使用特殊编辑命令。关于这些特性的更多信息,查看使用调试信息窗口

远程调试

通过调试器进行远程调试时,调试客户端可以访问有限的命令。要修改客户端可以访问的命令数,使用-clines 命令行选项或者 _NT_DEBUG_HISTORY_SIZE 环境变量

表达式计算

调试器能够识别两种表达式类型:MASM表达式C++表达式

如果没有特别指出,本帮助文档示例中使用的是Microsoft宏汇编(MASM)表达式。在MSAM表达式中,所有符号都被当作地址对待。

C++表达式和真实的C++代码中一样,符号被当作适当的数据类型。

每种语法何时被使用

可以使用下面的方法之一来选择默认的表达式类型:

如果没用使用上面任何一种方法,调试器使用MASM表达式。

如果想不改变默认的表达式类型来计算一个表达式,可以使用? (Evaluate Expression) 命令。

除了下面几种例外情况,所有命令和调试器信息窗口都通过默认表达式来解释他们的参数:

  • ?? (Evaluate C++ Expression) 命令总是使用C++ 表达式形式。
  • Watch窗口始终使用C++表达式。
  • Locals窗口始终使用C++ 表达式。
  • 有些扩展命令始终使用MASM表达式(而有一些扩展命令只允许使用数字参数)。
  • 如果将表达式用圆括号括起来,并在表达式前面插入两个at符号(@@),将会使用这种情况下通常使用的表达式形式。

双at符号(@@)使得可以在单个命令中为不同参数使用不同的表达式类型。也可以在长表达式中使用两种不同形式来计算子表达式。双at号可以嵌套。每层@@号都将表达式类型改为另一种。

警告  C++表达式语法用于处理结构和变量很有用,但是用作调试器命令的参数解析器并不适当。使用通常情况下的调试器命令或调试器扩展时,应该将MASM表达式设置为默认类型。如果有某个参数必须使用C++表达式语法时,使用@@号。

关于两种不同类型表达式的更多信息,查看数值表达式语法

表达式中的数字

MASM表达式中的数字根据当前的进制数来进行解释。n (Set Number Base) 命令可以用来将进制设置为16、10或8。所有未加前缀的数字都会按这个进制来解释。默认的进制数可以用0x(16进制)、0n(10进制)、0t(8进制)或0t(2进制)前缀覆盖掉。

在C++表达式中的数字如果没有专门指定,则被认为是10进制数。可以在数字前加上0x 来指定16进制整数,加上0来指定8进制整数。(但是,在调试器的输出中,有时候0n前缀用于8进制整数。)

如果一次想以不同进制数来显示数字,可以使用.formats (Show Number Formats)命令。

表达式中的符号

两种表达式解释符号的方式不同:

  • 在MASM表达式中,所有的符号都解释为地址。根据符号指向的数据的不同,可能是全局变量,本地变量,函数,段,模块或其他可识别标志的地址。
  • 在C++表达式中,符号按照它们的类型来解析。根据符号意义的不同,可能是整数、数据结构、函数指针,或其他数据类型。如果符号和C++数据类型不符合(例如未更改的模块名),则会产生一个语法错误。

如果符号不明确,可以在它前面加上模块名和感叹号(!),或者只加上感叹号。关于符号解析的更多信息,查看符号语法和符号匹配

表达式中的运算符

不同的表达式类型使用不同的运算符集合。

关于MASM表达式中的运算符和他们的运算优先级的更多信息,查看MASM数字和运算符

关于C++表达式的运算符和优先级规则,查看C++ 数字和运算符

MASM运算符都是基于byte的,C++运算符由C++类型决定(包括指针的转换)。

关于不同语法的示例,查看表达式示例

使用外壳命令

调试器可以将一些特定的命令传递给它运行的Microsoft Windows环境。

在 任何Windows 调试器中都可以使用.shell (Command Shell) 命令。该命令可以从调试器直接执行应用程序或者Microsoft MS-DOS命令。如果在进行远程调试,则这些外壳命令在服务端上运行。

.noshell (Prohibit Shell Commands) 命令或-noshell 命令行选项可以禁用所有外壳命令。即使开始了一个新的调试会话,调试器运行时命外壳令还是被禁用。在KD中使用.restart (Restart Kernel Connection)命令之后,外壳命令仍然被禁用。

如果在运行远程调试服务器,可能需要禁用掉外壳命令。因为如果这些命令可用,远程连接可以使用.shell 来修改计算机。

网络驱动器

在WinDbg中,可以用File | Map Network DriveFile | Disconnect Network Drive 菜单命令来控制网络驱动器的映射。这些改变都作用在WinDbg运行的计算机上,而不是远程连接到WinDbg的计算机。

使用别名

别名是用来自动被其他字符串替换的字符串。可以在调试器命令中使用它们来避免重复输入特定的字符串。

别名由别名(alias name)别名等价字符串(alias equivalent)组成。当使用 别名作为调试器命令的一部分时,会被自动替换为等价字符串。这种替换是在命令被解析或执行之前进行的。

调试器支持以下三种别名:

  • 可以设置和命名自定义别名(user-named aliases)
  • 设置固定别名,他们必须名为$u0, $u1, ..., $u9
  • 调试器设置的自动别名(automatic aliases)

定义自定义别名

定义自定义别名时,可以选择别名和等价字符串:

  • 别名可以是不包含空格的任意字符串。
  • 等价字符串可以是任意字符串。如果在键盘上输入,则等价字符串不能包含头部的空格或回车。等价字符串可以是内存中的字符串、数值表达式的值、文件中的内容、环境变量值或一个或多个调试器命令的输出。

别名和等价字符串都是大小写敏感的。

使用as (Set Alias)aS (Set Alias) 命令来定义或修改自定义别名。

使用ad (Delete Alias) 命令删除别名。

列举当前所有自定义别明,使用al (List Aliases)命令。

定义固定别名

有10个固定别名。他们是$u0, $u1, ..., $u9。他们的等价字符串可以是不包含ENTER键的任意字符串。

使用r (Registers) 命令为固定别明指定等价字符串。定义固定别名时,必须在字母"u"之前插入点号(.)。等号(=)之后的文本是等价字符串。等价字符串可以包含空格或分号,但是头部和尾部的空格被忽略掉。不能用引号将等价字符串括起来(除非希望替代结果中包含引号)。

注意  r (Registers)命令设置固定别名容易混淆。这些别明不是寄存器或伪寄存器,即使使用了r命令来设置了他们的等价字符串。这些别名前不需要添加at符号(@),也不能使用r命令来显示这些别明的值。

默认情况下,如果没有定义固定别名,他们是空字符串。

自动别名

调试器预设了下面一些自动别名

别名

等价字符串

$ntnsym

当前系统架构NT符号的最适合的模块。该别名可能是ntdllnt

$ntwsym

使用WOW64的32位调试最适合的NT符号的模块名。该别名可以是ntdll32Ntdll.dll的其他32位版本。

$ntsym

当前机器模式最适合的NT符号的模块名。以本地模式调试时,该别名和$ntnsym一样。当在非本地模式调试时,调试器会尝试找到适合这个模式的模块名。(例如,在使用WOW64的32位调试时,该别明和$ntwsym相同。)

$CurrentDumpFile

调试器上一次加载的dump文件名字。

$CurrentDumpPath

调试器上一次加载的dump文件所在的目录。

$CurrentDumpArchiveFile

调试器上一次加载的dump存档文件(CAB文件)名字。

$CurrentDumpArchivePath

调试器上一次加载的dump存档文件(CAB文件)所在目录。

 

除了可以使用别名相关的字符(例如${ })而伪寄存器不可以使用之外,自动别名和伪寄存器类似。

在调试器命令窗口使用别名

定义了别名之后,可以在任何命令入口中使用。别名会自动被等价字符串替代。因此,可以将别名作为表达式或者宏使用。

即使被引号括起来,别名仍然可以被正确展开。因为等价字符串可以包含任意数量的引号和分号,等价字符串可以代表多个命令。

自定义别名和其他字符之间必须使用空白字符隔开才能被识别。别名的第一个字符之前和最末一个字符之后必须是空格、分号或者引号。

注意  在调试器命令窗口输入的以"as", "aS", "ad", 或者 "al" 开头的文本不会进行别名替换。该限制避免不合适的别名替换。但是,这也意味着一行中跟在adal 之后的命令的别名不会被替换掉。如果想在以这些字符串开头的行中使用别名替换,可以在别名前加上分号。

也可以使用${ }符号来展开和其他文本连在一起的自定义别名。也可以和特定的开关一起使用该符号来避免别名被展开,或者显示特定别名的值。关于这些情况的更多信息,查看${ }  (Alias Interpreter)

不管在文本中嵌入得多深,自定义别名可以在一行的任意位置展开。

只在WinDbg中支持的命令(.open, .write_cmd_hist (Write Command History), .lsrcpath, 和 .lsrcfix)和少数辅助命令 (.hh, .cls, .wtitle, .remote, 内核模式 .restart, 和用户模式 .restart) 不能使用别名。

示例

如下例,可以使用别名来避免输入很长的或很复杂的符号。

0:000> as Short usersrv!NameTooLongToWantToType
0:000> dw Short +8

这个例子和上一个类似,但是使用固定别名。

0:000> r $.u0=usersrv!NameTooLongToWantToType
0:000> dw $u0+8

可以为经常使用的命令定义别名作为宏。下面的示例将eaxebx增加2次。

0:000> as GoUp r eax=eax+1; r ebx=ebx+1
0:000> GoUp
0:000> GoUp

下例使用别名简化命令输入。

0:000> as Cmd "dd esp 14; g"
0:000> bp MyApi Cmd 

下例和上面的示例类似,但是使用固定别名。

0:000> r $.u5="dd esp 14; g"
0:000> bp MyApi $u5 

前面两个示例实际上是下面的命令。

0:000> bp MyApi "dd esp 14; g"

递归的别名

在任何别名的定义中都可以使用固定别名。也可以在固定别名定义中使用自定义别名。但是,要在自定义别名的定义中使用自定义别名,必须在asaS命令前加上分号,否则该行不会进行别名替换。

在这种情况下使用递归别名,每个别名都在使用的地方马上被替换。例如,下面的显示是3,不是7

0:000> r $.u2=2 
0:000> r $.u1=1+$u2 
0:000> r $.u2=6 
0:000> ? $u1 
Evaluate expression: 3 = 00000003

类似的,下例的显示是3,不是7

0:000> as fred 2 
0:000> r $.u1= 1 + fred 
0:000> as fred 6 
0:000> ? $u1 
Evaluate expression: 3 = 00000003

下面的例子也是正确的,并且显示为9

0:000> r $.u0=2 
0:000> r $.u0=7+$u0 
0:000> ? $u0
Evaluate expression: 9 = 00000009

Tools.ini 文件

在 CDB (和NTSD)中,可以在tools.ini 文件中预定义固定别名。 与定义固定别名如下例,在[NTSD]入口中添加需要的$u 域。

[NTSD]
$u1:_ntdll!_RtlRaiseException
$u2:"dd esp 14;g"
$u9:$u1 + 42

不能在Tools.ini文件中设置自定义别名。

固定别名和自定义别名对比

自定义别名比固定别名要更加容易使用。他们的定义更简单,并且可以使用al (List Aliases) 命令列举出来。

固定别名即使和其他文本连在一起也能被替换掉。而将和其他文本连接在一起的自定义别名替换掉需要使用${ }  (Alias Interpreter)标记。

固定别名的替换会在自定义别名替换之前进行。

使用脚本文件

脚本文件是包含调试器命令序列的文本文件。调试器有多种多样的方法来加载和执行它。脚本文件里面的命令可以顺序执行,也可以包含复杂的流程。

可以使用下面的方法之一来执行脚本:

  • (仅在KD和CDB中;调试器启动时) 创建一个名为Ntsd.ini 的脚本文件,并放到启动调试器的目录中。调试器启动之后自动执行该脚本。要为启动脚本使用不同的文件,可以用-cf 命令行选项或者Tools.ini文件中的IniFile入口。
  • (仅在KD和CDB中;每个会话开始时) 创建一个脚本文件并使用-cfr 命令行选项指定它的路径和文件名。 调试器会在每次自己启动和调试目标启动时执行该脚本。
  • 在调试器运行之后使用$<$><$$<$$>< 命令执行脚本文件。关于该语法的更多信息,查看$<, $><, $><, $$>< (Run Script File)

使用$><$$><命令执行脚本和其他方法有一个很重要的不同点。使用它们时,调试器打开指定的脚本文件,并使用分号替换掉所有回车符,然后将替换后的文本作为单个命令块来执行。这几个命令对于包含调试器命令程序的脚本很有用。关于这些程序的更多信息,查看使用调试器命令程序

只在WinDbg中支持的命令(.open, .write_cmd_hist (Write Command History), .lsrcpath (Set Local Source Path), 和 .lsrcfix (Use Local Source Server))不能在脚本文件中使用,即使脚本是在WinDbg中执行的。另外,也不能在脚本文件中使用.hh (Open HTML Help File), .cls (Clear Screen).wtitle (Set Window Title).remote (Create Remote.exe Server) 、内核模式 .restart (Restart Kernel Connection) 和用户模式 .restart (Restart Target pplication) 命令。

注意  除了一个小例外,WinDbgzhichi的脚本和KD、CDB一样。只能在KD或CDB使用的脚本中使用.remote_exit (Exit Debugging Client) 命令。不能在WinDbg执行的脚本中退出一个调试客户端。

posted on 2008-04-22 23:56 NetRoc 阅读(1266) 评论(1)  编辑 收藏 引用 所属分类: WinDbg文档翻译

只有注册用户登录后才能发表评论。

导航

统计

常用链接

留言簿(6)

随笔档案(99)

文章分类(35)

文章档案(32)

Friends

Mirror

搜索

最新评论

阅读排行榜

评论排行榜