Chromium Chronicle n°13: débogage du voyage dans le temps avec RR

Épisode 13:Christian Biesinger à Madison, Wisconsin (mars 2020)
Épisodes précédents

Vous arrive-t-il d'exécuter le même test de façon répétée dans le débogueur pour essayer de comprendre comment le code est arrivé dans un état incorrect ? Nous avons un outil pour vous ! Facile à installer et à configurer, il enregistre une trace d'exécution, ce qui donne de nouveaux pouvoirs magiques à gdb. Remontez, exécutez en arrière pour voir où les variables ont modifié leur valeur ou quand une fonction a été appelée pour la dernière fois sur un objet (à l'aide de points d'arrêt conditionnels).

Sous Linux, vous pouvez utiliser rr. Effectuez l'installation à l'aide de sudo apt-get install rr ou depuis https://rr-project.org/.

Cette fonctionnalité n'est pas officiellement prise en charge, mais elle est très utile. Pour utiliser rr, vous devez d'abord enregistrer une trace, puis la relire.

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

Idéalement, les adresses de codes temporels et les adresses de pointeur restent identiques chaque fois que vous répétez la même trace. Les traces peuvent être rendues portables à l'aide de rr pack, ce qui vous permet de les copier sur une autre machine et de les relire sur cet ordinateur, ou de les répéter même après la recompilation. Exécutez votre programme à l'aide de continue. Vous pouvez utiliser toutes les commandes GDB standards -b, next, watch, etc. Toutefois, vous pouvez également utiliser reverse-next (rn), reverse-cont (rc), reverse-step (rs) et reverse-fin.

Ceux-ci respectent toujours les points d'arrêt que vous avez définis. Exemple :

(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*> (

Dans cet exemple, j'ai utilisé --single-process par souci de simplicité, mais ce n'est pas nécessaire. RR peut tracer plusieurs processus. Après l'enregistrement, vous pouvez afficher une liste à l'aide de rr ps et en sélectionner un à relire avec rr replay -f PID.

RR peut être utile de nombreuses façons. Vous pouvez utiliser d'autres commandes, par exemple quand savoir à quel numéro d'événement vous vous trouvez, ou rr replay -M pour annoter stdout avec un ID de processus et un numéro d'événement pour chaque ligne. Pour en savoir plus, consultez le site Web et la documentation de RR.