Chromium Chronicle #13: Отладка путешествий во времени с помощью RR

Эпизод 13: Кристиан Бизингер, Мэдисон, Висконсин (март 2020 г.)
Предыдущие серии

Случается ли вам, что вы снова и снова запускаете один и тот же тест в отладчике, пытаясь выяснить, почему код оказался в плохом состоянии? У нас есть инструмент для вас! Он прост в установке и настройке, записывает трассировку выполнения, что дает gdb новые волшебные возможности. Сделайте шаг назад, бегите назад , посмотрите, где переменные изменили свое значение или когда функция в последний раз вызывалась для объекта (с использованием условных точек останова).

В Linux вы можете использовать rr . Установите с помощью sudo apt-get install rr или с https://rr-project.org/ .

Это официально не поддерживается, но очень полезно. Принцип работы rr заключается в том, что вы сначала записываете трассировку , а затем воспроизводите ее .

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

Удобно, что адреса времени и указателя остаются неизменными каждый раз, когда вы воспроизводите одну и ту же трассу. Трассировки можно сделать переносимыми с помощью rr pack , чтобы их можно было скопировать на другую машину и воспроизвести там или воспроизвести даже после перекомпиляции. Запустите программу, используя continue . Вы можете использовать все обычные команды GDB -b , next , watch и т.д. Однако вы также можете использоватьverse -next ( rn ), reverse-cont ( rc ), reverse-step ( rs ), reverse-fin .

Они по-прежнему учитывают любые установленные вами точки останова. Например:

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

В этом примере я использовал --single-process для простоты, но это не обязательно. RR может отслеживать несколько процессов ; после записи вы можете просмотреть список с помощью rr ps и выбрать один для воспроизведения с помощью rr replay -f PID .

Есть много способов, которыми RR может быть полезен. Вы можете использовать и другие команды , например, When, чтобы узнать, на каком номере события вы находитесь, или rr replay -M , чтобы пометить stdout идентификатором процесса и номером события для каждой строки. Дополнительную информацию см. на веб-сайте RR и в документации .