aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/btf.c
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@kernel.org>2019-12-15 16:41:13 -0800
committerAlexei Starovoitov <ast@kernel.org>2019-12-15 16:44:22 -0800
commit01c6f7aaacf982fd80d5e855f0c6187d8155ffed (patch)
tree7f0220e2dd38b8f7c99c9b4780c97cd6513be982 /tools/lib/bpf/btf.c
parentMerge branch 'bpf-obj-skel' (diff)
parentselftests/bpf: Add tests for libbpf-provided externs (diff)
downloadlinux-dev-01c6f7aaacf982fd80d5e855f0c6187d8155ffed.tar.xz
linux-dev-01c6f7aaacf982fd80d5e855f0c6187d8155ffed.zip
Merge branch 'extern-var-support'
Andrii Nakryiko says: ==================== It's often important for BPF program to know kernel version or some specific config values (e.g., CONFIG_HZ to convert jiffies to seconds) and change or adjust program logic based on their values. As of today, any such need has to be resolved by recompiling BPF program for specific kernel and kernel configuration. In practice this is usually achieved by using BCC and its embedded LLVM/Clang. With such set up #ifdef CONFIG_XXX and similar compile-time constructs allow to deal with kernel varieties. With CO-RE (Compile Once – Run Everywhere) approach, this is not an option, unfortunately. All such logic variations have to be done as a normal C language constructs (i.e., if/else, variables, etc), not a preprocessor directives. This patch series add support for such advanced scenarios through C extern variables. These extern variables will be recognized by libbpf and supplied through extra .extern internal map, similarly to global data. This .extern map is read-only, which allows BPF verifier to track its content precisely as constants. That gives an opportunity to have pre-compiled BPF program, which can potentially use BPF functionality (e.g., BPF helpers) or kernel features (types, fields, etc), that are available only on a subset of targeted kernels, while effectively eleminating (through verifier's dead code detection) such unsupported functionality for other kernels (typically, older versions). Patch #3 explicitly tests a scenario of using unsupported BPF helper, to validate the approach. This patch set heavily relies on BTF type information emitted by compiler for each extern variable declaration. Based on specific types, libbpf does strict checks of config data values correctness. See patch #1 for details. Outline of the patch set: - patch #1 does a small clean up of internal map names contants; - patch #2 adds all of the libbpf internal machinery for externs support, including setting up BTF information for .extern data section; - patch #3 adds support for .extern into BPF skeleton; - patch #4 adds externs selftests, as well as enhances test_skeleton.c test to validate mmap()-ed .extern datasection functionality. v3->v4: - clean up copyrights and rebase onto latest skeleton patches (Alexei); v2->v3: - truncate too long strings (Alexei); - clean ups, adding comments (Alexei); v1->v2: - use BTF type information for externs (Alexei); - add strings support; - add BPF skeleton support for .extern. ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to '')
-rw-r--r--tools/lib/bpf/btf.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 84fe82f27bef..520021939d81 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -578,6 +578,12 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
return -ENOENT;
}
+ /* .extern datasec size and var offsets were set correctly during
+ * extern collection step, so just skip straight to sorting variables
+ */
+ if (t->size)
+ goto sort_vars;
+
ret = bpf_object__section_size(obj, name, &size);
if (ret || !size || (t->size && t->size != size)) {
pr_debug("Invalid size for section %s: %u bytes\n", name, size);
@@ -614,7 +620,8 @@ static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
vsi->offset = off;
}
- qsort(t + 1, vars, sizeof(*vsi), compare_vsi_off);
+sort_vars:
+ qsort(btf_var_secinfos(t), vars, sizeof(*vsi), compare_vsi_off);
return 0;
}