Coverage Report

Created: 2025-11-11 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libbpf/src/btf_relocate.c
Line
Count
Source
1
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2
/* Copyright (c) 2024, Oracle and/or its affiliates. */
3
4
#ifndef _GNU_SOURCE
5
#define _GNU_SOURCE
6
#endif
7
8
#ifdef __KERNEL__
9
#include <linux/bpf.h>
10
#include <linux/bsearch.h>
11
#include <linux/btf.h>
12
#include <linux/sort.h>
13
#include <linux/string.h>
14
#include <linux/bpf_verifier.h>
15
16
#define btf_type_by_id        (struct btf_type *)btf_type_by_id
17
#define btf__type_cnt       btf_nr_types
18
#define btf__base_btf       btf_base_btf
19
#define btf__name_by_offset     btf_name_by_offset
20
#define btf__str_by_offset      btf_str_by_offset
21
#define btf_kflag       btf_type_kflag
22
23
#define calloc(nmemb, sz)     kvcalloc(nmemb, sz, GFP_KERNEL | __GFP_NOWARN)
24
#define free(ptr)       kvfree(ptr)
25
#define qsort(base, num, sz, cmp)   sort(base, num, sz, cmp, NULL)
26
27
#else
28
29
#include "btf.h"
30
#include "bpf.h"
31
#include "libbpf.h"
32
#include "libbpf_internal.h"
33
34
#endif /* __KERNEL__ */
35
36
struct btf;
37
38
struct btf_relocate {
39
  struct btf *btf;
40
  const struct btf *base_btf;
41
  const struct btf *dist_base_btf;
42
  unsigned int nr_base_types;
43
  unsigned int nr_split_types;
44
  unsigned int nr_dist_base_types;
45
  int dist_str_len;
46
  int base_str_len;
47
  __u32 *id_map;
48
  __u32 *str_map;
49
};
50
51
/* Set temporarily in relocation id_map if distilled base struct/union is
52
 * embedded in a split BTF struct/union; in such a case, size information must
53
 * match between distilled base BTF and base BTF representation of type.
54
 */
55
0
#define BTF_IS_EMBEDDED ((__u32)-1)
56
57
/* <name, size, id> triple used in sorting/searching distilled base BTF. */
58
struct btf_name_info {
59
  const char *name;
60
  /* set when search requires a size match */
61
  bool needs_size: 1;
62
  unsigned int size: 31;
63
  __u32 id;
64
};
65
66
static int btf_relocate_rewrite_type_id(struct btf_relocate *r, __u32 i)
67
0
{
68
0
  struct btf_type *t = btf_type_by_id(r->btf, i);
69
0
  struct btf_field_iter it;
70
0
  __u32 *id;
71
0
  int err;
72
73
0
  err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS);
74
0
  if (err)
75
0
    return err;
76
77
0
  while ((id = btf_field_iter_next(&it)))
78
0
    *id = r->id_map[*id];
79
0
  return 0;
80
0
}
81
82
/* Simple string comparison used for sorting within BTF, since all distilled
83
 * types are named.  If strings match, and size is non-zero for both elements
84
 * fall back to using size for ordering.
85
 */
86
static int cmp_btf_name_size(const void *n1, const void *n2)
87
0
{
88
0
  const struct btf_name_info *ni1 = n1;
89
0
  const struct btf_name_info *ni2 = n2;
90
0
  int name_diff = strcmp(ni1->name, ni2->name);
91
92
0
  if (!name_diff && ni1->needs_size && ni2->needs_size)
93
0
    return ni2->size - ni1->size;
94
0
  return name_diff;
95
0
}
96
97
/* Binary search with a small twist; find leftmost element that matches
98
 * so that we can then iterate through all exact matches.  So for example
99
 * searching { "a", "bb", "bb", "c" }  we would always match on the
100
 * leftmost "bb".
101
 */
102
static struct btf_name_info *search_btf_name_size(struct btf_name_info *key,
103
              struct btf_name_info *vals,
104
              int nelems)
