假设我想使用适用于Windows的WinDbg,cdb或ntsd调试器调试此程序:
/* test.c */
#include <stdio.h>
int rip = 42;
int main(void)
{
puts("Hello world!");
return (0);
}
我为AMD64编译程序并在WinDbg下运行它。我在main()处设置断点,当断点命中时,我想检查RIP寄存器(程序计数器)的值,如果该值被视为指针,则检查该值周围的内存。
我可以直接用r rip
看到寄存器的值,但是当我尝试查看该地址周围的内存时,WinDbg会向我显示不同的地址!读完test.pdb中的符号后,WinDbg看到rip
是C代码中声明的全局变量,并向我显示&rip
周围的内存。
0:000> bu test!main
0:000> g
Breakpoint 0 hit
test!main:
00007ff6`de1868d0 4883ec28 sub rsp,28h
0:000> r rip
rip=00007ff6de1868d0
0:000> db rip
00007ff6`de1f2000 2a 00 00 00 ff ff ff ff-01 00 00 00 00 00 00 00 *...............
00007ff6`de1f2010 01 00 00 00 02 00 00 00-ff ff ff ff ff ff ff ff ................
00007ff6`de1f2020 00 00 00 00 00 00 00 00-43 46 92 e5 1b df 00 00 ........CF......
00007ff6`de1f2030 bc b9 6d 1a e4 20 ff ff-00 00 00 00 00 00 00 00 ..m.. ..........
00007ff6`de1f2040 00 01 00 00 00 00 00 00-ca b0 1e de f6 7f 00 00 ................
00007ff6`de1f2050 00 00 00 00 00 80 00 00-00 00 00 00 00 80 00 00 ................
00007ff6`de1f2060 d0 66 fc c2 f2 01 03 00-ab 90 ec 5e 22 c0 b2 44 .f.........^"..D
00007ff6`de1f2070 a5 dd fd 71 6a 22 2a 15-00 00 00 00 00 00 00 00 ...qj"*.........
0:000> ? rip
Evaluate expression: 140698265264128 = 00007ff6`de1f2000
0:000> ? dwo(rip)
Evaluate expression: 42 = 00000000`0000002a
这真的很烦人,但只要我知道它,手动读取这样的数据就不是问题了。但是,如果我想使用寄存器值,例如在编写调试器脚本时,则没有简单的解决方法:
0:000> bu test!main ".if (dwo(rip) == 0n42) { .echo Whoops! I don't want to get here! }"
0:000> g
Whoops! I don't want to get here!
test!main:
00007ff6`de1868d0 4883ec28 sub rsp,28h
这个问题,程序中的符号隐藏了寄存器名称,这对我来说非常困难。这破坏了一个实际情况:
foobar!rcx
,并且我在命令中对rcx
的任何引用都是在断点上执行的,这是指全局变量<!/ LI>
醇>
那么如何告诉WinDbg是的,我真的想读取寄存器?如果我想写那个寄存器怎么办?我必须在这里找到一件简单的事情。
答案 0 :(得分:5)
如通过another question所述,您可以在寄存器名称前加上一个符号(@
),以强制它被解释为寄存器或伪寄存器,绕过该尝试将其解析为十六进制数字或符号。
Registers and Pseudo-Registers in MASM Expressions
您可以在MASM表达式中使用寄存器和伪寄存器。 您可以在所有寄存器和伪寄存器之前添加at符号(@)。 at符号使调试器更快地访问该值。对于最常见的基于x86的寄存器,此符号是不必要的。对于其他寄存器和伪寄存器,我们建议您添加at符号,但实际上并不需要。如果省略不常见寄存器的at符号,调试器会尝试将文本解析为十六进制数,然后作为符号解析,最后作为寄存器。