mozilla rr
jest solidniejszą alternatywą dla odwrotnego debugowania GDB
https://github.com/mozilla/rr
Wbudowany zapis i odtwarzanie GDB ma poważne ograniczenia, np. Brak obsługi instrukcji AVX: odwrotne debugowanie gdb kończy się niepowodzeniem z komunikatem „Rekord procesu nie obsługuje instrukcji 0xf0d pod adresem”
Zalety rr:
- obecnie znacznie bardziej niezawodny. Przetestowałem to stosunkowo długie serie kilku złożonych programów.
- oferuje również interfejs GDB z protokołem gdbserver, dzięki czemu jest świetnym zamiennikiem
- mały spadek wydajności dla większości programów, sam tego nie zauważyłem bez wykonywania pomiarów
- generowane ślady są małe na dysku, ponieważ zapisywanych jest bardzo niewiele zdarzeń niedeterministycznych, do tej pory nigdy nie musiałem martwić się o ich rozmiar
rr osiąga to, najpierw uruchamiając program w sposób, który rejestruje to, co się wydarzyło przy każdym niedeterministycznym zdarzeniu, takim jak zmiana wątku.
Następnie podczas drugiego przebiegu powtórki używa tego pliku śledzenia, który jest zaskakująco mały, do rekonstrukcji dokładnie tego, co wydarzyło się w pierwotnym niedeterministycznym przebiegu, ale w sposób deterministyczny, do przodu lub do tyłu.
rr został pierwotnie opracowany przez Mozillę, aby pomóc im odtworzyć błędy synchronizacji, które pojawiły się podczas ich nocnych testów następnego dnia. Ale aspekt odwrotnego debugowania jest również fundamentalny w przypadku błędu, który pojawia się tylko godzinami w trakcie wykonywania, ponieważ często chcesz cofnąć się, aby zbadać, jaki poprzedni stan doprowadził do późniejszej awarii.
Poniższy przykład prezentuje niektóre z jego cech, szczególnie te reverse-next
, reverse-step
i reverse-continue
poleceń.
Zainstaluj na Ubuntu 18.04:
sudo apt-get install rr linux-tools-common linux-tools-generic linux-cloud-tools-generic
sudo cpupower frequency-set -g performance
# Overcome "rr needs /proc/sys/kernel/perf_event_paranoid <= 1, but it is 3."
echo 'kernel.perf_event_paranoid=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Program testowy:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int f() {
int i;
i = 0;
i = 1;
i = 2;
return i;
}
int main(void) {
int i;
i = 0;
i = 1;
i = 2;
/* Local call. */
f();
printf("i = %d\n", i);
/* Is randomness completely removed?
* Recently fixed: https://github.com/mozilla/rr/issues/2088 */
i = time(NULL);
printf("time(NULL) = %d\n", i);
return EXIT_SUCCESS;
}
skompiluj i uruchom:
gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay
Teraz jesteś w sesji GDB i możesz poprawnie odwrócić debugowanie:
(rr) break main
Breakpoint 1 at 0x55da250e96b0: file a.c, line 16.
(rr) continue
Continuing.
Breakpoint 1, main () at a.c:16
16 i = 0;
(rr) next
17 i = 1;
(rr) print i
$1 = 0
(rr) next
18 i = 2;
(rr) print i
$2 = 1
(rr) reverse-next
17 i = 1;
(rr) print i
$3 = 0
(rr) next
18 i = 2;
(rr) print i
$4 = 1
(rr) next
21 f();
(rr) step
f () at a.c:7
7 i = 0;
(rr) reverse-step
main () at a.c:21
21 f();
(rr) next
23 printf("i = %d\n", i);
(rr) next
i = 2
27 i = time(NULL);
(rr) reverse-next
23 printf("i = %d\n", i);
(rr) next
i = 2
27 i = time(NULL);
(rr) next
28 printf("time(NULL) = %d\n", i);
(rr) print i
$5 = 1509245372
(rr) reverse-next
27 i = time(NULL);
(rr) next
28 printf("time(NULL) = %d\n", i);
(rr) print i
$6 = 1509245372
(rr) reverse-continue
Continuing.
Breakpoint 1, main () at a.c:16
16 i = 0;
Podczas debugowania złożonego oprogramowania prawdopodobnie dojdziesz do punktu awarii, a następnie wpadniesz w głęboką ramkę. W takim przypadku nie zapominaj, że reverse-next
w przypadku wyższych klatek musisz najpierw:
reverse-finish
do tej klatki, zwykłe robienie tego up
nie wystarczy.
Moim zdaniem najpoważniejsze ograniczenia rr to:
UndoDB to komercyjna alternatywa dla rr: https://undo.io Oba są oparte na śledzeniu / odtwarzaniu, ale nie jestem pewien, jak się porównują pod względem funkcji i wydajności.