Debugging Tools for Windows |
三个调试器都可以直接读写内存。这些内存可以用地址或变量名来引用。
可以使用各种命令访问内存或内存区域。
下面的这些命令可以以各种格式读写内存。这些格式包括16进制字节、字(字、双字和4字)、整数(short, long, quad integers 和unsigned integers)、浮点数(10字节、16字节、32字节和64字节实数)、以及ASCII字符。
使用下面一些命令来处理更特殊的数据类型:
使用如下一些命令来操作内存块:
大多数情况下,这些命令都按照当前的基数来解释参数。因此,当前基数不是16时,要在16进制数前加上0x 。但是,这些命令的显示输出不管当前基数是什么,一般是16进制格式。(关于输出的更多信息,查看各个命令的主题。) 内存窗口(Memory window)使用10进制显示整数和实数,用16进制显示其他格式的数据。
使用n (Set Number Base)命令改变当前基数。用 ? (Evaluate Expression) 或.formats (Show Number Formats) 命令来快速的将数字从一种基数转变为另一种。
进行用户模式调试时,虚拟地址的意义由当前进程决定。进行内核模式调试时,虚拟地址的意义可以由调试器控制。更多信息,查看进程上下文。
用 !db, !dc, !dd, !dp, !du, 和!dw扩展命令读取物理内存的内容。
fp (Fill Physical Memory)命令在物理内存范围内写入一个模板,并重复直到内存块被填充满。
内核模式下使用WinDbg时,也可以直接使用Memory 窗口读写物理内存。
在物理内存中搜索一块数据或一个范围内的数据,使用!search扩展命令。
同样,关于物理地址的更多信息,查看将虚拟地址转换为物理地址。
全局变量的名字保存在应用程序编译时创建的符号文件中。调试器将全局变量名转换成虚拟地址。因此,任何接受地址作为参数的命令也可以适用变量名作为参数。
因此,可以使用本主题前面提到的所有命令来读写全局变量。
另外,可以使用? (Evaluate Expression)命令来显示和任何符号关联的地址。
下面例子中,假设需要查看一个32位整数MyCounter 全局变量的值。假设当前的基数为10。
可以用下面的方法得到它的地址并显示它。
Evaluate expression: 1244892 = 0012fedc
0:000> dd 0x0012fedc L1
0012fedc 00000052
第一个命令的输出表明MyCounter 的地址为0x0012FEDC。然后可以使用 D* 命令来显示该地址的一个双字。 (也可以使用1244892,这个地址的10进制值。但是,大多数C程序员会选择使用0x0012FEDC。) 第二条命令表明MyCounter 的值为0x52 (10进制82)。
可以用下面一条命令实现上面这些步骤。
0012fedc 00000052
要将MyCounter 修改为10进制的83,使用下面的命令。
这个例子使用10进制输入,因为这样对于整数来说要自然一些。但是,D* 命令的输出仍然是16进制格式。
局部变量和全局变量类似,也在符号文件中保存了信息。调试器同样会将它们的名字转换为地址。它们可以使用和全局变量一样的方式来读写。但是,如果某个命令需要指明某个符号是局部的,可以对符号使用单个美元符号( $ )和感叹号( ! )前缀,如$!var。
也可以使用下面这些方法来显示、修改和使用局部变量:
但是,局部变量和全局变量有一个主要的不同。当程序运行时,局部变量的意义由程序计数器的位置决定,因为这些变量的作用范围仅在定义它们的函数内部。
调试器根据局部上下文来解释局部变量。默认情况下这个上下文和程序计数器位置匹配。但是调试器可以改变上下文。关于局部上下文的更多信息,查看局部上下文。
当局部上下文被改变时,局部窗口会立即更新以显示新的局部变量集合。DV 命令也显示新的变量。所有这些新的变量都能够被上述的内存命令正确解释,之后就可以读写这些变量了。
调试优化后的代码时,有些局部变量可能被合并(collapsed?)、使用寄存器替代或可能只是临时存放到堆栈中。如果要在调试中使用源码文件或局部变量,最好不要优化代码。
在WinDbg中,也可以使用监视窗口(Watch window)来显示、修改全局和局部变量。
监视窗口可以显示任何需要的变量列表。可以包含全局变量和任何函数的局部变量。任何时候,监视窗口都显示这些变量中和当前函数作用范围匹配的那部分变量。同样可以通过监视窗口修改变量的值。
和局部窗口不同,监视窗口不会受到局部上下文的影响。只有当前的程序计数器作用范围内定义的变量能够被显示和修改。
关于该窗口的更多信息,查看监视窗口。