Chromium Chronicle #13: Gỡ lỗi du hành thời gian bằng RR

Tập 13: của Christian Biesinger tại Madison, WI (tháng 3 năm 2020)
Các tập trước

Bạn thấy mình chạy đi chạy lại cùng một quy trình kiểm thử trong trình gỡ lỗi, cố gắng tìm hiểu tại sao mã lại ở trạng thái xấu? Chúng tôi có một công cụ dành cho bạn! Sản phẩm này dễ cài đặt và thiết lập, ghi lại dấu vết thực thi, đồng thời cung cấp cho sức mạnh mới diệu kỳ để gdb. Lùi, chạy lùi, xem vị trí các biến đã thay đổi giá trị của mình hoặc thời điểm một hàm được gọi gần đây nhất trên một đối tượng (sử dụng điểm ngắt có điều kiện).

Trên Linux, bạn có thể sử dụng rr. Cài đặt bằng sudo apt-get install rr hoặc tại https://rr-project.org/.

Tính năng này không được hỗ trợ chính thức, nhưng rất hữu ích. Cách rr hoạt động là bạn ghi lại một dấu vết trước rồi phát lại dấu vết đó.

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

Một cách thuận tiện là thời gian và địa chỉ con trỏ luôn giữ nguyên mỗi khi bạn phát lại cùng một dấu vết. Dấu vết có thể được chuyển sang chế độ di động bằng rr pack để bạn có thể sao chép chúng vào một máy khác và phát lại ở đó hoặc phát lại ngay cả khi biên dịch lại. Chạy chương trình bằng continue. Bạn có thể sử dụng tất cả các GDB lệnh -b, next, watch, v.v. Tuy nhiên, bạn cũng có thể sử dụng đảo ngược tiếp theo (rn), đảo ngược (rc), bước đảo ngược (rs), vây ngược.

Các điểm ngắt này vẫn tuân theo mọi điểm ngắt mà bạn đã đặt. Ví dụ:

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

Trong ví dụ này, tôi đã sử dụng --single-process để đơn giản hoá, nhưng đó là là không cần thiết. RR có thể theo dõi nhiều quá trình; sau khi ghi, bạn có thể xem danh sách bằng rr ps rồi chọn một danh sách để phát lại bằng rr replay -f PID.

Có rất nhiều cách hữu ích RR. Bạn có thể sử dụng các lệnh khác, chẳng hạn như thời điểm tìm hiểu sự kiện bạn đang tham gia hoặc rr replay -M để chú thích stdout bằng mã quy trình và số sự kiện cho mỗi dòng. Xem trang web và tài liệu về RR để biết thêm thông tin.