105
0
{
106
0
  struct btf_name_info *ret = NULL;
107
0
  int high = nelems - 1;
108
0
  int low = 0;
109
110
0
  while (low <= high) {
111
0
    int mid = (low + high)/2;
112
0
    struct btf_name_info *val = &vals[mid];
113
0
    int diff = cmp_btf_name_size(key, val);
114
115
0
    if (diff == 0)
116
0
      ret = val;
117
    /* even if found, keep searching for leftmost match */
118
0
    if (diff <= 0)
119
0
      high = mid - 1;
120
0
    else
121
0
      low = mid + 1;
122
0
  }
123
0
  return ret;
124
0
}
125
126
/* If a member of a split BTF struct/union refers to a base BTF
127
 * struct/union, mark that struct/union id temporarily in the id_map
128
 * with BTF_IS_EMBEDDED.  Members can be const/restrict/volatile/typedef
129
 * reference types, but if a pointer is encountered, the type is no longer
130
 * considered embedded.
131
 */
132
static int btf_mark_embedded_composite_type_ids(struct btf_relocate *r, __u32 i)
133
0
{
134
0
  struct btf_type *t = btf_type_by_id(r->btf, i);
135
0
  struct btf_field_iter it;
136
0
  __u32 *id;
137
0
  int err;
138
139
0
  if (!btf_is_composite(t))
140
0
    return 0;
141
142
0
  err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS);
143
0
  if (err)
144
0
    return err;
145
146
0
  while ((id = btf_field_iter_next(&it))) {
147
0
    __u32 next_id = *id;
148
149
0
    while (next_id) {
150
0
      t = btf_type_by_id(r->btf, next_id);
151
0
      switch (btf_kind(t)) {
152
0
      case BTF_KIND_CONST:
153
0
      case BTF_KIND_RESTRICT:
154
0
      case BTF_KIND_VOLATILE:
155
0
      case BTF_KIND_TYPEDEF:
156
0
      case BTF_KIND_TYPE_TAG:
157
0
        next_id = t->type;
158
0
        break;
159
0
      case BTF_KIND_ARRAY: {
160
0
        struct btf_array *a = btf_array(t);
161
162
0
        next_id = a->type;
163
0
        break;
164
0
      }
165
0
      case BTF_KIND_STRUCT:
166
0
      case BTF_KIND_UNION:
167
0
        if (next_id < r->nr_dist_base_types)
168
0
          r->id_map[next_id] = BTF_IS_EMBEDDED;
169
0
        next_id = 0;
170
0
        break;
171
0
      default:
172
0
        next_id = 0;
173
0
        break;
174
0
      }
175
0
    }
176
0
  }
177
178
0
  return 0;
179
0
}
180
181
/* Build a map from distilled base BTF ids to base BTF ids. To do so, iterate
182
 * through base BTF looking up distilled type (using binary search) equivalents.
183
 */
184
static int btf_relocate_map_distilled_base(struct btf_relocate *r)
185
0
{
186
0
  struct btf_name_info *info, *info_end;
187
0
  struct btf_type *base_t, *dist_t;
188
0
  __u8 *base_name_cnt = NULL;
189
0
  int err = 0;
190
0
  __u32 id;
191
192
  /* generate a sort index array of name/type ids sorted by name for
193
   * distilled base BTF to speed name-based lookups.
194
   */
195
0
  info = calloc(r->nr_dist_base_types, sizeof(*info));
196
0
  if (!info) {
197
0
    err = -ENOMEM;
198
0
    goto done;
199
0
  }
200
0
  info_end = info + r->nr_dist_base_types;
201
0
  for (id = 0; id < r->nr_dist_base_types; id++) {
202
0
    dist_t = btf_type_by_id(r->dist_base_btf, id);
203
0
    info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
204
0
    info[id].id = id;
205
0
    info[id].size = dist_t->size;
206
0
    info[id].needs_size = true;
207
0
  }
208
0
  qsort(info, r->nr_dist_base_types, sizeof(*info), cmp_btf_name_size);
209
210
  /* Mark distilled base struct/union members of split BTF structs/unions
211
   * in id_map with BTF_IS_EMBEDDED; this signals that these types
212
   * need to match both name and size, otherwise embedding the base
213
   * struct/union in the split type is invalid.
214
   */
215
0
  for (id = r->nr_dist_base_types; id < r->nr_dist_base_types + r->nr_split_types; id++) {
216
0
    err = btf_mark_embedded_composite_type_ids(r, id);
217
0
    if (err)
218
0
      goto done;
219
0
  }
220
221
  /* Collect name counts for composite types in base BTF.  If multiple
222
   * instances of a struct/union of the same name exist, we need to use
223
   * size to determine which to map to since name alone is ambiguous.
224
   */
225
0
  base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt));
