On Tue, May 28, 2024 at 5:26 AM Alan Maguire <alan.maguire@xxxxxxxxxx> wrote: > > Map distilled base BTF type ids referenced in split BTF and their > references to the base BTF passed in, and if the mapping succeeds, > reparent the split BTF to the base BTF. > > Relocation is done by first verifying that distilled base BTF > only consists of named INT, FLOAT, ENUM, FWD, STRUCT and > UNION kinds; then we sort these to speed lookups. Once sorted, > the base BTF is iterated, and for each relevant kind we check > for an equivalent in distilled base BTF. When found, the > mapping from distilled -> base BTF id and string offset is recorded. > In establishing mappings, we need to ensure we check STRUCT/UNION > size when the STRUCT/UNION is embedded in a split BTF STRUCT/UNION, > and when duplicate names exist for the same STRUCT/UNION. Otherwise > size is ignored in matching STRUCT/UNIONs. > > Once all mappings are established, we can update type ids > and string offsets in split BTF and reparent it to the new base. > > Signed-off-by: Alan Maguire <alan.maguire@xxxxxxxxxx> > --- > tools/lib/bpf/Build | 2 +- > tools/lib/bpf/btf.c | 17 ++ > tools/lib/bpf/btf.h | 14 ++ > tools/lib/bpf/btf_relocate.c | 430 ++++++++++++++++++++++++++++++++ > tools/lib/bpf/libbpf.map | 1 + > tools/lib/bpf/libbpf_internal.h | 3 + > 6 files changed, 466 insertions(+), 1 deletion(-) > create mode 100644 tools/lib/bpf/btf_relocate.c > [...] > +/* Set temporarily in relocation id_map if distilled base struct/union is > + * embedded in a split BTF struct/union; in such a case, size information must > + * match between distilled base BTF and base BTF representation of type. > + */ > +#define BTF_IS_EMBEDDED ((__u32)-1) > + > +/* <name, size, id> triple used in sorting/searching distilled base BTF. */ > +struct btf_name_info { > + const char *name; > + int size:31; > + /* set when search requires a size match */ > + bool needs_size; this was meant to be a 1-bit field, right? `: 1` is missing? > + __u32 id; > +}; > + [...] > + case BTF_KIND_INT: > + if (dist_kind != base_kind || > + btf_int_encoding(base_t) != btf_int_encoding(dist_t)) > + continue; > + break; > + case BTF_KIND_FLOAT: > + if (dist_kind != base_kind) > + continue; > + break; > + case BTF_KIND_ENUM: > + /* ENUM and ENUM64 are encoded as sized ENUM in > + * distilled base BTF. > + */ > + if (dist_kind != base_kind && base_kind != BTF_KIND_ENUM64) > + continue; probably unnecessarily strict, I'd check something like if (!btf_is_enum_any(dist_t) || !btf_is_enum_any(base_t) || dist_t->size != base_t->size) continue; it's minor, unlikely to matter in practice > + break; > + case BTF_KIND_STRUCT: > + case BTF_KIND_UNION: > + /* size verification is required for embedded > + * struct/unions. > + */ > + if (r->id_map[dist_name_info->id] == BTF_IS_EMBEDDED && > + base_t->size != dist_t->size) > + continue; > + break; > + default: > + continue; > + } > + /* map id and name */ > + r->id_map[dist_name_info->id] = id; > + r->str_map[dist_t->name_off] = base_t->name_off; > + } [...]