BPFの開発をするときに欠かせない、「bpftrace」というトレーシングツールを試してみました。
参考)
https://github.com/iovisor/bpftrace/blob/master/INSTALL.md#ubuntu
「BPFによるトレーシングが簡単にできる「bpftrace」の使い方」
https://atmarkit.itmedia.co.jp/ait/articles/2006/15/news016.html
環境) Ubuntu 20.04
インストール)
sudo apt install build-essential
sudo apt-get update
sudo apt-get install -y \
bison \
cmake \
flex \
g++ \
git \
libelf-dev \
zlib1g-dev \
libfl-dev \
systemtap-sdt-dev \
binutils-dev \
libcereal-dev \
llvm-12-dev \
llvm-12-runtime \
libclang-12-dev \
clang-12 \
libpcap-dev \
libgtest-dev \
libgmock-dev \
asciidoctorgit clone –recurse-submodules https://github.com/iovisor/bpftrace
cd bpftrace
mkdir build
cd build
../build-libs.sh
cmake ..
make
sudo make install
下記にインストールされる。
/usr/local/bin/bpftrace
実行例(rootユーザ)
root@n07:~# bpftrace -e ‘tracepoint:syscalls:sys_enter_openat{printf(“%s\n”,str(args->filename));}’
Attaching 1 probe…
/proc/interrupts
/proc/stat
/proc/irq/20/smp_affinity
/proc/irq/19/smp_affinity
/proc/irq/19/smp_affinity
/proc/irq/0/smp_affinity
/proc/irq/1/smp_affinity
/proc/irq/8/smp_affinity
/proc/irq/12/smp_affinity
/proc/irq/14/smp_affinity
/proc/irq/15/smp_affinity
/etc/ld.so.cache
/lib/x86_64-linux-gnu/libc.so.6
/usr/lib/locale/locale-archive
/var/log/syslog
上記は、ファイルオープンをトレースしています。(別コンソールで、syslogを開く)
またユーザ関数もトレースしてみました。
1 2 3 4 5 6 7 8 |
#include <stdio.h> int myadd(int a, int b){ return a + b; } int main(){ printf("%d\n",myadd(1,2)); } |
トレースする関数の確認
root@n07:~# cc -o bpftest bpftest.c
root@n07:~# readelf -s /root/bpftest | grep FUNC
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
6: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (2)
29: 0000000000001090 0 FUNC LOCAL DEFAULT 16 deregister_tm_clones
30: 00000000000010c0 0 FUNC LOCAL DEFAULT 16 register_tm_clones
31: 0000000000001100 0 FUNC LOCAL DEFAULT 16 __do_global_dtors_aux
34: 0000000000001140 0 FUNC LOCAL DEFAULT 16 frame_dummy
45: 0000000000001000 0 FUNC LOCAL DEFAULT 12 _init
46: 0000000000001210 5 FUNC GLOBAL DEFAULT 16 __libc_csu_fini
50: 0000000000001218 0 FUNC GLOBAL HIDDEN 17 _fini
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_
57: 0000000000001149 24 FUNC GLOBAL DEFAULT 16 myadd
58: 00000000000011a0 101 FUNC GLOBAL DEFAULT 16 __libc_csu_init
60: 0000000000001060 47 FUNC GLOBAL DEFAULT 16 _start
62: 0000000000001161 49 FUNC GLOBAL DEFAULT 16 main
65: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.2
トレースの実行後、別コンソールで”/root/bpftest”の実行
root@n07:~# bpftrace -e ‘uprobe:/root/bpftest:myadd{printf(“%d, %d\n”, arg0, arg1);}’
Attaching 1 probe…
1, 2
root@n07:~# /root/bpftest
3
また、数々のツールが用意されています。
https://github.com/iovisor/bpftrace/tree/master/tools
下記にインストールされているのでrootユーザでパスを通しておきます。
/usr/local/share/bpftrace/tools
root@n07:~# execsnoop.bt
Attaching 3 probes…
TIME(ms) PID ARGS
8496 17036 ls –color=auto
34839 17041 cat /var/log/syslog
上記は、プロセスのトレースで、別コンソールで”ls”と”cat /var/log/syslog”を実行しました。
*.btは専用の言語でかかれており、そのまま実行できます。このあたり構文解析に必要なbisonやflexがインストールされた理由でしょう。
execsnoop.bt
1 2 3 4 5 6 7 8 9 10 |
#!/usr/bin/env bpftrace BEGIN { printf("%-10s %-5s %s\n", "TIME(ms)", "PID", "ARGS"); } tracepoint:syscalls:sys_enter_exec* { printf("%-10u %-5d ", elapsed / 1e6, pid); join(args->argv); } |
かなり整備されているツールという印象を受けました。
次は内容について深堀していきたいです。