mozilla rr
es una alternativa más sólida a la depuración inversa de GDB
https://github.com/mozilla/rr
El registro y la reproducción integrados de GDB tienen graves limitaciones, por ejemplo, no admite instrucciones AVX: la depuración inversa de gdb falla con "El registro del proceso no admite la instrucción 0xf0d en la dirección"
Ventajas de rr:
- mucho más confiable actualmente. Lo he probado en ejecuciones relativamente largas de varios programas complejos.
- también ofrece una interfaz GDB con el protocolo gdbserver, lo que lo convierte en un excelente reemplazo
- pequeña caída de rendimiento para la mayoría de los programas, no lo he notado sin hacer mediciones
- los rastros generados son pequeños en el disco porque solo se registran muy pocos eventos no deterministas, nunca he tenido que preocuparme por su tamaño hasta ahora
rr logra esto ejecutando primero el programa de una manera que registre lo que sucedió en cada evento no determinista, como un cambio de hilo.
Luego, durante la segunda ejecución de repetición, utiliza ese archivo de seguimiento, que es sorprendentemente pequeño, para reconstruir exactamente lo que sucedió en la ejecución no determinista original pero de una manera determinista, ya sea hacia adelante o hacia atrás.
rr fue desarrollado originalmente por Mozilla para ayudarlos a reproducir errores de sincronización que aparecieron en sus pruebas nocturnas al día siguiente. Pero el aspecto de la depuración inversa también es fundamental para cuando tiene un error que solo ocurre horas dentro de la ejecución, ya que a menudo desea dar un paso atrás para examinar qué estado anterior condujo al error posterior.
El siguiente ejemplo muestra algunas de sus características, en particular los reverse-next
, reverse-step
y reverse-continue
los comandos.
Instalar en 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
Programa de prueba:
#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;
}
compilar y ejecutar:
gcc -O0 -ggdb3 -o reverse.out -std=c89 -Wextra reverse.c
rr record ./reverse.out
rr replay
Ahora está dentro de una sesión de GDB y puede revertir correctamente la depuración:
(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;
Al depurar software complejo, es probable que corra hasta un punto de caída y luego caiga dentro de un marco profundo. En ese caso, no olvide que reverse-next
en marcos superiores, primero debe:
reverse-finish
hasta ese marco, hacer lo habitual up
no es suficiente.
Las limitaciones más graves de rr en mi opinión son:
UndoDB es una alternativa comercial a rr: https://undo.io Ambos están basados en rastreo / reproducción, pero no estoy seguro de cómo se comparan en términos de características y rendimiento.