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 #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 { 68 struct btf_type *t = btf_type_by_id(r->btf, i); 69 struct btf_field_iter it; 70 __u32 *id; 71 int err; 72 73 err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); 74 if (err) 75 return err; 76 77 while ((id = btf_field_iter_next(&it))) 78 *id = r->id_map[*id]; 79 return 0; 80 } 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 { 88 const struct btf_name_info *ni1 = n1; 89 const struct btf_name_info *ni2 = n2; 90 int name_diff = strcmp(ni1->name, ni2->name); 91 92 if (!name_diff && ni1->needs_size && ni2->needs_size) 93 return ni2->size - ni1->size; 94 return name_diff; 95 } 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 { 106 struct btf_name_info *ret = NULL; 107 int high = nelems - 1; 108 int low = 0; 109 110 while (low <= high) { 111 int mid = (low + high)/2; 112 struct btf_name_info *val = &vals[mid]; 113 int diff = cmp_btf_name_size(key, val); 114 115 if (diff == 0) 116 ret = val; 117 /* even if found, keep searching for leftmost match */ 118 if (diff <= 0) 119 high = mid - 1; 120 else 121 low = mid + 1; 122 } 123 return ret; 124 } 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 { 134 struct btf_type *t = btf_type_by_id(r->btf, i); 135 struct btf_field_iter it; 136 __u32 *id; 137 int err; 138 139 if (!btf_is_composite(t)) 140 return 0; 141 142 err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_IDS); 143 if (err) 144 return err; 145 146 while ((id = btf_field_iter_next(&it))) { 147 __u32 next_id = *id; 148 149 while (next_id) { 150 t = btf_type_by_id(r->btf, next_id); 151 switch (btf_kind(t)) { 152 case BTF_KIND_CONST: 153 case BTF_KIND_RESTRICT: 154 case BTF_KIND_VOLATILE: 155 case BTF_KIND_TYPEDEF: 156 case BTF_KIND_TYPE_TAG: 157 next_id = t->type; 158 break; 159 case BTF_KIND_ARRAY: { 160 struct btf_array *a = btf_array(t); 161 162 next_id = a->type; 163 break; 164 } 165 case BTF_KIND_STRUCT: 166 case BTF_KIND_UNION: 167 if (next_id < r->nr_dist_base_types) 168 r->id_map[next_id] = BTF_IS_EMBEDDED; 169 next_id = 0; 170 break; 171 default: 172 next_id = 0; 173 break; 174 } 175 } 176 } 177 178 return 0; 179 } 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 { 186 struct btf_name_info *info, *info_end; 187 struct btf_type *base_t, *dist_t; 188 __u8 *base_name_cnt = NULL; 189 int err = 0; 190 __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 info = calloc(r->nr_dist_base_types, sizeof(*info)); 196 if (!info) { 197 err = -ENOMEM; 198 goto done; 199 } 200 info_end = info + r->nr_dist_base_types; 201 for (id = 0; id < r->nr_dist_base_types; id++) { 202 dist_t = btf_type_by_id(r->dist_base_btf, id); 203 info[id].name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); 204 info[id].id = id; 205 info[id].size = dist_t->size; 206 info[id].needs_size = true; 207 } 208 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 for (id = r->nr_dist_base_types; id < r->nr_split_types; id++) { 216 err = btf_mark_embedded_composite_type_ids(r, id); 217 if (err) 218 goto done; 219 } 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 base_name_cnt = calloc(r->base_str_len, sizeof(*base_name_cnt)); 226 if (!base_name_cnt) { 227 err = -ENOMEM; 228 goto done; 229 } 230 for (id = 1; id < r->nr_base_types; id++) { 231 base_t = btf_type_by_id(r->base_btf, id); 232 if (!btf_is_composite(base_t) || !base_t->name_off) 233 continue; 234 if (base_name_cnt[base_t->name_off] < 255) 235 base_name_cnt[base_t->name_off]++; 236 } 237 238 /* Now search base BTF for matching distilled base BTF types. */ 239 for (id = 1; id < r->nr_base_types; id++) { 240 struct btf_name_info *dist_info, base_info = {}; 241 int dist_kind, base_kind; 242 243 base_t = btf_type_by_id(r->base_btf, id); 244 /* distilled base consists of named types only. */ 245 if (!base_t->name_off) 246 continue; 247 base_kind = btf_kind(base_t); 248 base_info.id = id; 249 base_info.name = btf__name_by_offset(r->base_btf, base_t->name_off); 250 switch (base_kind) { 251 case BTF_KIND_INT: 252 case BTF_KIND_FLOAT: 253 case BTF_KIND_ENUM: 254 case BTF_KIND_ENUM64: 255 /* These types should match both name and size */ 256 base_info.needs_size = true; 257 base_info.size = base_t->size; 258 break; 259 case BTF_KIND_FWD: 260 /* No size considerations for fwds. */ 261 break; 262 case BTF_KIND_STRUCT: 263 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 base_info.needs_size = base_name_cnt[base_t->name_off] > 1; 272 base_info.size = base_t->size; 273 break; 274 default: 275 continue; 276 } 277 /* iterate over all matching distilled base types */ 278 for (dist_info = search_btf_name_size(&base_info, info, r->nr_dist_base_types); 279 dist_info != NULL && dist_info < info_end && 280 cmp_btf_name_size(&base_info, dist_info) == 0; 281 dist_info++) { 282 if (!dist_info->id || dist_info->id >= r->nr_dist_base_types) { 283 pr_warn("base BTF id [%d] maps to invalid distilled base BTF id [%d]\n", 284 id, dist_info->id); 285 err = -EINVAL; 286 goto done; 287 } 288 dist_t = btf_type_by_id(r->dist_base_btf, dist_info->id); 289 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 switch (dist_kind) { 296 case BTF_KIND_FWD: 297 switch (base_kind) { 298 case BTF_KIND_FWD: 299 if (btf_kflag(dist_t) != btf_kflag(base_t)) 300 continue; 301 break; 302 case BTF_KIND_STRUCT: 303 if (btf_kflag(base_t)) 304 continue; 305 break; 306 case BTF_KIND_UNION: 307 if (!btf_kflag(base_t)) 308 continue; 309 break; 310 default: 311 continue; 312 } 313 break; 314 case BTF_KIND_INT: 315 if (dist_kind != base_kind || 316 btf_int_encoding(base_t) != btf_int_encoding(dist_t)) 317 continue; 318 break; 319 case BTF_KIND_FLOAT: 320 if (dist_kind != base_kind) 321 continue; 322 break; 323 case BTF_KIND_ENUM: 324 /* ENUM and ENUM64 are encoded as sized ENUM in 325 * distilled base BTF. 326 */ 327 if (base_kind != dist_kind && base_kind != BTF_KIND_ENUM64) 328 continue; 329 break; 330 case BTF_KIND_STRUCT: 331 case BTF_KIND_UNION: 332 /* size verification is required for embedded 333 * struct/unions. 334 */ 335 if (r->id_map[dist_info->id] == BTF_IS_EMBEDDED && 336 base_t->size != dist_t->size) 337 continue; 338 break; 339 default: 340 continue; 341 } 342 if (r->id_map[dist_info->id] && 343 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 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 base_info.name, dist_info->id, 354 base_t->size, id, r->id_map[dist_info->id]); 355 err = -EINVAL; 356 goto done; 357 } 358 /* map id and name */ 359 r->id_map[dist_info->id] = id; 360 r->str_map[dist_t->name_off] = base_t->name_off; 361 } 362 } 363 /* ensure all distilled BTF ids now have a mapping... */ 364 for (id = 1; id < r->nr_dist_base_types; id++) { 365 const char *name; 366 367 if (r->id_map[id] && r->id_map[id] != BTF_IS_EMBEDDED) 368 continue; 369 dist_t = btf_type_by_id(r->dist_base_btf, id); 370 name = btf__name_by_offset(r->dist_base_btf, dist_t->name_off); 371 pr_warn("distilled base BTF type '%s' [%d] is not mapped to base BTF id\n", 372 name, id); 373 err = -EINVAL; 374 break; 375 } 376 done: 377 free(base_name_cnt); 378 free(info); 379 return err; 380 } 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 { 385 unsigned int i; 386 387 for (i = 1; i < r->nr_dist_base_types; i++) { 388 struct btf_type *t = btf_type_by_id(r->dist_base_btf, i); 389 int kind = btf_kind(t); 390 391 switch (kind) { 392 case BTF_KIND_INT: 393 case BTF_KIND_FLOAT: 394 case BTF_KIND_ENUM: 395 case BTF_KIND_STRUCT: 396 case BTF_KIND_UNION: 397 case BTF_KIND_FWD: 398 if (t->name_off) 399 break; 400 pr_warn("type [%d], kind [%d] is invalid for distilled base BTF; it is anonymous\n", 401 i, kind); 402 return -EINVAL; 403 default: 404 pr_warn("type [%d] in distilled based BTF has unexpected kind [%d]\n", 405 i, kind); 406 return -EINVAL; 407 } 408 } 409 return 0; 410 } 411 412 static int btf_relocate_rewrite_strs(struct btf_relocate *r, __u32 i) 413 { 414 struct btf_type *t = btf_type_by_id(r->btf, i); 415 struct btf_field_iter it; 416 __u32 *str_off; 417 int off, err; 418 419 err = btf_field_iter_init(&it, t, BTF_FIELD_ITER_STRS); 420 if (err) 421 return err; 422 423 while ((str_off = btf_field_iter_next(&it))) { 424 if (!*str_off) 425 continue; 426 if (*str_off >= r->dist_str_len) { 427 *str_off += r->base_str_len - r->dist_str_len; 428 } else { 429 off = r->str_map[*str_off]; 430 if (!off) { 431 pr_warn("string '%s' [offset %u] is not mapped to base BTF", 432 btf__str_by_offset(r->btf, off), *str_off); 433 return -ENOENT; 434 } 435 *str_off = off; 436 } 437 } 438 return 0; 439 } 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 { 446 unsigned int nr_types = btf__type_cnt(btf); 447 const struct btf_header *dist_base_hdr; 448 const struct btf_header *base_hdr; 449 struct btf_relocate r = {}; 450 int err = 0; 451 __u32 id, i; 452 453 r.dist_base_btf = btf__base_btf(btf); 454 if (!base_btf || r.dist_base_btf == base_btf) 455 return -EINVAL; 456 457 r.nr_dist_base_types = btf__type_cnt(r.dist_base_btf); 458 r.nr_base_types = btf__type_cnt(base_btf); 459 r.nr_split_types = nr_types - r.nr_dist_base_types; 460 r.btf = btf; 461 r.base_btf = base_btf; 462 463 r.id_map = calloc(nr_types, sizeof(*r.id_map)); 464 r.str_map = calloc(btf_header(r.dist_base_btf)->str_len, sizeof(*r.str_map)); 465 dist_base_hdr = btf_header(r.dist_base_btf); 466 base_hdr = btf_header(r.base_btf); 467 r.dist_str_len = dist_base_hdr->str_len; 468 r.base_str_len = base_hdr->str_len; 469 if (!r.id_map || !r.str_map) { 470 err = -ENOMEM; 471 goto err_out; 472 } 473 474 err = btf_relocate_validate_distilled_base(&r); 475 if (err) 476 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 for (id = r.nr_dist_base_types; id < nr_types; id++) 483 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 err = btf_relocate_map_distilled_base(&r); 490 if (err) 491 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 for (i = 0, id = r.nr_dist_base_types; i < r.nr_split_types; i++, id++) { 498 err = btf_relocate_rewrite_type_id(&r, id); 499 if (err) 500 goto err_out; 501 } 502 /* String offsets now need to be updated using the str_map. */ 503 for (i = 0; i < r.nr_split_types; i++) { 504 err = btf_relocate_rewrite_strs(&r, i + r.nr_dist_base_types); 505 if (err) 506 goto err_out; 507 } 508 /* Finally reset base BTF to be base_btf */ 509 btf_set_base_btf(btf, base_btf); 510 511 if (id_map) { 512 *id_map = r.id_map; 513 r.id_map = NULL; 514 } 515 err_out: 516 free(r.id_map); 517 free(r.str_map); 518 return err; 519 } 520
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.