Episodio 13: de Christian Biesinger en Madison, WI (marzo de 2020)
Episodios anteriores
¿Ejecutas la misma prueba una y otra vez en el depurador para intentar averiguar cómo entró en mal estado el código? Tenemos una herramienta para ti.
Es fácil de instalar y configurar, registra un seguimiento de ejecución y eso le otorga nuevos poderes mágicos a gdb
. Retrocede, ejecuta hacia atrás y consulta dónde cambiaron su valor las variables o cuándo se llamó por última vez a una función en un objeto (mediante puntos de interrupción condicionales).
En Linux, puedes usar rr. Instálalo con sudo apt-get install rr
o desde https://rr-project.org/.
No se admite oficialmente, pero es muy útil. La forma en que funciona rr
es que primero registras un seguimiento y, luego, lo vuelves a reproducir.
rr record .../content_shell --no-sandbox --disable-hang-monitor --single-process
# record the trace. --single-process is optional, see below. The other flags are required.
rr replay # This will replay the last trace
(gdb) # rr uses GDB to let you replay traces
De manera conveniente, la sincronización y las direcciones del puntero se mantienen iguales cada vez que vuelves a reproducir el mismo seguimiento. Los registros se pueden convertir en portátiles con rr pack
, de modo que puedas copiarlos en otra máquina y volver a reproducirlos allí o reproducirlos incluso después de volver a compilarlos. Ejecuta el programa con continue
. Puedes usar todos los comandos de GDB normales -b
, next
, watch
, etc. Sin embargo, también puedes usar reverse-next (rn
), reverse-cont (rc
), reverse-step (rs
) y reverse-fin.
Estas seguirán respetando los puntos de interrupción que hayas establecido. Por ejemplo:
(gdb) c # Execute to the end
(gdb) break blink::LayoutFlexibleBox::UpdateLayout
(gdb) rc # Run back to the last layout call
Thread 5 hit Breakpoint 1, blink::LayoutBlock::UpdateLayout (
this=0x121672224010)
(gdb) # Inspect anything you want here. To find the previous Layout call on this object:
(gdb) cond 1 this == 0x121672224010
(gdb) rc
Thread 5 hit Breakpoint 1, blink::LayoutBlock::UpdateLayout (
this=0x121672224010)
(gdb) watch -l style_.ptr_ # Or find the last time the style_ was changed
(gdb) rc
Thread 5 hit Hardware watchpoint 2: -location style_.ptr_
Old value = (const blink::ComputedStyle *) 0x1631ad3dbb0
New value = (const blink::ComputedStyle *) 0x0
0x00007f68cabcf78e in std::__Cr::swap<blink::ComputedStyle const*> (
En este ejemplo, usé --single-process
para simplificar, pero no es necesario. RR puede hacer un seguimiento de varios procesos. Después del registro, puedes ver una lista con rr ps
y elegir uno para volver a reproducirlo con rr replay -f PID
.
RR puede ser útil de muchas maneras. Hay otros comandos que puedes usar, como cuándo averiguar el número de evento en el que te encuentras o rr replay -M
para anotar stdout
con un ID de proceso y un número de evento para cada línea. Consulta el sitio web y la documentación de RR para obtener más detalles.