Reputation: 33
I am trying to debug a program and am interested in the line for(int i =0; i<10; i++) and want to change i <10 to i<=10 in the GDB debugger. I've used print to change variable names, but how do I do it for this? Thank you.
Upvotes: 3
Views: 1597
Reputation: 213799
want to change i <10 to i<=10 in the GDB debugger.
There are few ways to do this, depending on exactly what you need.
I'll assume that you simply need to do this once, that your binary is built without optimizations, on x86_64
.
Given:
#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 <printf@plt>
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.
Here you can see that the instruction at address 0x400556
compares value of i
(stored on stack in location $rbp-4
) with constant 9
, and jumps back if the value is less than or equal to 9
.
So you can set a breakpoint on instruction at 0x40055a
, and then force the jump to be taken even when the compiled code says it shouldn't be:
(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]
Voila: we've printed an extra value.
Another possible approach: set a breakpoint on instruction at 0x400556
, adjust the value of i
to i-1
, single-step, adjust the value of i
to i+1
, continue.
Yet another approach: binary patch the instruction at 0x400556
to compare with constant 10
instead of 9
:
(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.
Here you can see that the constant 9
is part of the instruction bytes, in particular the byte at address 0x400559
. You can change that byte:
(gdb) start
Starting program: /tmp/a.out
Temporary breakpoint 1, main () at t.c:4
4 for (int i = 0; i < 10; i++)
Let's overwrite the instruction and disassemble again:
(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.
Looks good: we now compare to 10
instead of 9
. Does it work?
(gdb) c
Continuing.
0
1
2
3
4
5
6
7
8
9
10
[Inferior 1 (process 23131) exited normally]
Yes, it does!
P.S. Binary-patching the instruction is equivalent to editing the source and rebuilding the binary, except the patch is "forgotten" on next run
.
Upvotes: 3