Skip to content

Commit ea26899

Browse files
Donglin PengKernel Patches Daemon
authored andcommitted
libbpf: Add BTF permutation support for type reordering
Introduce btf__permute() API to allow in-place rearrangement of BTF types. This function reorganizes BTF type order according to a provided array of type IDs, updating all type references to maintain consistency. Cc: Eduard Zingerman <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Alan Maguire <[email protected]> Cc: Song Liu <[email protected]> Cc: Xiaoqin Zhang <[email protected]> Signed-off-by: Donglin Peng <[email protected]>
1 parent 67d3dd3 commit ea26899

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed

tools/lib/bpf/btf.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5829,3 +5829,189 @@ int btf__relocate(struct btf *btf, const struct btf *base_btf)
58295829
btf->owns_base = false;
58305830
return libbpf_err(err);
58315831
}
5832+
5833+
struct btf_permute {
5834+
struct btf *btf;
5835+
__u32 *id_map;
5836+
__u32 offs;
5837+
};
5838+
5839+
/* Callback function to remap individual type ID references */
5840+
static int btf_permute_remap_type_id(__u32 *type_id, void *ctx)
5841+
{
5842+
struct btf_permute *p = ctx;
5843+
__u32 new_type_id = *type_id;
5844+
5845+
/* skip references that point into the base BTF */
5846+
if (new_type_id < p->btf->start_id)
5847+
return 0;
5848+
5849+
/* invalid reference id */
5850+
if (new_type_id >= btf__type_cnt(p->btf))
5851+
return -EINVAL;
5852+
5853+
new_type_id = p->id_map[new_type_id - p->offs];
5854+
/* reference a dropped type is not allowed */
5855+
if (new_type_id == 0)
5856+
return -EINVAL;
5857+
5858+
*type_id = new_type_id;
5859+
return 0;
5860+
}
5861+
5862+
int btf__permute(struct btf *btf, __u32 *id_map, __u32 id_map_cnt,
5863+
const struct btf_permute_opts *opts)
5864+
{
5865+
struct btf_permute p;
5866+
struct btf_ext *btf_ext;
5867+
void *next_type, *end_type;
5868+
void *nt, *new_types = NULL;
5869+
int err = 0, n, i, new_type_len;
5870+
__u32 *order_map = NULL;
5871+
__u32 offs, id, new_nr_types = 0;
5872+
5873+
if (btf__base_btf(btf)) {
5874+
/*
5875+
* For split BTF, the number of types added on the
5876+
* top of base BTF
5877+
*/
5878+
n = btf->nr_types;
5879+
offs = btf->start_id;
5880+
} else if (id_map[0] != 0) {
5881+
/* id_map[0] must be 0 for base BTF */
5882+
err = -EINVAL;
5883+
goto done;
5884+
} else {
5885+
/* include VOID type 0 for base BTF */
5886+
n = btf__type_cnt(btf);
5887+
offs = 0;
5888+
}
5889+
5890+
if (!OPTS_VALID(opts, btf_permute_opts) || (id_map_cnt != n))
5891+
return libbpf_err(-EINVAL);
5892+
5893+
/* used to record the storage sequence of types */
5894+
order_map = calloc(n, sizeof(*id_map));
5895+
if (!order_map) {
5896+
err = -ENOMEM;
5897+
goto done;
5898+
}
5899+
5900+
new_types = calloc(btf->hdr->type_len, 1);
5901+
if (!new_types) {
5902+
err = -ENOMEM;
5903+
goto done;
5904+
}
5905+
5906+
if (btf_ensure_modifiable(btf)) {
5907+
err = -ENOMEM;
5908+
goto done;
5909+
}
5910+
5911+
for (i = 0; i < id_map_cnt; i++) {
5912+
id = id_map[i];
5913+
/*
5914+
* 0: Drop the specified type (exclude base BTF type 0).
5915+
* For base BTF, type 0 is always preserved.
5916+
*/
5917+
if (id == 0)
5918+
continue;
5919+
/* Invalid id */
5920+
if (id < btf->start_id || id >= btf__type_cnt(btf)) {
5921+
err = -EINVAL;
5922+
goto done;
5923+
}
5924+
id -= offs;
5925+
/* Multiple types cannot be mapped to the same ID */
5926+
if (order_map[id]) {
5927+
err = -EINVAL;
5928+
goto done;
5929+
}
5930+
order_map[id] = i + offs;
5931+
new_nr_types = max(id + 1, new_nr_types);
5932+
}
5933+
5934+
/* Check for missing IDs */
5935+
for (i = offs ? 0 : 1; i < new_nr_types; i++) {
5936+
if (order_map[i] == 0) {
5937+
err = -EINVAL;
5938+
goto done;
5939+
}
5940+
}
5941+
5942+
p.btf = btf;
5943+
p.id_map = id_map;
5944+
p.offs = offs;
5945+
nt = new_types;
5946+
for (i = offs ? 0 : 1; i < new_nr_types; i++) {
5947+
struct btf_field_iter it;
5948+
const struct btf_type *t;
5949+
__u32 *type_id;
5950+
int type_size;
5951+
5952+
id = order_map[i];
5953+
/* must be a valid type ID */
5954+
t = btf__type_by_id(btf, id);
5955+
if (!t) {
5956+
err = -EINVAL;
5957+
goto done;
5958+
}
5959+
type_size = btf_type_size(t);
5960+
memcpy(nt, t, type_size);
5961+
5962+
/* Fix up referenced IDs for BTF */
5963+
err = btf_field_iter_init(&it, nt, BTF_FIELD_ITER_IDS);
5964+
if (err)
5965+
goto done;
5966+
while ((type_id = btf_field_iter_next(&it))) {
5967+
err = btf_permute_remap_type_id(type_id, &p);
5968+
if (err)
5969+
goto done;
5970+
}
5971+
5972+
nt += type_size;
5973+
}
5974+
5975+
/* Fix up referenced IDs for btf_ext */
5976+
btf_ext = OPTS_GET(opts, btf_ext, NULL);
5977+
if (btf_ext) {
5978+
err = btf_ext_visit_type_ids(btf_ext, btf_permute_remap_type_id, &p);
5979+
if (err)
5980+
goto done;
5981+
}
5982+
5983+
new_type_len = nt - new_types;
5984+
next_type = new_types;
5985+
end_type = next_type + new_type_len;
5986+
i = 0;
5987+
while (next_type + sizeof(struct btf_type) <= end_type) {
5988+
btf->type_offs[i++] = next_type - new_types;
5989+
next_type += btf_type_size(next_type);
5990+
}
5991+
5992+
/* Resize */
5993+
if (new_type_len < btf->hdr->type_len) {
5994+
void *tmp_types;
5995+
5996+
tmp_types = realloc(new_types, new_type_len);
5997+
if (new_type_len && !tmp_types) {
5998+
err = -ENOMEM;
5999+
goto done;
6000+
}
6001+
new_types = tmp_types;
6002+
btf->nr_types = new_nr_types - (offs ? 0 : 1);
6003+
btf->type_offs_cap = btf->nr_types;
6004+
btf->types_data_cap = new_type_len;
6005+
btf->hdr->type_len = new_type_len;
6006+
btf->hdr->str_off = new_type_len;
6007+
btf->raw_size = btf->hdr->hdr_len + btf->hdr->type_len + btf->hdr->str_len;
6008+
}
6009+
free(btf->types_data);
6010+
btf->types_data = new_types;
6011+
return 0;
6012+
6013+
done:
6014+
free(order_map);
6015+
free(new_types);
6016+
return libbpf_err(err);
6017+
}

