Windbg 条件断点未按预期工作,我的语法是否正确?
Windbg conditional break point not working as expected, is my syntax correct?
我正在尝试学习如何在 windbg 中设置条件断点,我的程序名为 ConsoleApplication7,如下所示:
int main()
{
int r1 = 0;
r1 += 1;
r1 = 3;
return 0;
}
我用VC编译这个程序。然后在 windbg 中,我设置 "Symbol path" 和 "Source path",在 windbg 中打开 ConsoleApplication7.exe,windbg 运行并打开 .cpp 文件。
在 windbg 里面我设置了一个条件断点,我希望程序应该在 "r1=3".
行
bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"
但是当我按下"g"时,windbg并没有说"Hit breakpoint",只是打印出寄存器信息。 运行 "g" 3次后,程序终止,如下所示:
0:000> bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"
*** WARNING: Unable to verify checksum for ConsoleApplication7.exe
0:000> bl
0 e 01251380 0001 (0001) 0:**** ConsoleApplication7!main "j (poi(r1)>2) ''; 'gc'"
0:000> g
eax=00718918 ebx=7efde000 ecx=0071b880 edx=00000001 esi=00000000 edi=00000000
eip=01251380 esp=002afeb4 ebp=002aff00 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication7!main:
01251380 55 push ebp
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=002afe18 ebp=002afe34 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404 add esp,4
0:000> g
^ No runnable debuggees error in 'g'
其他命令如ba、bp在程序中运行良好,只是条件断点不行。
我的条件语句是否正确?为什么它不起作用?
我尝试了 Dono 回答中的建议,但它显示了另一个问题
0:000> bp ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> bl
0 e 008e143e 0001 (0001) 0:**** ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> g
(4458.4840): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=7efde000 ecx=d3392f75 edx=00000001 esi=00000000 edi=00000000
eip=cccccccc esp=0046f82c ebp=cccccccc iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
cccccccc ?? ???
似乎这个条件断点导致异常?
谢谢!
我也尝试了Blabb的建议,不幸的是,它没有用:
0:000> t "$$>a< c:\autostep.txt"
Couldn't resolve error at 'r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" } '
eax=00000001 ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=001dfcb0
eip=013b13c0 esp=001dfbac ebp=001dfcb0 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication7!f:
013b13c0 55 push ebp
好像C++风格的命令不起作用,所以我把它改成了MASM风格
j (poi(r1)==3)''; 't "$$>a< c:\autostep.txt"'
另存为 c:\autostep.txt
然后我重新启动 windbg 以重新加载它。
0:000> t "$$>a< c:\autostep.txt"
eax=00000000 ebx=00000000 ecx=bc260000 edx=0015dc38 esi=fffffffe edi=00000000
eip=77ba0e15 esp=0042f804 ebp=0042f830 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
ntdll!LdrpDoDebuggerBreak+0x2d:
77ba0e15 8975fc mov dword ptr [ebp-4],esi ss:002b:0042f82c=00000000
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=0042fb94 ebp=0042fbb0 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404 add esp,4
这一次,它没有语法问题,但它并没有像我预期的那样 break/stop。我错过了什么吗?
谢谢。
你的命令意思是:在main函数开始时无条件中断。然后,如果 r1 > 2,什么都不做;否则,继续。
请注意,bp 获取一个地址并在其上中断。因为您有符号 (PDB),所以您可以将符号 "consoleapplication7!main" 转换为地址。这指向函数的开始,r1 甚至还没有被初始化,所以它不可能 > 2,除了随机垃圾值。
所以首先你需要在一个更合理的位置休息。有多种方法可以做到这一点。您可以 "unscramble" 汇编代码 uf consoleapplication7!main
并确定要中断的偏移地址。类似于 bp ConsoleApplication7!main+0x35 "j (poi(r1) > 2) ''; 'gc'"
。这可能有点困难。一种更简单的方法是指定行号,例如 bp `driver.cpp:6` "j (poi(r1) > 2) ''; 'gc'"
,假设您的主要函数位于名为 driver.cpp.
的文件中
此外,您需要注意您的应用程序是为调试模式还是发布模式编译的。在发布模式下,您的大部分主要功能都可以优化掉,因为 r1 的值可以在编译时预先计算。这自然会影响偏移量。
最后,除非您习惯使用 j 来表示 "if",否则我建议使用更现代的 .if (condition) { commands } .else { commands }
语法。虽然他们做同样的事情,但后者更具可读性。
有关详细信息,请参阅 here。
首先你应该知道你的程序将被优化到 xor eax,eax ; ret
除非您在调试模式下编译并使用 /Od 开关明确禁用优化
(我假设您正在调试模式下使用视觉怪物项目来处理这个问题)
其次,您应该知道调试器不知道您的 r1 r2 或其他什么,除非存在符号信息和事件,那么您应该知道有两个表达式计算器 MASM 和 C++,默认情况下 windbg 使用 MASM
? poi(r1) == MASM evaluation
?? r1 == c++ evaluation
否则调试器只理解 cpu 理解的变量,如 BYTE , WORD , DWORD , QWORD .... etc
和地址
当您设置条件断点时,如 bp xxxxxmodule!yyyyysymbol "condition" 条件仅在指定的地址上计算,不在下面
所以你的情况只在主要
上进行了评估
你应该更进一步,评估每一步的条件,直到你遇到一个匹配项
编译后的代码和反汇编的 main() 代码将如下所示
0:000> .dml_flow steptest!main .
<No previous node>
STEPTEST!main (013e6aa0):
e:\test\steptest\steptest.cpp
2 013e6aa0 push ebp
2 013e6aa1 mov ebp,esp
2 013e6aa3 push ecx
3 013e6aa4 mov dword ptr [ebp-4],0
4 013e6aab mov eax,dword ptr [ebp-4]
4 013e6aae add eax,1
4 013e6ab1 mov dword ptr [ebp-4],eax
5 013e6ab4 mov dword ptr [ebp-4],3
6 013e6abb xor eax,eax
7 013e6abd mov esp,ebp
7 013e6abf pop ebp
7 013e6ac0 ret
<No next node>
0:000> lsa .
1: int main()
2: {
3: int r1 = 0;
> 4: r1 += 1;
5: r1 = 3;
6: return 0;
7: }
所以你的条件只能在第 6 行或地址 013e6abb xor eax, eax
的汇编中为真
您设置了一个 conditional bp on 013e6aa0
并且仅在该地址评估条件
你需要找到一种方法直到 013e6abb
那是你应该
step <evaluate> if match stop else repeat step and evaluate until match occurs
为此,将以下行放入名为 autostep.txt 的文件中,并将其保存到 c:\
脚本说明
如果 c++ 表达式 r1 等于 3,则显示 locals else 步骤并再次通过 运行 此脚本重新评估(因此此脚本将在每个指令序列上执行,直到找到匹配项)
.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" }
现在在 windbg 中打开 exe 并执行
bp xxxxmod!main
g
t "$$>a< c:\autostep.txt"
当 r1 为 3 时,windbg 将中断
E:\test\STEPTEST>cdb -c "g steptest!main" STEPTEST.exe
0:000> cdb: Reading initial command 'g steptest!main'
STEPTEST!main:
013e6aa0 55 push ebp
0:000> t "$$>a< c:\autostep.txt"
r1 = 0n3
013e6abb 33c0 xor eax,eax
0:000> ?? r1
int 0n3
0:000> ? poi(r1)
Evaluate expression: 3 = 00000003
0:000> ? &main ; ? &@eip
Evaluate expression: 20867744 = 013e6aa0
Evaluate expression: 20867771 = 013e6abb
0:000>
您可以在 cmd.exe
中调用脚本
cat c:\autostep.txt
.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" }
cdb -c "g steptest!main;$$>a< c:\autostep.txt" STEPTEST.exe
0:000> cdb: Reading initial command 'g steptest!main;$$>a< c:\autostep.txt'
r1 = 0n3
eax=00000001 ebx=7ffd6000 ecx=a4894de4 edx=00000001 esi=00a2dd04 edi=00a2dd08
eip=009d6abb esp=0019f8d0 ebp=0019f8d4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
STEPTEST!main+0x1b:
009d6abb 33c0 xor eax,eax
0:000>
我正在尝试学习如何在 windbg 中设置条件断点,我的程序名为 ConsoleApplication7,如下所示:
int main()
{
int r1 = 0;
r1 += 1;
r1 = 3;
return 0;
}
我用VC编译这个程序。然后在 windbg 中,我设置 "Symbol path" 和 "Source path",在 windbg 中打开 ConsoleApplication7.exe,windbg 运行并打开 .cpp 文件。
在 windbg 里面我设置了一个条件断点,我希望程序应该在 "r1=3".
行bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"
但是当我按下"g"时,windbg并没有说"Hit breakpoint",只是打印出寄存器信息。 运行 "g" 3次后,程序终止,如下所示:
0:000> bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"
*** WARNING: Unable to verify checksum for ConsoleApplication7.exe
0:000> bl
0 e 01251380 0001 (0001) 0:**** ConsoleApplication7!main "j (poi(r1)>2) ''; 'gc'"
0:000> g
eax=00718918 ebx=7efde000 ecx=0071b880 edx=00000001 esi=00000000 edi=00000000
eip=01251380 esp=002afeb4 ebp=002aff00 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication7!main:
01251380 55 push ebp
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=002afe18 ebp=002afe34 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404 add esp,4
0:000> g
^ No runnable debuggees error in 'g'
其他命令如ba、bp在程序中运行良好,只是条件断点不行。
我的条件语句是否正确?为什么它不起作用?
我尝试了 Dono 回答中的建议,但它显示了另一个问题
0:000> bp ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> bl
0 e 008e143e 0001 (0001) 0:**** ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> g
(4458.4840): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=7efde000 ecx=d3392f75 edx=00000001 esi=00000000 edi=00000000
eip=cccccccc esp=0046f82c ebp=cccccccc iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
cccccccc ?? ???
似乎这个条件断点导致异常? 谢谢!
我也尝试了Blabb的建议,不幸的是,它没有用:
0:000> t "$$>a< c:\autostep.txt"
Couldn't resolve error at 'r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" } '
eax=00000001 ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=001dfcb0
eip=013b13c0 esp=001dfbac ebp=001dfcb0 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication7!f:
013b13c0 55 push ebp
好像C++风格的命令不起作用,所以我把它改成了MASM风格
j (poi(r1)==3)''; 't "$$>a< c:\autostep.txt"'
另存为 c:\autostep.txt 然后我重新启动 windbg 以重新加载它。
0:000> t "$$>a< c:\autostep.txt"
eax=00000000 ebx=00000000 ecx=bc260000 edx=0015dc38 esi=fffffffe edi=00000000
eip=77ba0e15 esp=0042f804 ebp=0042f830 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000244
ntdll!LdrpDoDebuggerBreak+0x2d:
77ba0e15 8975fc mov dword ptr [ebp-4],esi ss:002b:0042f82c=00000000
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=0042fb94 ebp=0042fbb0 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404 add esp,4
这一次,它没有语法问题,但它并没有像我预期的那样 break/stop。我错过了什么吗?
谢谢。
你的命令意思是:在main函数开始时无条件中断。然后,如果 r1 > 2,什么都不做;否则,继续。
请注意,bp 获取一个地址并在其上中断。因为您有符号 (PDB),所以您可以将符号 "consoleapplication7!main" 转换为地址。这指向函数的开始,r1 甚至还没有被初始化,所以它不可能 > 2,除了随机垃圾值。
所以首先你需要在一个更合理的位置休息。有多种方法可以做到这一点。您可以 "unscramble" 汇编代码 uf consoleapplication7!main
并确定要中断的偏移地址。类似于 bp ConsoleApplication7!main+0x35 "j (poi(r1) > 2) ''; 'gc'"
。这可能有点困难。一种更简单的方法是指定行号,例如 bp `driver.cpp:6` "j (poi(r1) > 2) ''; 'gc'"
,假设您的主要函数位于名为 driver.cpp.
此外,您需要注意您的应用程序是为调试模式还是发布模式编译的。在发布模式下,您的大部分主要功能都可以优化掉,因为 r1 的值可以在编译时预先计算。这自然会影响偏移量。
最后,除非您习惯使用 j 来表示 "if",否则我建议使用更现代的 .if (condition) { commands } .else { commands }
语法。虽然他们做同样的事情,但后者更具可读性。
有关详细信息,请参阅 here。
首先你应该知道你的程序将被优化到 xor eax,eax ; ret
除非您在调试模式下编译并使用 /Od 开关明确禁用优化
(我假设您正在调试模式下使用视觉怪物项目来处理这个问题)
其次,您应该知道调试器不知道您的 r1 r2 或其他什么,除非存在符号信息和事件,那么您应该知道有两个表达式计算器 MASM 和 C++,默认情况下 windbg 使用 MASM
? poi(r1) == MASM evaluation
?? r1 == c++ evaluation
否则调试器只理解 cpu 理解的变量,如 BYTE , WORD , DWORD , QWORD .... etc
和地址
当您设置条件断点时,如 bp xxxxxmodule!yyyyysymbol "condition" 条件仅在指定的地址上计算,不在下面 所以你的情况只在主要
上进行了评估你应该更进一步,评估每一步的条件,直到你遇到一个匹配项
编译后的代码和反汇编的 main() 代码将如下所示
0:000> .dml_flow steptest!main .
<No previous node>
STEPTEST!main (013e6aa0):
e:\test\steptest\steptest.cpp
2 013e6aa0 push ebp
2 013e6aa1 mov ebp,esp
2 013e6aa3 push ecx
3 013e6aa4 mov dword ptr [ebp-4],0
4 013e6aab mov eax,dword ptr [ebp-4]
4 013e6aae add eax,1
4 013e6ab1 mov dword ptr [ebp-4],eax
5 013e6ab4 mov dword ptr [ebp-4],3
6 013e6abb xor eax,eax
7 013e6abd mov esp,ebp
7 013e6abf pop ebp
7 013e6ac0 ret
<No next node>
0:000> lsa .
1: int main()
2: {
3: int r1 = 0;
> 4: r1 += 1;
5: r1 = 3;
6: return 0;
7: }
所以你的条件只能在第 6 行或地址 013e6abb xor eax, eax
您设置了一个 conditional bp on 013e6aa0
并且仅在该地址评估条件
你需要找到一种方法直到 013e6abb
那是你应该
step <evaluate> if match stop else repeat step and evaluate until match occurs
为此,将以下行放入名为 autostep.txt 的文件中,并将其保存到 c:\
脚本说明
如果 c++ 表达式 r1 等于 3,则显示 locals else 步骤并再次通过 运行 此脚本重新评估(因此此脚本将在每个指令序列上执行,直到找到匹配项)
.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" }
现在在 windbg 中打开 exe 并执行
bp xxxxmod!main
g
t "$$>a< c:\autostep.txt"
当 r1 为 3 时,windbg 将中断
E:\test\STEPTEST>cdb -c "g steptest!main" STEPTEST.exe
0:000> cdb: Reading initial command 'g steptest!main'
STEPTEST!main:
013e6aa0 55 push ebp
0:000> t "$$>a< c:\autostep.txt"
r1 = 0n3
013e6abb 33c0 xor eax,eax
0:000> ?? r1
int 0n3
0:000> ? poi(r1)
Evaluate expression: 3 = 00000003
0:000> ? &main ; ? &@eip
Evaluate expression: 20867744 = 013e6aa0
Evaluate expression: 20867771 = 013e6abb
0:000>
您可以在 cmd.exe
中调用脚本cat c:\autostep.txt
.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" }
cdb -c "g steptest!main;$$>a< c:\autostep.txt" STEPTEST.exe
0:000> cdb: Reading initial command 'g steptest!main;$$>a< c:\autostep.txt'
r1 = 0n3
eax=00000001 ebx=7ffd6000 ecx=a4894de4 edx=00000001 esi=00a2dd04 edi=00a2dd08
eip=009d6abb esp=0019f8d0 ebp=0019f8d4 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
STEPTEST!main+0x1b:
009d6abb 33c0 xor eax,eax
0:000>