226
0
  if (!base_name_cnt) {
227
0
    err = -ENOMEM;
228
0
    goto done;
229
0
  }
230
0
  for (id = 1; id < r->nr_base_types; id++) {
231
0
    base_t = btf_type_by_id(r->base_btf, id);
232
0
    if (!btf_is_composite(base_t) || !base_t->name_off)
233
0
      continue;
234
0
    if (base_name_cnt[base_t->name_off] < 255)
235
0
      base_name_cnt[base_t->name_off]++;
236
0
  }
237
238
  /* Now search base BTF for matching distilled base BTF types. */
239
0
  for (id = 1; id < r->nr_base_types; id++) {
240
0
    struct btf_name_info *dist_info, base_info = {};
241
0
    int dist_kind, base_kind;
242
243
0
    base_t = btf_type_by_id(r->base_btf, id);
244
    /* distilled base consists of named types only. */
245
0
    if (!base_t->name_off)
246
0
      continue;
247
0
    base_kind = btf_kind(base_t);
248
0
    base_info.id = id;
249
0
    base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off);
250
0
    switch (base_kind) {
251
0
    case BTF_KIND_INT:
252
0
    case BTF_KIND_FLOAT:
253
0
    case BTF_KIND_ENUM:
254
0
    case BTF_KIND_ENUM64:
255
      /* These types should match both name and size */
256
0
      base_info.needs_size = true;
257
0
      base_info.size = base_t->size;
258
0
      break;
259
0
    case BTF_KIND_FWD:
260
      /* No size considerations for fwds. */
261
0
      break;
262
0
    case BTF_KIND_STRUCT:
263
0
    case BTF_KIND_UNION:
264
      /* Size only needs to be used for struct/union if there
265
       * are multiple types in base BTF with the same name.
266
       * If there are multiple _distilled_ types with the same
267
       * name (a very unlikely scenario), that doesn't matter
268
       * unless corresponding _base_ types to match them are
269
       * missing.
270
       */
271
0
      base_info.needs_size = base_name_cnt[base_t->name_off] > 1;
272
0
      base_info.size = base_t->size;
273
0
      break;
274
0
    default:
275
0
      continue;
276
0
    }
277
    /* iterate over all matching distilled base types */
278
0
    for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types);
279
0
         dist_info != NULL && dist_info < info_end &&
280
0
         cmp_btf_name_size(&base_info, dist_info) == 0;
281
0
         dist_info++) {
282
0
      if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) {
283
0
        pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n",
284
0
          id, dist_info->id);
285
0
        err = -EINVAL;
286
0
        goto done;
287
0
      }
288
0
      dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id);
289
0
      dist_kind = btf_kind(dist_t);
290
291
      /* Validate that the found distilled type is compatible.
292
       * Do not error out on mismatch as another match may
293
       * occur for an identically-named type.
294
       */
