2017-09-03 162 views
2

我想調試一個程序,並且對(int i = 0; i < 10; i ++) 感興趣,並且希望在GDB調試器中將i <更改爲i < = 10。我已經使用print來更改變量名稱,但我該如何做到這一點?謝謝。使用GDB更改for循環條件?

+0

gdb無法更改您的代碼,它被設置爲只讀... –

+0

我同意:我認爲有一些工具可以讓你在調試器(Visual Studio)中實際*替換代碼...但是我懷疑gdb是否可以這樣做。 – GhostCat

+0

我想,你可以改變寄存器來跳轉跳轉條件... – arrowd

回答

2

想要更改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上被「遺忘」。