使用GDB更改for循环条件?
问题描述:
我想调试一个程序,并且对(int i = 0; i < 10; i ++) 感兴趣,并且希望在GDB调试器中将i <更改为i < = 10。我已经使用print来更改变量名称,但我该如何做到这一点?谢谢。使用GDB更改for循环条件?
答
想要更改i < 10到i < = 10在GDB调试器中。
有几种方法可以做到这一点,这取决于正好你需要什么。
我假设你只需要做一次这样的事情,即你的二进制文件没有经过优化就构建了x86_64
。
鉴于:
#include <stdio.h>
int main()
{
for (int i = 0; i < 10; i++)
printf("%d\n", i);
return 0;
}
gcc -g -std=c99 t.c && gdb -q ./a.out
gdb) disas main
Dump of assembler code for function main:
0x000000000040052d <+0>: push %rbp
0x000000000040052e <+1>: mov %rsp,%rbp
0x0000000000400531 <+4>: sub $0x10,%rsp
0x0000000000400535 <+8>: movl $0x0,-0x4(%rbp)
0x000000000040053c <+15>: jmp 0x400556 <main+41>
0x000000000040053e <+17>: mov -0x4(%rbp),%eax
0x0000000000400541 <+20>: mov %eax,%esi
0x0000000000400543 <+22>: mov $0x4005f4,%edi
0x0000000000400548 <+27>: mov $0x0,%eax
0x000000000040054d <+32>: callq 0x400410 <[email protected]>
0x0000000000400552 <+37>: addl $0x1,-0x4(%rbp)
0x0000000000400556 <+41>: cmpl $0x9,-0x4(%rbp)
0x000000000040055a <+45>: jle 0x40053e <main+17>
0x000000000040055c <+47>: mov $0x0,%eax
0x0000000000400561 <+52>: leaveq
0x0000000000400562 <+53>: retq
End of assembler dump.
在这里可以看到,在地址0x400556
指令(在位置$rbp-4
存储在栈)具有恒定9
比较的i
值,并跳回如果该值小于或等于到9
。
所以,你可以在0x40055a
设置指令断点,然后即使编译后的代码表示,它不应该采取力跳:
(gdb) b *0x40055a if i == 10
Breakpoint 1 at 0x40055a: file t.c, line 4.
(gdb) run
Starting program: /tmp/a.out
0
1
2
3
4
5
6
7
8
9
Breakpoint 1, 0x000000000040055a in main() at t.c:4
4 for (int i = 0; i < 10; i++)
(gdb) p i
$1 = 10
(gdb) jump *0x40053e
Continuing at 0x40053e.
10
[Inferior 1 (process 22210) exited normally]
瞧:我们已经印制一个额外的价值。
另一个可能的方法:设置指令断点在0x400556
,的i
值调整为i-1
,单步骤中,i
值调整为i+1
,继续。
另一种方法:
(gdb) disas/r 0x400556,0x400557
Dump of assembler code from 0x400556 to 0x400557:
0x0000000000400556 <main+41>: 83 7d fc 09 cmpl $0x9,-0x4(%rbp)
End of assembler dump.
在这里你可以看到,不断9
是指令字节的一部分,特别是在字节:二进制补丁在0x400556
指令以恒定10
代替9
比较地址0x400559
。您可以更改字节:
(gdb) start
Starting program: /tmp/a.out
Temporary breakpoint 1, main() at t.c:4
4 for (int i = 0; i < 10; i++)
让我们覆盖的指令,再拆卸:
(gdb) set *(char*)0x400559 = 10
(gdb) disas/r 0x400556,0x400557
Dump of assembler code from 0x400556 to 0x400557:
0x0000000000400556 <main+41>: 83 7d fc 0a cmpl $0xa,-0x4(%rbp)
End of assembler dump.
看起来不错:我们现在比较10
而不是9
。它工作吗?
(gdb) c
Continuing.
0
1
2
3
4
5
6
7
8
9
10
[Inferior 1 (process 23131) exited normally]
是的,它的确如此!
P.S.二进制修补指令相当于编辑源代码并重新构建二进制文件,除了该补丁在下一个run
上被“遗忘”。
gdb无法更改您的代码,它被设置为只读... –
我同意:我认为有一些工具可以让你在调试器(Visual Studio)中实际*替换代码...但是我怀疑gdb是否可以这样做。 – GhostCat
我想,你可以改变寄存器来跳转跳转条件... – arrowd