295
0
      switch (dist_kind) {
296
0
      case BTF_KIND_FWD:
297
0
        switch (base_kind) {
298
0
        case BTF_KIND_FWD:
299
0
          if (btf_kflag(dist_t) != btf_kflag(base_t))
300
0
            continue;
301
0
          break;
302
0
        case BTF_KIND_STRUCT:
303
0
          if (btf_kflag(base_t))
304
0
            continue;
305
0
          break;
306
0
        case BTF_KIND_UNION:
307
0
          if (!btf_kflag(base_t))
308
0
            continue;
309
0
          break;
310
0
        default:
311
0
          continue;
312
0
        }
313
0
        break;
314
0
      case BTF_KIND_INT:
315
0
        if (dist_kind != base_kind ||
316
0
            btf_int_encoding(base_t) != btf_int_encoding(dist_t))
317
0
          continue;
318
0
        break;
319
0
      case BTF_KIND_FLOAT:
320
0
        if (dist_kind != base_kind)
321
0
          continue;
322
0
        break;
323
0
      case BTF_KIND_ENUM:
324
        /* ENUM and ENUM64 are encoded as sized ENUM in
325
         * distilled base BTF.
326
         */
327
0
        if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64)
328
0
          continue;
329
0
        break;
330
0
      case BTF_KIND_STRUCT:
331
0
      case BTF_KIND_UNION:
332
        /* size verification is required for embedded
333
         * struct/unions.
334
         */
335
0
        if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED &&
336
0
            base_t->size != dist_t->size)
337
0
          continue;
338
0
        break;
339
0
      default:
340
0
        continue;
341
0
      }
342
0
      if (r->id_map[dist_info->id] &&
343
0
          r->id_map[dist_info->id] != BTF_IS_EMBEDDED) {
344
        /* we already have a match; this tells us that
345
         * multiple base types of the same name
346
         * have the same size, since for cases where
347
         * multiple types have the same name we match
348
         * on name and size.  In this case, we have
349
         * no way of determining which to relocate
350
         * to in base BTF, so error out.
351
         */
352
0
        pr_warn("distilled base BTF type '%s' [%u], size %u has multiple candidates of the same size (ids [%u, %u]) in base BTF\n",
353
0
          base_info.name, dist_info->id,
354
0
          base_t->size, id, r->id_map[dist_info->id]);
355
0
        err = -EINVAL;
356
0
        goto done;
357
0
      }
358
      /* map id and name */
359
0
      r->id_map[dist_info->id] = id;
360
0
      r->str_map[dist_t->name_off] = base_t->name_off;
361
0
    }
362
0
  }
363
  /* ensure all distilled BTF ids now have a mapping... */
364
0
  for (id = 1; id < r->nr_dist_base_types; id++) {
365
0
    const char *name;
366
367
0
    if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED)
368
0
      continue;
369
0
    dist_t = btf_type_by_id(r->dist_base_btf, id);
370
0
    name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off);
371
0
    pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n",
372
0
      name, id);
373
0
    err = -EINVAL;
374
0
    break;
375
0
  }
376
0
done:
377
0
  free(base_name_cnt);
378
0
  free(info);
379
0
  return err;
380
0
}
381
382
/* distilled base should only have named int/float/enum/fwd/struct/union types. */
383
static int btf_relocate_validate_distilled_base(struct btf_relocate *r)
384
0
{
385
0
  unsigned int i;
386
387
0
  for (i = 1; i < r->nr_dist_base_types; i++) {
388
0
    struct btf_type *t = btf_type_by_id(r->dist_base_btf, i);
389
0
    int kind = btf_kind(t);
390
391
0
    switch (kind) {
392
0
    case BTF_KIND_INT:
393
0
    case BTF_KIND_FLOAT:
394
0
    case BTF_KIND_ENUM:
395
0
    case BTF_KIND_STRUCT:
396
0
    case BTF_KIND_UNION:
397
0
    case BTF_KIND_FWD:
398
0
      if (t->name_off)
399
0
        break;
400
0
      pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n",
401
0
        i, kind);
402
0
      return -EINVAL;
403
0
    default:
404
0
      pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n",
405
0
        i, kind);
406
0
      return -EINVAL;
407
0
    }
408
0
  }
409
0
  return 0;
410
0
}
411
412
static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i)
413
0
{
414
0
  struct btf_type *t = btf_type_by_id(r->btf, i);
415
0
  struct btf_field_iter it;
416
0
  __u32 *str_off;
417
0
  int off, err;
418
419
0
  err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS);
420
0
  if (err)
421
0
    return err;
