Notes on Intel Processor Trace

2021-11-26 | Tags: #research

Intel® PT: Intel Processor Trace is a hardware support that can track branches on Intel processors at hardware level. Afterwards, the control flow graph can be extracted with the collected outputs.

Packets

Packet Meaning Generation
TNT Taken Not-Taken On a conditional branch or compressed RET
TIP Target IP Indirect branch (including un-compressed RET)
TIP.PGE Packet Generation Enable Any branch instruction, control flow transfer
  • Some of these packets can have dependencies.
  • TIP.PGE packets also includes target IP's

Perf

Intel-pt linux kernel 4 versiyonu ile birlikte perf ile birlikte kullanılabiliyor. Bunun sayesinde herhangi ekstra bir kütüphaneye gerek kalmadan processor trace özelliğini kullanabiliyoruz. En basit örneklerden birisi:

$ sudo perf record -e intel_pt//u ls
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0,177 MB perf.data ]

Burada //u şeklinde verildiği zaman userspace anlamına geliyor eğer //k gelseydi kernel olacaktı. Intel-pt dokümanında bunlar sıralanmış:

u       userspace
k       kernel
h       hypervisor
G       guest
H       host
p       precise ip

Gelen veriyi parse edebilmek için perf script'i kullanabiliriz.

$ sudo perf script -i perf.data > a.txt

Gelen çıktı:

.....
.....
ls 461322 [001] 391156.010600:          1  branches:uH:      7fcc113606f0 _dl_sysdep_start+0x0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>                0 [unknown] ([unknown])
ls 461322 [001] 391156.010602:          1  branches:uH:      7fcc11360727 _dl_sysdep_start+0x37 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>                0 [unknown] ([unknown])
ls 461322 [001] 391156.010605:          1  branches:uH:      7fcc1136080a _dl_sysdep_start+0x11a (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>                0 [unknown] ([unknown])
ls 461322 [001] 391156.010608:          1  branches:uH:      7fcc11360a86 _dl_sysdep_start+0x396 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>     7fcc1135e040 __GI___tunables_init+0x0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
.....
.....

Perf script'de alacağımız çıktıları flagler üzerinden belirleyebiliyoruz. --itrace üzerinden verebiliriz. Default hali --itrace=cepwx .

i       synthesize "instructions" events
b       synthesize "branches" events
x       synthesize "transactions" events
w       synthesize "ptwrite" events
p       synthesize "power" events (incl. PSB events)
c       synthesize branches events (calls only)
r       synthesize branches events (returns only)
e       synthesize tracing error events
d       create a debug log
g       synthesize a call chain (use with i or x)
G       synthesize a call chain on existing event records
l       synthesize last branch entries (use with i or x)
L       synthesize last branch entries on existing event records
s       skip initial number of events
q       quicker (less detailed) decoding
Z       prefer to ignore timestamps (so-called "timeless" decoding)

Aynı zamanda perf script'inde gösterilmesini istediğimiz (fields) kolonları da ayarlayabiliyoruz. Bunun için:

perf script -F pid,cpu,time

Buraya verebileceğimiz diğer parametrelerde aşağıda mevcut.

comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr,symoff, srcline, period, iregs, uregs, brstack, brstacksym, flags, bpf-output, brstackinsn, brstackoff, callindent, insn, insnlen, synth, phys_addr, metric, misc, srccode, ipc, data_page_size, code_page_size

Bu parametrelerden flags parametresi ilginç eklenebilir.

Aynı zamanda eventleri gruplayabiliriz. Örneğin intel_pt ile branch_miss eventleri burada birleştiriliyor. Bununla beraber branch miss'ler için intel_pt verisi oluşturuluyor.

sudo perf record -e '{intel_pt//u,branch-misses:u}' ./prog

Çıktı:

....
a.out 480642 399271.008150:          1 branch-misses:u:                            7f21e31dae78 _dl_start+0x88 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152:          1     branches:uH:   tr strt                             0 [unknown] ([unknown]) =>     7f21e31dae78 _dl_start+0x88 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152:          1     branches:uH:   jcc                      7f21e31dae82 _dl_start+0x92 (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>     7f21e31db070 _dl_start+0x280 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
a.out 480642 399271.008152:          1     branches:uH:   jcc                      7f21e31db07c _dl_start+0x28c (/usr/lib/x86_64-linux-gnu/ld-2.31.so) =>     7f21e31db090 _dl_start+0x2a0 (/usr/lib/x86_64-linux-gnu/ld-2.31.so)
....

Kaynaklar

  • https://lwn.net/Articles/648154/
  • https://man7.org/linux/man-pages/man1/perf-intel-pt.1.html
  • https://man7.org/linux/man-pages/man1/perf-script.1.html
  • https://blog.cubieserver.de/publications/Henschel_Intel-PT_2017.pdf

This was the end of the blog post. You can reach me via email umusasadik at gmail com