The Chromium Chronicle n. 13: debug per i viaggi nel tempo con RR

Episodio 13: di Christian Biesinger in Madison, WI (marzo 2020)
Puntate precedenti

Ti ritrovi a eseguire lo stesso test più volte nel debugger, cercando di capire come il codice non funzionasse? Abbiamo uno strumento per te. Facile da installare e configurare, registrerà una traccia di esecuzione e conferisce magici nuovi poteri a gdb. Fai un passo indietro, esegui a ritroso, vedi dove le variabili hanno modificato il loro valore o l'ultima volta che una funzione è stata chiamata su un oggetto (utilizzando i punti di interruzione condizionali).

Su Linux, puoi utilizzare rr. Installa utilizzando sudo apt-get install rr o da https://rr-project.org/.

Questa funzionalità non è ufficialmente supportata, ma è molto utile. rr funziona per registrare una traccia, quindi ririprodurla.

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

In pratica, gli indirizzi di sincronizzazione e puntatore rimangono invariati ogni volta che ripeti la stessa traccia. Le tracce possono essere rese portabili utilizzando rr pack in modo da copiarle su un'altra macchina e riprodurle da lì oppure riprodurle anche dopo la ricompilazione. Esegui il programma utilizzando continue. Puoi utilizzare tutti i normali comandi GDB -b, next, watch e così via. Tuttavia, puoi anche utilizzare reverse-next (rn), reverse-cont (rc), reverse-step (rs), reverse-fin.

Questi punti di interruzione rispettano comunque gli eventuali punti di interruzione impostati. Ad esempio:

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

In questo esempio, ho utilizzato --single-process per semplicità, ma non è necessario. RR può tracciare più processi; dopo la registrazione, puoi visualizzare un elenco utilizzando rr ps e selezionarne uno da riprodurre con rr replay -f PID.

RR può essere utile in molti modi. Puoi utilizzare altri comandi, ad esempio quando scoprire a quale numero di evento ti trovi oppure rr replay -M per annotare stdout con un ID processo e un numero di evento per ogni riga. Per ulteriori dettagli, consulta il sito web e la documentazione di RR.