422
423
0
  while ((str_off = btf_field_iter_next(&it))) {
424
0
    if (!*str_off)
425
0
      continue;
426
0
    if (*str_off >= r->dist_str_len) {
427
0
      *str_off += r->base_str_len - r->dist_str_len;
428
0
    } else {
429
0
      off = r->str_map[*str_off];
430
0
      if (!off) {
431
0
        pr_warn("string '%s' [offset %u] is not mapped to base BTF\n",
432
0
          btf__str_by_offset(r->btf, off), *str_off);
433
0
        return -ENOENT;
434
0
      }
435
0
      *str_off = off;
436
0
    }
437
0
  }
438
0
  return 0;
439
0
}
440
441
/* If successful, output of relocation is updated BTF with base BTF pointing
442
 * at base_btf, and type ids, strings adjusted accordingly.
443
 */
444
int btf_relocate(struct btf *btf, const struct btf *base_btf, __u32 **id_map)
445
0
{
446
0
  unsigned int nr_types = btf__type_cnt(btf);
447
0
  const struct btf_header *dist_base_hdr;
448
0
  const struct btf_header *base_hdr;
449
0
  struct btf_relocate r = {};
450
0
  int err = 0;
451
0
  __u32 id, i;
452
453
0
  r.dist_base_btf = btf__base_btf(btf);
454
0
  if (!base_btf || r.dist_base_btf == base_btf)
455
0
    return -EINVAL;
456
457
0
  r.nr_dist_base_types = btf__type_cnt(r.dist_base_btf);
458
0
  r.nr_base_types = btf__type_cnt(base_btf);
459
0
  r.nr_split_types = nr_types - r.nr_dist_base_types;
460
0
  r.btf = btf;
461
0
  r.base_btf = base_btf;
462
463
0
  r.id_map = calloc(nr_types, sizeof(*r.id_map));
464
0
  r.str_map = calloc(btf_header(r.dist_base_btf)->str_len, sizeof(*r.str_map));
465
0
  dist_base_hdr = btf_header(r.dist_base_btf);
466
0
  base_hdr = btf_header(r.base_btf);
467
0
  r.dist_str_len = dist_base_hdr->str_len;
468
0
  r.base_str_len = base_hdr->str_len;
469
0
  if (!r.id_map || !r.str_map) {
470
0
    err = -ENOMEM;
471
0
    goto err_out;
472
0
  }
473
474
0
  err = btf_relocate_validate_distilled_base(&r);
475
0
  if (err)
476
0
    goto err_out;
477
478
  /* Split BTF ids need to be adjusted as base and distilled base
479
   * have different numbers of types, changing the start id of split
480
   * BTF.
481
   */
482
0
  for (id = r.nr_dist_base_types; id < nr_types; id++)
483
0
    r.id_map[id] = id + r.nr_base_types - r.nr_dist_base_types;
484
485
  /* Build a map from distilled base ids to actual base BTF ids; it is used
486
   * to update split BTF id references.  Also build a str_map mapping from
487
   * distilled base BTF names to base BTF names.
488
   */
489
0
  err = btf_relocate_map_distilled_base(&r);
490
0
  if (err)
491
0
    goto err_out;
492
493
  /* Next, rewrite type ids in split BTF, replacing split ids with updated
494
   * ids based on number of types in base BTF, and base ids with
495
   * relocated ids from base_btf.
496
   */
497
0
  for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) {
498
0
    err = btf_relocate_rewrite_type_id(&r, id);
499
0
    if (err)
500
0
      goto err_out;
501
0
  }
502
  /* String offsets now need to be updated using the str_map. */
503
0
  for (i = 0; i < r.nr_split_types; i++) {
504
0
    err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types);
505
0
    if (err)
506
0
      goto err_out;
507
0
  }
508
  /* Finally reset base BTF to be base_btf */
509
0
  btf_set_base_btf(btf, base_btf);
510
511
0
  if (id_map) {
512
0
    *id_map = r.id_map;
513
0
    r.id_map = NULL;
514
0
  }
515
0
err_out:
516
0
  free(r.id_map);
517
0
  free(r.str_map);
518
0
  return err;
519
0
}