/* Set temporarily in relocation id_map if distilled base struct/union is *embeddedinasplitBTFstruct/union;insuchacase,sizeinformationmust *matchbetweendistilledbaseBTFandbaseBTFrepresentationoftype.
*/ #define BTF_IS_EMBEDDED ((__u32)-1)
/* <name, size, id> triple used in sorting/searching distilled base BTF. */ struct btf_name_info { constchar *name; /* set when search requires a size match */ bool needs_size: 1; unsignedint size: 31;
__u32 id;
};
/* Binary search with a small twist; find leftmost element that matches *sothatwecantheniteratethroughallexactmatches.Soforexample *searching{"a","bb","bb","c"}wewouldalwaysmatchonthe *leftmost"bb".
*/ staticstruct btf_name_info *search_btf_name_size(struct btf_name_info *key, struct btf_name_info *vals, int nelems)
{ struct btf_name_info *ret = NULL; int high = nelems - 1; int low = 0;
while (low <= high) { int mid = (low + high)/2; struct btf_name_info *val = &vals[mid]; int diff = cmp_btf_name_size(key, val);
if (diff == 0)
ret = val; /* even if found, keep searching for leftmost match */ if (diff <= 0)
high = mid - 1; else
low = mid + 1;
} return ret;
}
/* If a member of a split BTF struct/union refers to a base BTF *struct/union,markthatstruct/unionidtemporarilyintheid_map *withBTF_IS_EMBEDDED.Memberscanbeconst/restrict/volatile/typedef *referencetypes,butifapointerisencountered,thetypeisnolonger *consideredembedded.
*/ staticint btf_mark_embedded_composite_type_ids(struct btf_relocate *r, __u32 i)
{ struct btf_type *t = btf_type_by_id(r->btf, i); struct btf_field_iter it;
__u32 *id; int err;
if (!btf_is_composite(t)) return0;
err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); if (err) return err;
while ((id = btf_field_iter_next(&it))) {
__u32 next_id = *id;
while (next_id) {
t = btf_type_by_id(r->btf, next_id); switch (btf_kind(t)) { case BTF_KIND_CONST: case BTF_KIND_RESTRICT: case BTF_KIND_VOLATILE: case BTF_KIND_TYPEDEF: case BTF_KIND_TYPE_TAG:
next_id = t->type; break; case BTF_KIND_ARRAY: { struct btf_array *a = btf_array(t);
next_id = a->type; break;
} case BTF_KIND_STRUCT: case BTF_KIND_UNION: if (next_id < r->nr_dist_base_types)
r->id_map[next_id] = BTF_IS_EMBEDDED;
next_id = 0; break; default:
next_id = 0; break;
}
}
}
return0;
}
/* Build a map from distilled base BTF ids to base BTF ids. To do so, iterate *throughbaseBTFlookingupdistilledtype(usingbinarysearch)equivalents.
*/ staticint btf_relocate_map_distilled_base(struct btf_relocate *r)
{ struct btf_name_info *info, *info_end; struct btf_type *base_t, *dist_t;
__u8 *base_name_cnt = NULL; int err = 0;
__u32 id;
/* generate a sort index array of name/type ids sorted by name for *distilledbaseBTFtospeedname-basedlookups.
*/
info = calloc(r->nr_dist_base_types, sizeof(*info)); if (!info) {
err = -ENOMEM; goto done;
}
info_end = info + r->nr_dist_base_types; for (id = 0; id < r->nr_dist_base_types; id++) {
dist_t = btf_type_by_id(r->dist_base_btf, id);
info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
info[id].id = id;
info[id].size = dist_t->size;
info[id].needs_size = true;
}
qsort(info, r->nr_dist_base_types, sizeof(*info), cmp_btf_name_size);
/* Mark distilled base struct/union members of split BTF structs/unions *inid_mapwithBTF_IS_EMBEDDED;thissignalsthatthesetypes *needtomatchbothnameandsize,otherwiseembeddingthebase *struct/unioninthesplittypeisinvalid.
*/ for (id = r->nr_dist_base_types; id < r->nr_dist_base_types + r->nr_split_types; id++) {
err = btf_mark_embedded_composite_type_ids(r, id); if (err) goto done;
}
/* Collect name counts for composite types in base BTF. If multiple *instancesofastruct/unionofthesamenameexist,weneedtouse *sizetodeterminewhichtomaptosincenamealoneisambiguous.
*/
base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt)); if (!base_name_cnt) {
err = -ENOMEM; goto done;
} for (id = 1; id < r->nr_base_types; id++) {
base_t = btf_type_by_id(r->base_btf, id); if (!btf_is_composite(base_t) || !base_t->name_off) continue; if (base_name_cnt[base_t->name_off] < 255)
base_name_cnt[base_t->name_off]++;
}
/* Now search base BTF for matching distilled base BTF types. */ for (id = 1; id < r->nr_base_types; id++) { struct btf_name_info *dist_info, base_info = {}; int dist_kind, base_kind;
base_t = btf_type_by_id(r->base_btf, id); /* distilled base consists of named types only. */ if (!base_t->name_off) continue;
base_kind = btf_kind(base_t);
base_info.id = id;
base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); switch (base_kind) { case BTF_KIND_INT: case BTF_KIND_FLOAT: case BTF_KIND_ENUM: case BTF_KIND_ENUM64: /* These types should match both name and size */
base_info.needs_size = true;
base_info.size = base_t->size; break; case BTF_KIND_FWD: /* No size considerations for fwds. */ break; case BTF_KIND_STRUCT: case BTF_KIND_UNION: /* Size only needs to be used for struct/union if there *aremultipletypesinbaseBTFwiththesamename. *Iftherearemultiple_distilled_typeswiththesame *name(averyunlikelyscenario),thatdoesn'tmatter *unlesscorresponding_base_typestomatchthemare *missing.
*/
base_info.needs_size = base_name_cnt[base_t->name_off] > 1;
base_info.size = base_t->size; break; default: continue;
} /* iterate over all matching distilled base types */ for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types);
dist_info != NULL && dist_info < info_end &&
cmp_btf_name_size(&base_info, dist_info) == 0;
dist_info++) { if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) {
pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n",
id, dist_info->id);
err = -EINVAL; goto done;
}
dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id);
dist_kind = btf_kind(dist_t);
/* Validate that the found distilled type is compatible. *Donoterroroutonmismatchasanothermatchmay *occurforanidentically-namedtype.
*/ switch (dist_kind) { case BTF_KIND_FWD: switch (base_kind) { case BTF_KIND_FWD: if (btf_kflag(dist_t) != btf_kflag(base_t)) continue; break; case BTF_KIND_STRUCT: if (btf_kflag(base_t)) continue; break; case BTF_KIND_UNION: if (!btf_kflag(base_t)) continue; break; default: continue;
} break; 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 *distilledbaseBTF.
*/ if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64) continue; break; case BTF_KIND_STRUCT: case BTF_KIND_UNION: /* size verification is required for embedded *struct/unions.
*/ if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED &&
base_t->size != dist_t->size) continue; break; default: continue;
} if (r->id_map[dist_info->id] &&
r->id_map[dist_info->id] != BTF_IS_EMBEDDED) { /* we already have a match; this tells us that *multiplebasetypesofthesamename *havethesamesize,sinceforcaseswhere *multipletypeshavethesamenamewematch *onnameandsize.Inthiscase,wehave *nowayofdeterminingwhichtorelocate *toinbaseBTF,soerrorout.
*/
pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n",
base_info.name, dist_info->id,
base_t->size, id, r->id_map[dist_info->id]);
err = -EINVAL; goto done;
} /* map id and name */
r->id_map[dist_info->id] = id;
r->str_map[dist_t->name_off] = base_t->name_off;
}
} /* ensure all distilled BTF ids now have a mapping... */ for (id = 1; id < r->nr_dist_base_types; id++) { constchar *name;
if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED) continue;
dist_t = btf_type_by_id(r->dist_base_btf, id);
name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n",
name, id);
err = -EINVAL; break;
}
done:
free(base_name_cnt);
free(info); return err;
}
/* distilled base should only have named int/float/enum/fwd/struct/union types. */ staticint btf_relocate_validate_distilled_base(struct btf_relocate *r)
{ unsignedint i;
for (i = 1; i < r->nr_dist_base_types; i++) { struct btf_type *t = btf_type_by_id(r->dist_base_btf, i); int kind = btf_kind(t);
switch (kind) { case BTF_KIND_INT: case BTF_KIND_FLOAT: case BTF_KIND_ENUM: case BTF_KIND_STRUCT: case BTF_KIND_UNION: case BTF_KIND_FWD: if (t->name_off) break;
pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n",
i, kind); return -EINVAL; default:
pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n",
i, kind); return -EINVAL;
}
} return0;
}
err = btf_relocate_validate_distilled_base(&r); if (err) goto err_out;
/* Split BTF ids need to be adjusted as base and distilled base *havedifferentnumbersoftypes,changingthestartidofsplit *BTF.
*/ for (id = r.nr_dist_base_types; id < nr_types; id++)
r.id_map[id] = id + r.nr_base_types - r.nr_dist_base_types;
/* Build a map from distilled base ids to actual base BTF ids; it is used *toupdatesplitBTFidreferences.Alsobuildastr_mapmappingfrom *distilledbaseBTFnamestobaseBTFnames.
*/
err = btf_relocate_map_distilled_base(&r); if (err) goto err_out;
/* Next, rewrite type ids in split BTF, replacing split ids with updated *idsbasedonnumberoftypesinbaseBTF,andbaseidswith *relocatedidsfrombase_btf.
*/ for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) {
err = btf_relocate_rewrite_type_id(&r, id); if (err) goto err_out;
} /* String offsets now need to be updated using the str_map. */ for (i = 0; i < r.nr_split_types; i++) {
err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types); if (err) goto err_out;
} /* Finally reset base BTF to be base_btf */
btf_set_base_btf(btf, base_btf);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.