CO-RE (Compile Once, Run Everywhere) is a mechanism used with eBPF to ensure portability of the programs, mainly those intended for tracing. It addresses the issue that arises when a given structure is modified between two kernel versions. Tracing programs may attempt to access a field from a given structure by reading at a specific offset in that structure. But if modifications occur in a later version and introduce a change for the length of the structure, or for the order of its member fields, then the program will not be compatible.
CO-RE solves this by relying on BTF objects (BPF Type Format). A BTF object contains debug information about a program. This is in fact a simplified version of the DWARF format, used for example by GDB. BTF objects are loaded into the kernel, and they often hold information on eBPF bytecode, for example to dump the C instructions from which the program was compiled. But BTF can also describe other objects like the kernel itself. In that case, BTF can provide, just before an eBPF program is loaded, the relevant information for accessing the kernel structures. The required adjustments are performed as “ELF relocation” steps, just before the bytecode is sent to the kernel.
The easiest way to use CO-RE is through libbpf. Note that because it needs the
BTF information for the kernel, CO-RE is only available if the
CONFIG_DEBUG_INFO_BTF option has been set when compiling the kernel. Recent
tooling (LLVM, libbpf) is also necessary.
If you want more information on this topic, Andrii Nakryiko explains everything
there is to know about CO-RE
on his blog.
The specification for BTF can be found in
the kernel documentation,
but you might also want to have a look at the
bpftool-btf man page if you are
curious to inspect BTF objects on your system.