Chromium Chronicle Nr. 13: Debugging von Zeitreisen mit RR

Folge 13:von Christian Biesinger in Madison, Wisconsin, USA (März 2020)
Vorherige Folgen

Führen Sie immer wieder denselben Test im Debugger aus, um herauszufinden, warum der Code fehlerhaft ist? Wir haben ein Tool für dich! Der Dienst ist einfach zu installieren und einzurichten. Er zeichnet einen Ausführungs-Trace auf, was gdb magische neue Möglichkeiten verleiht. Gehen Sie einen Schritt zurück, laufen Sie zurück und sehen Sie sich an, wo Variablen ihren Wert geändert haben oder wann eine Funktion zuletzt für ein Objekt aufgerufen wurde (mit bedingten Haltepunkten).

Unter Linux können Sie rr verwenden. Installieren Sie das Projekt mit sudo apt-get install rr oder über https://rr-project.org/.

Dies wird offiziell nicht unterstützt, ist aber sehr hilfreich. rr funktioniert so, dass Sie zuerst einen Trace aufzeichnen und dann wiederholen.

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

Praktischerweise bleiben Timing und Zeigeradressen bei jeder Wiedergabe desselben Trace gleich. Traces können mit rr pack portiert werden, sodass Sie sie auf einen anderen Computer kopieren und dort wiedergeben oder auch nach einer Neukompilierung noch einmal wiedergeben können. Führen Sie Ihr Programm mit continue aus. Sie können alle regulären GDB-Befehle -b, next, watch usw. verwenden. Sie können aber auch reverse-next (rn), reverse-cont (rc), reverse-step (rs) und reverse-fin verwenden.

Auch hier werden alle von Ihnen festgelegten Haltepunkte berücksichtigt. Beispiel:

(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 diesem Beispiel habe ich der Einfachheit halber --single-process verwendet, aber das ist nicht erforderlich. RR kann mehrere Prozesse verfolgen. Nach der Aufnahme können Sie mit rr ps eine Liste aufrufen und einen Prozess für die erneute Wiedergabe mit rr replay -f PID auswählen.

RR kann auf viele Arten nützlich sein. Es gibt weitere Befehle, die Sie verwenden können, z. B. wann Sie herausfinden, bei welcher Ereignisnummer Sie sich befinden, oder rr replay -M, um stdout mit einer Prozess-ID und einer Ereignisnummer für jede Zeile zu annotieren. Weitere Informationen finden Sie auf der RR-Website und -Dokumentation.