tools/lib/bpf/btf.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,49 @@ LIBBPF_API int btf__dedup(struct btf *btf, const struct btf_dedup_opts *opts);
281281
*/
282282
LIBBPF_API int btf__relocate(struct btf *btf, const struct btf *base_btf);
283283

284+
struct btf_permute_opts {
285+
size_t sz;
286+
/* optional .BTF.ext info along the main BTF info */
287+
struct btf_ext *btf_ext;
288+
size_t :0;
289+
};
290+
#define btf_permute_opts__last_field btf_ext
291+
292+
/**
293+
* @brief **btf__permute()** performs in-place BTF type rearrangement
294+
* @param btf BTF object to permute
295+
* @param id_map Array mapping original type IDs to new IDs
296+
* @param id_map_cnt Number of elements in @id_map
297+
* @param opts Optional parameters for BTF extension updates
298+
* @return 0 on success, negative error code on failure
299+
*
300+
* **btf__permute()** rearranges BTF types according to the specified ID mapping.
301+
* The @id_map array defines the new type ID for each original type ID.
302+
*
303+
* For **base BTF**:
304+
* - @id_map must include all types from ID 0 to `btf__type_cnt(btf)-1`
305+
* - @id_map_cnt should be `btf__type_cnt(btf)`
306+
* - Mapping uses `id_map[original_id] = new_id`
307+
*
308+
* For **split BTF**:
309+
* - @id_map should cover only split types
310+
* - @id_map_cnt should be `btf__type_cnt(btf) - btf__type_cnt(btf__base_btf(btf))`
311+
* - Mapping uses `id_map[original_id - btf__type_cnt(btf__base_btf(btf))] = new_id`
312+
*
313+
* Setting @id_map element to 0 (except `id_map[0]` for base BTF) drops the corresponding type.
314+
* Dropped types must not be referenced by any retained types. After permutation,
315+
* type references in BTF data and optional extension are updated automatically.
316+
*
317+
* Note: Dropping types may orphan some strings, requiring subsequent **btf__dedup()**
318+
* to clean up unreferenced strings.
319+
*
320+
* On error, returns negative error code and sets errno:
321+
* - `-EINVAL`: Invalid parameters or ID mapping (duplicates, out-of-range)
322+
* - `-ENOMEM`: Memory allocation failure
323+
*/
324+
LIBBPF_API int btf__permute(struct btf *btf, __u32 *id_map, __u32 id_map_cnt,
325+
const struct btf_permute_opts *opts);
326+
284327
struct btf_dump;
285328

286329
struct btf_dump_opts {

tools/lib/bpf/libbpf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,4 +451,5 @@ LIBBPF_1.7.0 {
451451
global:
452452
bpf_map__set_exclusive_program;
453453
bpf_map__exclusive_program;
454+
btf__permute;
454455
} LIBBPF_1.6.0;

0 commit comments

Comments
 (0)