Skip to content

Commit

Permalink
bpftool: add support for split BTF to gen min_core_btf
Browse files Browse the repository at this point in the history
Enables a user to generate minimized kernel module BTF.

If an eBPF program probes a function within a kernel module or uses types that come from a kernel module, split BTF is required. The split module BTF contains only the BTF types that are unique to the module. It will reference the base/vmlinux BTF types and always starts its type IDs at X+1 where X is the largest type ID in the base BTF.

Minimization allows a user to ship only the types necessary to do relocations for the program(s) in the provided eBPF object file(s). A minimized module BTF will still not contain vmlinux BTF types, so you should always minimize the vmlinux file first, and then minimize the kernel module file.

Example:

bpftool gen min_core_btf vmlinux.btf vmlinux-min.btf prog.bpf.o
bpftool -B vmlinux-min.btf gen min_core_btf module.btf module-min.btf prog.bpf.o

Signed-off-by: Bryce Kahle <[email protected]>
  • Loading branch information
brycekahle committed Jan 16, 2024
1 parent b0e69ac commit b719879
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 6 deletions.
20 changes: 19 additions & 1 deletion docs/bpftool-gen.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ SYNOPSIS

**bpftool** [*OPTIONS*] **gen** *COMMAND*

*OPTIONS* := { |COMMON_OPTIONS| | { **-L** | **--use-loader** } }
*OPTIONS* := { |COMMON_OPTIONS| | { **-L** | **--use-loader** } | { **-B** | **--base-btf** } }

*COMMAND* := { **object** | **skeleton** | **help** }

Expand Down Expand Up @@ -208,6 +208,20 @@ OPTIONS
not use the majority of the libbpf infrastructure, and does not need
libelf.

-B, --base-btf *FILE*
Pass a base BTF object. Base BTF objects are typically used
with BTF objects for kernel modules. To avoid duplicating
all kernel symbols required by modules, BTF objects for
modules are "split", they are built incrementally on top of
the kernel (vmlinux) BTF object. So the base BTF reference
should usually point to the kernel BTF.

When the main BTF object to process (for example, the
module BTF to dump) is passed as a *FILE*, bpftool attempts
to autodetect the path for the base object, and passing
this option is optional. When the main BTF object is passed
through other handles, this option becomes necessary.

EXAMPLES
========
**$ cat example1.bpf.c**
Expand Down Expand Up @@ -444,3 +458,7 @@ ones given to min_core_btf.
obj = bpf_object__open_file("one.bpf.o", &opts);

...

Kernel module BTF may also be minimized by using the -B option:

**$ bpftool -B 5.4.0-example.btf gen min_core_btf 5.4.0-module.btf 5.4.0-module-smaller.btf one.bpf.o**
17 changes: 12 additions & 5 deletions src/gen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,7 @@ static int do_help(int argc, char **argv)
"\n"
" " HELP_SPEC_OPTIONS " |\n"
" {-L|--use-loader} }\n"
" {-B|--base-btf} }\n"
"",
bin_name, "gen");

Expand Down Expand Up @@ -1695,14 +1696,14 @@ btfgen_new_info(const char *targ_btf_path)
if (!info)
return NULL;

info->src_btf = btf__parse(targ_btf_path, NULL);
info->src_btf = btf__parse_split(targ_btf_path, base_btf);
if (!info->src_btf) {
err = -errno;
p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));
goto err_out;
}

info->marked_btf = btf__parse(targ_btf_path, NULL);
info->marked_btf = btf__parse_split(targ_btf_path, base_btf);
if (!info->marked_btf) {
err = -errno;
p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));
Expand Down Expand Up @@ -2141,10 +2142,16 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
{
struct btf *btf_new = NULL;
unsigned int *ids = NULL;
const struct btf *base;
unsigned int i, n = btf__type_cnt(info->marked_btf);
int start_id = 1;
int err = 0;

btf_new = btf__new_empty();
base = btf__base_btf(info->src_btf);
if (base)
start_id = btf__type_cnt(base);

btf_new = btf__new_empty_split((struct btf *)base);
if (!btf_new) {
err = -errno;
goto err_out;
Expand All @@ -2157,7 +2164,7 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
}

/* first pass: add all marked types to btf_new and add their new ids to the ids map */
for (i = 1; i < n; i++) {
for (i = start_id; i < n; i++) {
const struct btf_type *cloned_type, *type;
const char *name;
int new_id;
Expand Down Expand Up @@ -2213,7 +2220,7 @@ static struct btf *btfgen_get_btf(struct btfgen_info *info)
}

/* second pass: fix up type ids */
for (i = 1; i < btf__type_cnt(btf_new); i++) {
for (i = start_id; i < btf__type_cnt(btf_new); i++) {
struct btf_type *btf_type = (struct btf_type *) btf__type_by_id(btf_new, i);

err = btf_type_visit_type_ids(btf_type, btfgen_remap_id, ids);
Expand Down

0 comments on commit b719879

Please sign in to comment.