Re: [PATCH v2 bpf-next 02/18] libbpf: Add support for BTF kinds LOC[_PARAM|_PROTO|SEC]
From: Eduard Zingerman <eddyz87@gmail.com>
Date: 2026-09-09 22:27:02
Also in:
bpf
On Tue, 2026-09-01 at 17:57 +0100, Alan Maguire wrote:
Add support for new kinds to libbpf. BTF_KIND_LOC_PARAM and BTF_KIND_LOC_PROTO are dedup-able so add support for their deduplication, whereas since BTF_KIND_LOCSEC contains a unique offset it is not. LOC_PARAM is considered a primary type since it contains no external references; LOC_PROTO is a reference type consisting of LOC_PARAM references so they are handled in the primary and reference dedup phases respectively. For BTF field iteration, BTF_KIND_LOCSEC needs 2 m_offs[] values for the associated KIND_FUNC and KIND_LOC_PROTO type ids in each LOCSEC entry. Add APIs to add location param, location prototypes and location sections and btf_is_* tests, data accessors for each. For BTF distillation we add location info to split BTF. Signed-off-by: Alan Maguire <redacted> ---
Acked-by: Eduard Zingerman <eddyz87@gmail.com> (Please see a few nits below) ...
quoted hunk ↗ jump to hunk
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
...
quoted hunk ↗ jump to hunk
@@ -4395,6 +4653,45 @@ static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
...
+static long btf_hash_loc_param(struct btf_type *t)
+{
+ long h = btf_hash_common(t);
+ __u32 *v = (__u32 *)btf_loc_param(t);
+ int i, vlen = btf_vlen(t);
+
+ for (i = 0; i <= vlen; i++, v++)
+ h = hash_combine(h, *v);
+ return h;
+}should v->flags be hashed as well?
+static bool btf_equal_loc_param(struct btf_type *t1, struct btf_type *t2)
+{
+ struct btf_loc_param *p1 = btf_loc_param(t1);
+ struct btf_loc_param *p2 = btf_loc_param(t2);
+ __u32 *v1 = (__u32 *)(p1 + 1);
+ __u32 *v2 = (__u32 *)(p2 + 1);
+ int i, vlen = btf_vlen(t1);
+
llm is right, the p{1,2}->flags comparison is missing.
quoted hunk ↗ jump to hunk
+ if (!btf_equal_common(t1, t2)) + return false; + for (i = 0; i < vlen; i++, v1++, v2++) { + if (*v1 != *v2) + return false; + } + return true; +} + /* * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs, * as referenced type IDs equivalence is established separately during type@@ -4622,6 +4919,12 @@ static int btf_dedup_prep(struct btf_dedup *d)case BTF_KIND_FUNC_PROTO: h = btf_hash_fnproto(t); break; + case BTF_KIND_LOC_PARAM: + h = btf_hash_loc_param(t); + break; + case BTF_KIND_LOC_PROTO: + h = btf_hash_loc_proto(t); + break;
Maybe add LOCSEC as an empty case, same as for VAR and DATASEC above? Otherwise if someone ever tries to dedup a non-module BTF with a LOCSEC the operation would return -EINVAL.
default:
pr_debug("unknown kind %d for type [%d]\n", btf_kind(t), type_id);
return -EINVAL;...
quoted hunk ↗ jump to hunk
@@ -5489,6 +5813,41 @@ static int btf_dedup_ref_type(struct btf_dedup *d, __u32 type_id)break; } + case BTF_KIND_LOC_PROTO: { + __u32 *p1, *p2; + __u32 i, vlen; + + p1 = btf_loc_proto_params(t); + vlen = btf_vlen(t); + + for (i = 0; i < vlen; i++, p1++) { + ref_type_id = btf_dedup_ref_type(d, *p1); + if (ref_type_id < 0) + return ref_type_id; + *p1 = ref_type_id; + } + + h = btf_hash_loc_proto(t); + for_each_dedup_cand(d, hash_entry, h) { + cand_id = hash_entry->value; + cand = btf_type_by_id(d->btf, cand_id); + if (!btf_equal_common(t, cand)) + continue; + vlen = btf_vlen(cand);
Nit: btf_equal_common() checks vlen for equivalence,
so it appears that the above line is redundant.
+ p1 = btf_loc_proto_params(t);
+ p2 = btf_loc_proto_params(cand);
+ if (vlen == 0) {
+ new_id = cand_id;
+ break;
+ }
Nit: It appears that special case for `vlen == 0` is not necessary,
wouldn't memcmp(..., 0) be 0?
+ if (memcmp(p1, p2, vlen * sizeof(__u32)) == 0) {
+ new_id = cand_id;
+ break;
+ }
+ }
+ break;
+ }
+
default:
return -EINVAL;
}...
quoted hunk ↗ jump to hunk
--- a/tools/lib/bpf/btf_iter.c +++ b/tools/lib/bpf/btf_iter.c
...
quoted hunk ↗ jump to hunk
@@ -94,6 +109,8 @@ int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t,case BTF_KIND_DECL_TAG: case BTF_KIND_TYPE_TAG: case BTF_KIND_DATASEC: + case BTF_KIND_LOC_PARAM: + case BTF_KIND_LOC_PROTO: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)} };@@ -127,6 +144,11 @@ int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t,1, {offsetof(struct btf_param, name_off)} }; break; + case BTF_KIND_LOCSEC: + it->desc = (struct btf_field_desc) { + 1, {offsetof(struct btf_type, name_off)} + }; + break;
Nit: can this be grouped wit the _PARAM and _PROTO cases? ...