W tym wpisie chcę zademonstrować prostą sztuczkę, która nie jest jeszcze powszechnie znana, a jest już dostępna od jakiegoś czasu w debugerze GDB. Chodzi o funkcję reverse-exection, która weszła w wersji 7 GDB. Reverse-execution to oczywiście wykonywanie wstecz instrukcji programu.
Zademonstrujmy to może na prostym programie napisanym w C:
#include <stdlib.h>
int main()
{
int x;
x = rand();
x = rand();
x = rand();
return 0;
}
Skompilujmy go z flagami debugowymi:
gcc -g test.c -o test
Jak widać program nie robi nic mądrego, losowo generuje trzy liczby.
Uruchommy ten program w GDB:
gdb ./test
Włączmy wykonywanie programu komendą start:
(gdb) start
...
Temporary breakpoint 1, main () at test.c:7
7 x = rand();
Program powinien zatrzymać się na pierwszej linijce i i tak się dzieje. Aby móc skorzystać z reverse-execution należy włączyć nagrywanie wykonywania kodu:
(gdb) record
Teraz możemy przechodzić po jednej linijce i obserwować jak się zmieniała wartość zmiennej x:
(gdb) next
8 x = rand();
(gdb) print x
$1 = 1804289383
Ale powiedzmy, że zapomnieliśmy sprawdzić, jaką wartość miał wcześniej x, aby to zrobić wykorzystamy instrukcję reverse-next:
(gdb) reverse-next
No more reverse-execution history.
main () at test.c:7
7 x = rand();
(gdb) print x
$2 = 0
Po przednio x miał wartość 0.
Komenda step też ma swój odpowiednik w postaci reverse-step. Nagrywanie nie musi być włączone od razu po uruchomieniu GDB, może ono zostać włączone gdy dotrzemy do problematycznego dla nas fragmentu kodu.
Powyższy przykład jest może nieco głupkowaty, ale w prosty sposób obrazuje jak używać tego mechanizmu. Może się to okazać przydatne podczas analizy kodu, gdzie wykonywane są jakieś złożone operacje i w trakcie jego wykonywania coś przestaje nam się zgadzać, wtedy nie musimy uruchamiać debugera ponownie tylko wystarczy, że wykonamy odpowiednią ilość kroków wstecz.