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 <[email protected]>
> ---

Acked-by: Eduard Zingerman <[email protected]>

(Please see a few nits below)

...

> diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c

...

> @@ -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.

> +     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;

...

> @@ -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;
>       }

...

> --- a/tools/lib/bpf/btf_iter.c
> +++ b/tools/lib/bpf/btf_iter.c

...

> @@ -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?

...


Reply via email to