[https://itiskj.hatenablog.com/entry/2020/12/18/054957](https://itiskj.hatenablog.com/entry/2020/12/18/054957) BCCの課題は,clang+LLVM,Linuxカーネルヘッダをインストールするか,配布バイナリに組み込むことが必要であり,配布時のバイナリサイズや,CPU/メモリリソースを食う.CPUリソースの消費については,プログラムの起動時だけですむかもしれない. > ... requiring customers to install the LLVM, Clang, and kernel header dependencies – which can consume over 100 Mbytes of storage --- > [http://brendangregg.com/blog/2020-11-04/bpf-co-re-btf-libbpf.html](http://brendangregg.com/blog/2020-11-04/bpf-co-re-btf-libbpf.html) BPFのバイトコードをELFで保存して、他のカーネルに送ればいいというものではありません。多くのBPFプログラムは、あるカーネルのバージョンから別のカーネルに変更される可能性のあるカーネル構造体を歩きます。あなたのBPFバイトコードは異なるカーネルでまだ実行できるかもしれませんが、間違った構造体のオフセットを読み、ゴミのような出力をするかもしれません! opensnoop(8) は安定したトレースポイントやその引数を計測するのでカーネル構造体を歩きませんが、他の多くのツールではそうなっています。 これは再配置の問題であり、BTF と CO-RE の両方が BPF バイナリに対してこれを解決します。BTFは型情報を提供し、構造体のオフセットやその他の詳細を必要に応じて問い合わせることができ、CO-REはBPFプログラムのどの部分をどのように書き換える必要があるかを記録します。CO-REの開発者であるAndrii Nakryiko氏が、より深く説明するために長い記事を書いています。BPFのポータビリティとCO-RE、BTFの型情報。 --- [[BPF portability and CO-RE]] 1. CO-RE (Compile-Once Run Anywhare) 2. BCCの欠点は、コンパイルと実行を同一ホスト上でやるので、コンパイルのためのCPUリソースをくうし、メモリ使用量とか、ディスクスペースも消費する。llvm/clangとか、kernel-develパッケージ。コンパイルエラーも実行しないと検出できない。 3. compileは一回にしよう。カーネルバージョンの差異をどう吸収するか。構造体のメンバー変数のoffset値とかってbytecodeに埋め込まれている。メンバー変数のアクセスをLLVMがコンパイル時にELF bytecodeのセクションのrelocationとして記録。 4. BTF(BPF Type Format)による軽量な型フォーマットがあって、構造体のoffsetを書き換え。DWARFの100倍軽量 5. task_struct->pidフィールドにアクセスしようとした場合、Clangはそれが構造体task_struct内に存在する "pid_t "型の "pid "という名前のfieldであることを記録します。これは、ターゲットカーネルが task_struct レイアウトで "pid" フィールドが task_struct 構造体内の異なるオフセットに移動した場合(例えば、"pid" フィールドの前に余分なフィールドが追加されたため)や、入れ子になった匿名構造体やunionに移動した場合でも(これは C コードでは完全に透過的なので、誰もそのような詳細に注意を払わない)、その名前と型の情報だけでそれを見つけることができるようにするためです。これをfield offset relocationと呼びます。 6. Libbpfは、BPFプログラムの記録されたBTFタイプと再配置情報を見て、実行中のカーネルから提供されるBTF情報と照合します。"カスタム・テーラーメイド "されたBPFプログラム 7. /sys/kernel/btf/vmlinux がはえてる必要があって、Ubuntu 20.04まではカーネルのビルドオプション変更して再ビルドが必要。Ubuntu 20.10からはデフォルトで使える。 8. フィールドアクセスには、BPF_CORE_READ マクロで。