2636 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2019 Facebook */3 4#ifndef _GNU_SOURCE5#define _GNU_SOURCE6#endif7#include <ctype.h>8#include <errno.h>9#include <fcntl.h>10#include <libgen.h>11#include <linux/err.h>12#include <stdbool.h>13#include <stdio.h>14#include <string.h>15#include <unistd.h>16#include <bpf/bpf.h>17#include <bpf/libbpf.h>18#include <bpf/libbpf_internal.h>19#include <sys/types.h>20#include <sys/stat.h>21#include <sys/mman.h>22#include <bpf/btf.h>23 24#include "json_writer.h"25#include "main.h"26 27#define MAX_OBJ_NAME_LEN 6428 29static void sanitize_identifier(char *name)30{31 int i;32 33 for (i = 0; name[i]; i++)34 if (!isalnum(name[i]) && name[i] != '_')35 name[i] = '_';36}37 38static bool str_has_prefix(const char *str, const char *prefix)39{40 return strncmp(str, prefix, strlen(prefix)) == 0;41}42 43static bool str_has_suffix(const char *str, const char *suffix)44{45 size_t i, n1 = strlen(str), n2 = strlen(suffix);46 47 if (n1 < n2)48 return false;49 50 for (i = 0; i < n2; i++) {51 if (str[n1 - i - 1] != suffix[n2 - i - 1])52 return false;53 }54 55 return true;56}57 58static const struct btf_type *59resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id)60{61 const struct btf_type *t;62 63 t = skip_mods_and_typedefs(btf, id, NULL);64 if (!btf_is_ptr(t))65 return NULL;66 67 t = skip_mods_and_typedefs(btf, t->type, res_id);68 69 return btf_is_func_proto(t) ? t : NULL;70}71 72static void get_obj_name(char *name, const char *file)73{74 char file_copy[PATH_MAX];75 76 /* Using basename() POSIX version to be more portable. */77 strncpy(file_copy, file, PATH_MAX - 1)[PATH_MAX - 1] = '\0';78 strncpy(name, basename(file_copy), MAX_OBJ_NAME_LEN - 1)[MAX_OBJ_NAME_LEN - 1] = '\0';79 if (str_has_suffix(name, ".o"))80 name[strlen(name) - 2] = '\0';81 sanitize_identifier(name);82}83 84static void get_header_guard(char *guard, const char *obj_name, const char *suffix)85{86 int i;87 88 sprintf(guard, "__%s_%s__", obj_name, suffix);89 for (i = 0; guard[i]; i++)90 guard[i] = toupper(guard[i]);91}92 93static bool get_map_ident(const struct bpf_map *map, char *buf, size_t buf_sz)94{95 static const char *sfxs[] = { ".data", ".rodata", ".bss", ".kconfig" };96 const char *name = bpf_map__name(map);97 int i, n;98 99 if (!bpf_map__is_internal(map)) {100 snprintf(buf, buf_sz, "%s", name);101 return true;102 }103 104 for (i = 0, n = ARRAY_SIZE(sfxs); i < n; i++) {105 const char *sfx = sfxs[i], *p;106 107 p = strstr(name, sfx);108 if (p) {109 snprintf(buf, buf_sz, "%s", p + 1);110 sanitize_identifier(buf);111 return true;112 }113 }114 115 return false;116}117 118static bool get_datasec_ident(const char *sec_name, char *buf, size_t buf_sz)119{120 static const char *pfxs[] = { ".data", ".rodata", ".bss", ".kconfig" };121 int i, n;122 123 /* recognize hard coded LLVM section name */124 if (strcmp(sec_name, ".addr_space.1") == 0) {125 /* this is the name to use in skeleton */126 snprintf(buf, buf_sz, "arena");127 return true;128 }129 for (i = 0, n = ARRAY_SIZE(pfxs); i < n; i++) {130 const char *pfx = pfxs[i];131 132 if (str_has_prefix(sec_name, pfx)) {133 snprintf(buf, buf_sz, "%s", sec_name + 1);134 sanitize_identifier(buf);135 return true;136 }137 }138 139 return false;140}141 142static void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args)143{144 vprintf(fmt, args);145}146 147static int codegen_datasec_def(struct bpf_object *obj,148 struct btf *btf,149 struct btf_dump *d,150 const struct btf_type *sec,151 const char *obj_name)152{153 const char *sec_name = btf__name_by_offset(btf, sec->name_off);154 const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec);155 int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec);156 char var_ident[256], sec_ident[256];157 bool strip_mods = false;158 159 if (!get_datasec_ident(sec_name, sec_ident, sizeof(sec_ident)))160 return 0;161 162 if (strcmp(sec_name, ".kconfig") != 0)163 strip_mods = true;164 165 printf(" struct %s__%s {\n", obj_name, sec_ident);166 for (i = 0; i < vlen; i++, sec_var++) {167 const struct btf_type *var = btf__type_by_id(btf, sec_var->type);168 const char *var_name = btf__name_by_offset(btf, var->name_off);169 DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,170 .field_name = var_ident,171 .indent_level = 2,172 .strip_mods = strip_mods,173 );174 int need_off = sec_var->offset, align_off, align;175 __u32 var_type_id = var->type;176 177 /* static variables are not exposed through BPF skeleton */178 if (btf_var(var)->linkage == BTF_VAR_STATIC)179 continue;180 181 if (off > need_off) {182 p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n",183 sec_name, i, need_off, off);184 return -EINVAL;185 }186 187 align = btf__align_of(btf, var->type);188 if (align <= 0) {189 p_err("Failed to determine alignment of variable '%s': %d",190 var_name, align);191 return -EINVAL;192 }193 /* Assume 32-bit architectures when generating data section194 * struct memory layout. Given bpftool can't know which target195 * host architecture it's emitting skeleton for, we need to be196 * conservative and assume 32-bit one to ensure enough padding197 * bytes are generated for pointer and long types. This will198 * still work correctly for 64-bit architectures, because in199 * the worst case we'll generate unnecessary padding field,200 * which on 64-bit architectures is not strictly necessary and201 * would be handled by natural 8-byte alignment. But it still202 * will be a correct memory layout, based on recorded offsets203 * in BTF.204 */205 if (align > 4)206 align = 4;207 208 align_off = (off + align - 1) / align * align;209 if (align_off != need_off) {210 printf("\t\tchar __pad%d[%d];\n",211 pad_cnt, need_off - off);212 pad_cnt++;213 }214 215 /* sanitize variable name, e.g., for static vars inside216 * a function, it's name is '<function name>.<variable name>',217 * which we'll turn into a '<function name>_<variable name>'218 */219 var_ident[0] = '\0';220 strncat(var_ident, var_name, sizeof(var_ident) - 1);221 sanitize_identifier(var_ident);222 223 printf("\t\t");224 err = btf_dump__emit_type_decl(d, var_type_id, &opts);225 if (err)226 return err;227 printf(";\n");228 229 off = sec_var->offset + sec_var->size;230 }231 printf(" } *%s;\n", sec_ident);232 return 0;233}234 235static const struct btf_type *find_type_for_map(struct btf *btf, const char *map_ident)236{237 int n = btf__type_cnt(btf), i;238 char sec_ident[256];239 240 for (i = 1; i < n; i++) {241 const struct btf_type *t = btf__type_by_id(btf, i);242 const char *name;243 244 if (!btf_is_datasec(t))245 continue;246 247 name = btf__str_by_offset(btf, t->name_off);248 if (!get_datasec_ident(name, sec_ident, sizeof(sec_ident)))249 continue;250 251 if (strcmp(sec_ident, map_ident) == 0)252 return t;253 }254 return NULL;255}256 257static bool is_mmapable_map(const struct bpf_map *map, char *buf, size_t sz)258{259 size_t tmp_sz;260 261 if (bpf_map__type(map) == BPF_MAP_TYPE_ARENA && bpf_map__initial_value(map, &tmp_sz)) {262 snprintf(buf, sz, "arena");263 return true;264 }265 266 if (!bpf_map__is_internal(map) || !(bpf_map__map_flags(map) & BPF_F_MMAPABLE))267 return false;268 269 if (!get_map_ident(map, buf, sz))270 return false;271 272 return true;273}274 275static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)276{277 struct btf *btf = bpf_object__btf(obj);278 struct btf_dump *d;279 struct bpf_map *map;280 const struct btf_type *sec;281 char map_ident[256];282 int err = 0;283 284 d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);285 if (!d)286 return -errno;287 288 bpf_object__for_each_map(map, obj) {289 /* only generate definitions for memory-mapped internal maps */290 if (!is_mmapable_map(map, map_ident, sizeof(map_ident)))291 continue;292 293 sec = find_type_for_map(btf, map_ident);294 295 /* In some cases (e.g., sections like .rodata.cst16 containing296 * compiler allocated string constants only) there will be297 * special internal maps with no corresponding DATASEC BTF298 * type. In such case, generate empty structs for each such299 * map. It will still be memory-mapped and its contents300 * accessible from user-space through BPF skeleton.301 */302 if (!sec) {303 printf(" struct %s__%s {\n", obj_name, map_ident);304 printf(" } *%s;\n", map_ident);305 } else {306 err = codegen_datasec_def(obj, btf, d, sec, obj_name);307 if (err)308 goto out;309 }310 }311 312 313out:314 btf_dump__free(d);315 return err;316}317 318static bool btf_is_ptr_to_func_proto(const struct btf *btf,319 const struct btf_type *v)320{321 return btf_is_ptr(v) && btf_is_func_proto(btf__type_by_id(btf, v->type));322}323 324static int codegen_subskel_datasecs(struct bpf_object *obj, const char *obj_name)325{326 struct btf *btf = bpf_object__btf(obj);327 struct btf_dump *d;328 struct bpf_map *map;329 const struct btf_type *sec, *var;330 const struct btf_var_secinfo *sec_var;331 int i, err = 0, vlen;332 char map_ident[256], sec_ident[256];333 bool strip_mods = false, needs_typeof = false;334 const char *sec_name, *var_name;335 __u32 var_type_id;336 337 d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);338 if (!d)339 return -errno;340 341 bpf_object__for_each_map(map, obj) {342 /* only generate definitions for memory-mapped internal maps */343 if (!is_mmapable_map(map, map_ident, sizeof(map_ident)))344 continue;345 346 sec = find_type_for_map(btf, map_ident);347 if (!sec)348 continue;349 350 sec_name = btf__name_by_offset(btf, sec->name_off);351 if (!get_datasec_ident(sec_name, sec_ident, sizeof(sec_ident)))352 continue;353 354 strip_mods = strcmp(sec_name, ".kconfig") != 0;355 printf(" struct %s__%s {\n", obj_name, sec_ident);356 357 sec_var = btf_var_secinfos(sec);358 vlen = btf_vlen(sec);359 for (i = 0; i < vlen; i++, sec_var++) {360 DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts,361 .indent_level = 2,362 .strip_mods = strip_mods,363 /* we'll print the name separately */364 .field_name = "",365 );366 367 var = btf__type_by_id(btf, sec_var->type);368 var_name = btf__name_by_offset(btf, var->name_off);369 var_type_id = var->type;370 371 /* static variables are not exposed through BPF skeleton */372 if (btf_var(var)->linkage == BTF_VAR_STATIC)373 continue;374 375 /* The datasec member has KIND_VAR but we want the376 * underlying type of the variable (e.g. KIND_INT).377 */378 var = skip_mods_and_typedefs(btf, var->type, NULL);379 380 printf("\t\t");381 /* Func and array members require special handling.382 * Instead of producing `typename *var`, they produce383 * `typeof(typename) *var`. This allows us to keep a384 * similar syntax where the identifier is just prefixed385 * by *, allowing us to ignore C declaration minutiae.386 */387 needs_typeof = btf_is_array(var) || btf_is_ptr_to_func_proto(btf, var);388 if (needs_typeof)389 printf("__typeof__(");390 391 err = btf_dump__emit_type_decl(d, var_type_id, &opts);392 if (err)393 goto out;394 395 if (needs_typeof)396 printf(")");397 398 printf(" *%s;\n", var_name);399 }400 printf(" } %s;\n", sec_ident);401 }402 403out:404 btf_dump__free(d);405 return err;406}407 408static void codegen(const char *template, ...)409{410 const char *src, *end;411 int skip_tabs = 0, n;412 char *s, *dst;413 va_list args;414 char c;415 416 n = strlen(template);417 s = malloc(n + 1);418 if (!s)419 exit(-1);420 src = template;421 dst = s;422 423 /* find out "baseline" indentation to skip */424 while ((c = *src++)) {425 if (c == '\t') {426 skip_tabs++;427 } else if (c == '\n') {428 break;429 } else {430 p_err("unrecognized character at pos %td in template '%s': '%c'",431 src - template - 1, template, c);432 free(s);433 exit(-1);434 }435 }436 437 while (*src) {438 /* skip baseline indentation tabs */439 for (n = skip_tabs; n > 0; n--, src++) {440 if (*src != '\t') {441 p_err("not enough tabs at pos %td in template '%s'",442 src - template - 1, template);443 free(s);444 exit(-1);445 }446 }447 /* trim trailing whitespace */448 end = strchrnul(src, '\n');449 for (n = end - src; n > 0 && isspace(src[n - 1]); n--)450 ;451 memcpy(dst, src, n);452 dst += n;453 if (*end)454 *dst++ = '\n';455 src = *end ? end + 1 : end;456 }457 *dst++ = '\0';458 459 /* print out using adjusted template */460 va_start(args, template);461 n = vprintf(s, args);462 va_end(args);463 464 free(s);465}466 467static void print_hex(const char *data, int data_sz)468{469 int i, len;470 471 for (i = 0, len = 0; i < data_sz; i++) {472 int w = data[i] ? 4 : 2;473 474 len += w;475 if (len > 78) {476 printf("\\\n");477 len = w;478 }479 if (!data[i])480 printf("\\0");481 else482 printf("\\x%02x", (unsigned char)data[i]);483 }484}485 486static size_t bpf_map_mmap_sz(const struct bpf_map *map)487{488 long page_sz = sysconf(_SC_PAGE_SIZE);489 size_t map_sz;490 491 map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);492 map_sz = roundup(map_sz, page_sz);493 return map_sz;494}495 496/* Emit type size asserts for all top-level fields in memory-mapped internal maps. */497static void codegen_asserts(struct bpf_object *obj, const char *obj_name)498{499 struct btf *btf = bpf_object__btf(obj);500 struct bpf_map *map;501 struct btf_var_secinfo *sec_var;502 int i, vlen;503 const struct btf_type *sec;504 char map_ident[256], var_ident[256];505 506 if (!btf)507 return;508 509 codegen("\510 \n\511 __attribute__((unused)) static void \n\512 %1$s__assert(struct %1$s *s __attribute__((unused))) \n\513 { \n\514 #ifdef __cplusplus \n\515 #define _Static_assert static_assert \n\516 #endif \n\517 ", obj_name);518 519 bpf_object__for_each_map(map, obj) {520 if (!is_mmapable_map(map, map_ident, sizeof(map_ident)))521 continue;522 523 sec = find_type_for_map(btf, map_ident);524 if (!sec) {525 /* best effort, couldn't find the type for this map */526 continue;527 }528 529 sec_var = btf_var_secinfos(sec);530 vlen = btf_vlen(sec);531 532 for (i = 0; i < vlen; i++, sec_var++) {533 const struct btf_type *var = btf__type_by_id(btf, sec_var->type);534 const char *var_name = btf__name_by_offset(btf, var->name_off);535 long var_size;536 537 /* static variables are not exposed through BPF skeleton */538 if (btf_var(var)->linkage == BTF_VAR_STATIC)539 continue;540 541 var_size = btf__resolve_size(btf, var->type);542 if (var_size < 0)543 continue;544 545 var_ident[0] = '\0';546 strncat(var_ident, var_name, sizeof(var_ident) - 1);547 sanitize_identifier(var_ident);548 549 printf("\t_Static_assert(sizeof(s->%s->%s) == %ld, \"unexpected size of '%s'\");\n",550 map_ident, var_ident, var_size, var_ident);551 }552 }553 codegen("\554 \n\555 #ifdef __cplusplus \n\556 #undef _Static_assert \n\557 #endif \n\558 } \n\559 ");560}561 562static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)563{564 struct bpf_program *prog;565 566 bpf_object__for_each_program(prog, obj) {567 const char *tp_name;568 569 codegen("\570 \n\571 \n\572 static inline int \n\573 %1$s__%2$s__attach(struct %1$s *skel) \n\574 { \n\575 int prog_fd = skel->progs.%2$s.prog_fd; \n\576 ", obj_name, bpf_program__name(prog));577 578 switch (bpf_program__type(prog)) {579 case BPF_PROG_TYPE_RAW_TRACEPOINT:580 tp_name = strchr(bpf_program__section_name(prog), '/') + 1;581 printf("\tint fd = skel_raw_tracepoint_open(\"%s\", prog_fd);\n", tp_name);582 break;583 case BPF_PROG_TYPE_TRACING:584 case BPF_PROG_TYPE_LSM:585 if (bpf_program__expected_attach_type(prog) == BPF_TRACE_ITER)586 printf("\tint fd = skel_link_create(prog_fd, 0, BPF_TRACE_ITER);\n");587 else588 printf("\tint fd = skel_raw_tracepoint_open(NULL, prog_fd);\n");589 break;590 default:591 printf("\tint fd = ((void)prog_fd, 0); /* auto-attach not supported */\n");592 break;593 }594 codegen("\595 \n\596 \n\597 if (fd > 0) \n\598 skel->links.%1$s_fd = fd; \n\599 return fd; \n\600 } \n\601 ", bpf_program__name(prog));602 }603 604 codegen("\605 \n\606 \n\607 static inline int \n\608 %1$s__attach(struct %1$s *skel) \n\609 { \n\610 int ret = 0; \n\611 \n\612 ", obj_name);613 614 bpf_object__for_each_program(prog, obj) {615 codegen("\616 \n\617 ret = ret < 0 ? ret : %1$s__%2$s__attach(skel); \n\618 ", obj_name, bpf_program__name(prog));619 }620 621 codegen("\622 \n\623 return ret < 0 ? ret : 0; \n\624 } \n\625 \n\626 static inline void \n\627 %1$s__detach(struct %1$s *skel) \n\628 { \n\629 ", obj_name);630 631 bpf_object__for_each_program(prog, obj) {632 codegen("\633 \n\634 skel_closenz(skel->links.%1$s_fd); \n\635 ", bpf_program__name(prog));636 }637 638 codegen("\639 \n\640 } \n\641 ");642}643 644static void codegen_destroy(struct bpf_object *obj, const char *obj_name)645{646 struct bpf_program *prog;647 struct bpf_map *map;648 char ident[256];649 650 codegen("\651 \n\652 static void \n\653 %1$s__destroy(struct %1$s *skel) \n\654 { \n\655 if (!skel) \n\656 return; \n\657 %1$s__detach(skel); \n\658 ",659 obj_name);660 661 bpf_object__for_each_program(prog, obj) {662 codegen("\663 \n\664 skel_closenz(skel->progs.%1$s.prog_fd); \n\665 ", bpf_program__name(prog));666 }667 668 bpf_object__for_each_map(map, obj) {669 if (!get_map_ident(map, ident, sizeof(ident)))670 continue;671 if (bpf_map__is_internal(map) &&672 (bpf_map__map_flags(map) & BPF_F_MMAPABLE))673 printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$zd);\n",674 ident, bpf_map_mmap_sz(map));675 codegen("\676 \n\677 skel_closenz(skel->maps.%1$s.map_fd); \n\678 ", ident);679 }680 codegen("\681 \n\682 skel_free(skel); \n\683 } \n\684 ",685 obj_name);686}687 688static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)689{690 DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);691 struct bpf_map *map;692 char ident[256];693 int err = 0;694 695 err = bpf_object__gen_loader(obj, &opts);696 if (err)697 return err;698 699 err = bpf_object__load(obj);700 if (err) {701 p_err("failed to load object file");702 goto out;703 }704 /* If there was no error during load then gen_loader_opts705 * are populated with the loader program.706 */707 708 /* finish generating 'struct skel' */709 codegen("\710 \n\711 }; \n\712 ", obj_name);713 714 715 codegen_attach_detach(obj, obj_name);716 717 codegen_destroy(obj, obj_name);718 719 codegen("\720 \n\721 static inline struct %1$s * \n\722 %1$s__open(void) \n\723 { \n\724 struct %1$s *skel; \n\725 \n\726 skel = skel_alloc(sizeof(*skel)); \n\727 if (!skel) \n\728 goto cleanup; \n\729 skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\730 ",731 obj_name, opts.data_sz);732 bpf_object__for_each_map(map, obj) {733 const void *mmap_data = NULL;734 size_t mmap_size = 0;735 736 if (!is_mmapable_map(map, ident, sizeof(ident)))737 continue;738 739 codegen("\740 \n\741 { \n\742 static const char data[] __attribute__((__aligned__(8))) = \"\\\n\743 ");744 mmap_data = bpf_map__initial_value(map, &mmap_size);745 print_hex(mmap_data, mmap_size);746 codegen("\747 \n\748 \"; \n\749 \n\750 skel->%1$s = skel_prep_map_data((void *)data, %2$zd,\n\751 sizeof(data) - 1);\n\752 if (!skel->%1$s) \n\753 goto cleanup; \n\754 skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\755 } \n\756 ", ident, bpf_map_mmap_sz(map));757 }758 codegen("\759 \n\760 return skel; \n\761 cleanup: \n\762 %1$s__destroy(skel); \n\763 return NULL; \n\764 } \n\765 \n\766 static inline int \n\767 %1$s__load(struct %1$s *skel) \n\768 { \n\769 struct bpf_load_and_run_opts opts = {}; \n\770 int err; \n\771 static const char opts_data[] __attribute__((__aligned__(8))) = \"\\\n\772 ",773 obj_name);774 print_hex(opts.data, opts.data_sz);775 codegen("\776 \n\777 \"; \n\778 static const char opts_insn[] __attribute__((__aligned__(8))) = \"\\\n\779 ");780 print_hex(opts.insns, opts.insns_sz);781 codegen("\782 \n\783 \"; \n\784 \n\785 opts.ctx = (struct bpf_loader_ctx *)skel; \n\786 opts.data_sz = sizeof(opts_data) - 1; \n\787 opts.data = (void *)opts_data; \n\788 opts.insns_sz = sizeof(opts_insn) - 1; \n\789 opts.insns = (void *)opts_insn; \n\790 \n\791 err = bpf_load_and_run(&opts); \n\792 if (err < 0) \n\793 return err; \n\794 ");795 bpf_object__for_each_map(map, obj) {796 const char *mmap_flags;797 798 if (!is_mmapable_map(map, ident, sizeof(ident)))799 continue;800 801 if (bpf_map__map_flags(map) & BPF_F_RDONLY_PROG)802 mmap_flags = "PROT_READ";803 else804 mmap_flags = "PROT_READ | PROT_WRITE";805 806 codegen("\807 \n\808 skel->%1$s = skel_finalize_map_data(&skel->maps.%1$s.initial_value, \n\809 %2$zd, %3$s, skel->maps.%1$s.map_fd);\n\810 if (!skel->%1$s) \n\811 return -ENOMEM; \n\812 ",813 ident, bpf_map_mmap_sz(map), mmap_flags);814 }815 codegen("\816 \n\817 return 0; \n\818 } \n\819 \n\820 static inline struct %1$s * \n\821 %1$s__open_and_load(void) \n\822 { \n\823 struct %1$s *skel; \n\824 \n\825 skel = %1$s__open(); \n\826 if (!skel) \n\827 return NULL; \n\828 if (%1$s__load(skel)) { \n\829 %1$s__destroy(skel); \n\830 return NULL; \n\831 } \n\832 return skel; \n\833 } \n\834 \n\835 ", obj_name);836 837 codegen_asserts(obj, obj_name);838 839 codegen("\840 \n\841 \n\842 #endif /* %s */ \n\843 ",844 header_guard);845 err = 0;846out:847 return err;848}849 850static void851codegen_maps_skeleton(struct bpf_object *obj, size_t map_cnt, bool mmaped, bool populate_links)852{853 struct bpf_map *map;854 char ident[256];855 size_t i, map_sz;856 857 if (!map_cnt)858 return;859 860 /* for backward compatibility with old libbpf versions that don't861 * handle new BPF skeleton with new struct bpf_map_skeleton definition862 * that includes link field, avoid specifying new increased size,863 * unless we absolutely have to (i.e., if there are struct_ops maps864 * present)865 */866 map_sz = offsetof(struct bpf_map_skeleton, link);867 if (populate_links) {868 bpf_object__for_each_map(map, obj) {869 if (bpf_map__type(map) == BPF_MAP_TYPE_STRUCT_OPS) {870 map_sz = sizeof(struct bpf_map_skeleton);871 break;872 }873 }874 }875 876 codegen("\877 \n\878 \n\879 /* maps */ \n\880 s->map_cnt = %zu; \n\881 s->map_skel_sz = %zu; \n\882 s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt,\n\883 sizeof(*s->maps) > %zu ? sizeof(*s->maps) : %zu);\n\884 if (!s->maps) { \n\885 err = -ENOMEM; \n\886 goto err; \n\887 } \n\888 ",889 map_cnt, map_sz, map_sz, map_sz890 );891 i = 0;892 bpf_object__for_each_map(map, obj) {893 if (!get_map_ident(map, ident, sizeof(ident)))894 continue;895 896 codegen("\897 \n\898 \n\899 map = (struct bpf_map_skeleton *)((char *)s->maps + %zu * s->map_skel_sz);\n\900 map->name = \"%s\"; \n\901 map->map = &obj->maps.%s; \n\902 ",903 i, bpf_map__name(map), ident);904 /* memory-mapped internal maps */905 if (mmaped && is_mmapable_map(map, ident, sizeof(ident))) {906 printf("\tmap->mmaped = (void **)&obj->%s;\n", ident);907 }908 909 if (populate_links && bpf_map__type(map) == BPF_MAP_TYPE_STRUCT_OPS) {910 codegen("\911 \n\912 map->link = &obj->links.%s; \n\913 ", ident);914 }915 i++;916 }917}918 919static void920codegen_progs_skeleton(struct bpf_object *obj, size_t prog_cnt, bool populate_links)921{922 struct bpf_program *prog;923 int i;924 925 if (!prog_cnt)926 return;927 928 codegen("\929 \n\930 \n\931 /* programs */ \n\932 s->prog_cnt = %zu; \n\933 s->prog_skel_sz = sizeof(*s->progs); \n\934 s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);\n\935 if (!s->progs) { \n\936 err = -ENOMEM; \n\937 goto err; \n\938 } \n\939 ",940 prog_cnt941 );942 i = 0;943 bpf_object__for_each_program(prog, obj) {944 codegen("\945 \n\946 \n\947 s->progs[%1$zu].name = \"%2$s\"; \n\948 s->progs[%1$zu].prog = &obj->progs.%2$s;\n\949 ",950 i, bpf_program__name(prog));951 952 if (populate_links) {953 codegen("\954 \n\955 s->progs[%1$zu].link = &obj->links.%2$s;\n\956 ",957 i, bpf_program__name(prog));958 }959 i++;960 }961}962 963static int walk_st_ops_shadow_vars(struct btf *btf, const char *ident,964 const struct btf_type *map_type, __u32 map_type_id)965{966 LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts, .indent_level = 3);967 const struct btf_type *member_type;968 __u32 offset, next_offset = 0;969 const struct btf_member *m;970 struct btf_dump *d = NULL;971 const char *member_name;972 __u32 member_type_id;973 int i, err = 0, n;974 int size;975 976 d = btf_dump__new(btf, codegen_btf_dump_printf, NULL, NULL);977 if (!d)978 return -errno;979 980 n = btf_vlen(map_type);981 for (i = 0, m = btf_members(map_type); i < n; i++, m++) {982 member_type = skip_mods_and_typedefs(btf, m->type, &member_type_id);983 member_name = btf__name_by_offset(btf, m->name_off);984 985 offset = m->offset / 8;986 if (next_offset < offset)987 printf("\t\t\tchar __padding_%d[%d];\n", i, offset - next_offset);988 989 switch (btf_kind(member_type)) {990 case BTF_KIND_INT:991 case BTF_KIND_FLOAT:992 case BTF_KIND_ENUM:993 case BTF_KIND_ENUM64:994 /* scalar type */995 printf("\t\t\t");996 opts.field_name = member_name;997 err = btf_dump__emit_type_decl(d, member_type_id, &opts);998 if (err) {999 p_err("Failed to emit type declaration for %s: %d", member_name, err);1000 goto out;1001 }1002 printf(";\n");1003 1004 size = btf__resolve_size(btf, member_type_id);1005 if (size < 0) {1006 p_err("Failed to resolve size of %s: %d\n", member_name, size);1007 err = size;1008 goto out;1009 }1010 1011 next_offset = offset + size;1012 break;1013 1014 case BTF_KIND_PTR:1015 if (resolve_func_ptr(btf, m->type, NULL)) {1016 /* Function pointer */1017 printf("\t\t\tstruct bpf_program *%s;\n", member_name);1018 1019 next_offset = offset + sizeof(void *);1020 break;1021 }1022 /* All pointer types are unsupported except for1023 * function pointers.1024 */1025 fallthrough;1026 1027 default:1028 /* Unsupported types1029 *1030 * Types other than scalar types and function1031 * pointers are currently not supported in order to1032 * prevent conflicts in the generated code caused1033 * by multiple definitions. For instance, if the1034 * struct type FOO is used in a struct_ops map,1035 * bpftool has to generate definitions for FOO,1036 * which may result in conflicts if FOO is defined1037 * in different skeleton files.1038 */1039 size = btf__resolve_size(btf, member_type_id);1040 if (size < 0) {1041 p_err("Failed to resolve size of %s: %d\n", member_name, size);1042 err = size;1043 goto out;1044 }1045 printf("\t\t\tchar __unsupported_%d[%d];\n", i, size);1046 1047 next_offset = offset + size;1048 break;1049 }1050 }1051 1052 /* Cannot fail since it must be a struct type */1053 size = btf__resolve_size(btf, map_type_id);1054 if (next_offset < (__u32)size)1055 printf("\t\t\tchar __padding_end[%d];\n", size - next_offset);1056 1057out:1058 btf_dump__free(d);1059 1060 return err;1061}1062 1063/* Generate the pointer of the shadow type for a struct_ops map.1064 *1065 * This function adds a pointer of the shadow type for a struct_ops map.1066 * The members of a struct_ops map can be exported through a pointer to a1067 * shadow type. The user can access these members through the pointer.1068 *1069 * A shadow type includes not all members, only members of some types.1070 * They are scalar types and function pointers. The function pointers are1071 * translated to the pointer of the struct bpf_program. The scalar types1072 * are translated to the original type without any modifiers.1073 *1074 * Unsupported types will be translated to a char array to occupy the same1075 * space as the original field, being renamed as __unsupported_*. The user1076 * should treat these fields as opaque data.1077 */1078static int gen_st_ops_shadow_type(const char *obj_name, struct btf *btf, const char *ident,1079 const struct bpf_map *map)1080{1081 const struct btf_type *map_type;1082 const char *type_name;1083 __u32 map_type_id;1084 int err;1085 1086 map_type_id = bpf_map__btf_value_type_id(map);1087 if (map_type_id == 0)1088 return -EINVAL;1089 map_type = btf__type_by_id(btf, map_type_id);1090 if (!map_type)1091 return -EINVAL;1092 1093 type_name = btf__name_by_offset(btf, map_type->name_off);1094 1095 printf("\t\tstruct %s__%s__%s {\n", obj_name, ident, type_name);1096 1097 err = walk_st_ops_shadow_vars(btf, ident, map_type, map_type_id);1098 if (err)1099 return err;1100 1101 printf("\t\t} *%s;\n", ident);1102 1103 return 0;1104}1105 1106static int gen_st_ops_shadow(const char *obj_name, struct btf *btf, struct bpf_object *obj)1107{1108 int err, st_ops_cnt = 0;1109 struct bpf_map *map;1110 char ident[256];1111 1112 if (!btf)1113 return 0;1114 1115 /* Generate the pointers to shadow types of1116 * struct_ops maps.1117 */1118 bpf_object__for_each_map(map, obj) {1119 if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS)1120 continue;1121 if (!get_map_ident(map, ident, sizeof(ident)))1122 continue;1123 1124 if (st_ops_cnt == 0) /* first struct_ops map */1125 printf("\tstruct {\n");1126 st_ops_cnt++;1127 1128 err = gen_st_ops_shadow_type(obj_name, btf, ident, map);1129 if (err)1130 return err;1131 }1132 1133 if (st_ops_cnt)1134 printf("\t} struct_ops;\n");1135 1136 return 0;1137}1138 1139/* Generate the code to initialize the pointers of shadow types. */1140static void gen_st_ops_shadow_init(struct btf *btf, struct bpf_object *obj)1141{1142 struct bpf_map *map;1143 char ident[256];1144 1145 if (!btf)1146 return;1147 1148 /* Initialize the pointers to_ops shadow types of1149 * struct_ops maps.1150 */1151 bpf_object__for_each_map(map, obj) {1152 if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS)1153 continue;1154 if (!get_map_ident(map, ident, sizeof(ident)))1155 continue;1156 codegen("\1157 \n\1158 obj->struct_ops.%1$s = (__typeof__(obj->struct_ops.%1$s))\n\1159 bpf_map__initial_value(obj->maps.%1$s, NULL);\n\1160 \n\1161 ", ident);1162 }1163}1164 1165static int do_skeleton(int argc, char **argv)1166{1167 char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];1168 size_t map_cnt = 0, prog_cnt = 0, attach_map_cnt = 0, file_sz, mmap_sz;1169 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);1170 char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;1171 struct bpf_object *obj = NULL;1172 const char *file;1173 char ident[256];1174 struct bpf_program *prog;1175 int fd, err = -1;1176 struct bpf_map *map;1177 struct btf *btf;1178 struct stat st;1179 1180 if (!REQ_ARGS(1)) {1181 usage();1182 return -1;1183 }1184 file = GET_ARG();1185 1186 while (argc) {1187 if (!REQ_ARGS(2))1188 return -1;1189 1190 if (is_prefix(*argv, "name")) {1191 NEXT_ARG();1192 1193 if (obj_name[0] != '\0') {1194 p_err("object name already specified");1195 return -1;1196 }1197 1198 strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);1199 obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';1200 } else {1201 p_err("unknown arg %s", *argv);1202 return -1;1203 }1204 1205 NEXT_ARG();1206 }1207 1208 if (argc) {1209 p_err("extra unknown arguments");1210 return -1;1211 }1212 1213 if (stat(file, &st)) {1214 p_err("failed to stat() %s: %s", file, strerror(errno));1215 return -1;1216 }1217 file_sz = st.st_size;1218 mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));1219 fd = open(file, O_RDONLY);1220 if (fd < 0) {1221 p_err("failed to open() %s: %s", file, strerror(errno));1222 return -1;1223 }1224 obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);1225 if (obj_data == MAP_FAILED) {1226 obj_data = NULL;1227 p_err("failed to mmap() %s: %s", file, strerror(errno));1228 goto out;1229 }1230 if (obj_name[0] == '\0')1231 get_obj_name(obj_name, file);1232 opts.object_name = obj_name;1233 if (verifier_logs)1234 /* log_level1 + log_level2 + stats, but not stable UAPI */1235 opts.kernel_log_level = 1 + 2 + 4;1236 obj = bpf_object__open_mem(obj_data, file_sz, &opts);1237 if (!obj) {1238 char err_buf[256];1239 1240 err = -errno;1241 libbpf_strerror(err, err_buf, sizeof(err_buf));1242 p_err("failed to open BPF object file: %s", err_buf);1243 goto out;1244 }1245 1246 bpf_object__for_each_map(map, obj) {1247 if (!get_map_ident(map, ident, sizeof(ident))) {1248 p_err("ignoring unrecognized internal map '%s'...",1249 bpf_map__name(map));1250 continue;1251 }1252 1253 if (bpf_map__type(map) == BPF_MAP_TYPE_STRUCT_OPS)1254 attach_map_cnt++;1255 1256 map_cnt++;1257 }1258 bpf_object__for_each_program(prog, obj) {1259 prog_cnt++;1260 }1261 1262 get_header_guard(header_guard, obj_name, "SKEL_H");1263 if (use_loader) {1264 codegen("\1265 \n\1266 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\1267 /* THIS FILE IS AUTOGENERATED BY BPFTOOL! */ \n\1268 #ifndef %2$s \n\1269 #define %2$s \n\1270 \n\1271 #include <bpf/skel_internal.h> \n\1272 \n\1273 struct %1$s { \n\1274 struct bpf_loader_ctx ctx; \n\1275 ",1276 obj_name, header_guard1277 );1278 } else {1279 codegen("\1280 \n\1281 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\1282 \n\1283 /* THIS FILE IS AUTOGENERATED BY BPFTOOL! */ \n\1284 #ifndef %2$s \n\1285 #define %2$s \n\1286 \n\1287 #include <errno.h> \n\1288 #include <stdlib.h> \n\1289 #include <bpf/libbpf.h> \n\1290 \n\1291 #define BPF_SKEL_SUPPORTS_MAP_AUTO_ATTACH 1 \n\1292 \n\1293 struct %1$s { \n\1294 struct bpf_object_skeleton *skeleton; \n\1295 struct bpf_object *obj; \n\1296 ",1297 obj_name, header_guard1298 );1299 }1300 1301 if (map_cnt) {1302 printf("\tstruct {\n");1303 bpf_object__for_each_map(map, obj) {1304 if (!get_map_ident(map, ident, sizeof(ident)))1305 continue;1306 if (use_loader)1307 printf("\t\tstruct bpf_map_desc %s;\n", ident);1308 else1309 printf("\t\tstruct bpf_map *%s;\n", ident);1310 }1311 printf("\t} maps;\n");1312 }1313 1314 btf = bpf_object__btf(obj);1315 err = gen_st_ops_shadow(obj_name, btf, obj);1316 if (err)1317 goto out;1318 1319 if (prog_cnt) {1320 printf("\tstruct {\n");1321 bpf_object__for_each_program(prog, obj) {1322 if (use_loader)1323 printf("\t\tstruct bpf_prog_desc %s;\n",1324 bpf_program__name(prog));1325 else1326 printf("\t\tstruct bpf_program *%s;\n",1327 bpf_program__name(prog));1328 }1329 printf("\t} progs;\n");1330 }1331 1332 if (prog_cnt + attach_map_cnt) {1333 printf("\tstruct {\n");1334 bpf_object__for_each_program(prog, obj) {1335 if (use_loader)1336 printf("\t\tint %s_fd;\n",1337 bpf_program__name(prog));1338 else1339 printf("\t\tstruct bpf_link *%s;\n",1340 bpf_program__name(prog));1341 }1342 1343 bpf_object__for_each_map(map, obj) {1344 if (!get_map_ident(map, ident, sizeof(ident)))1345 continue;1346 if (bpf_map__type(map) != BPF_MAP_TYPE_STRUCT_OPS)1347 continue;1348 1349 if (use_loader)1350 printf("t\tint %s_fd;\n", ident);1351 else1352 printf("\t\tstruct bpf_link *%s;\n", ident);1353 }1354 1355 printf("\t} links;\n");1356 }1357 1358 if (btf) {1359 err = codegen_datasecs(obj, obj_name);1360 if (err)1361 goto out;1362 }1363 if (use_loader) {1364 err = gen_trace(obj, obj_name, header_guard);1365 goto out;1366 }1367 1368 codegen("\1369 \n\1370 \n\1371 #ifdef __cplusplus \n\1372 static inline struct %1$s *open(const struct bpf_object_open_opts *opts = nullptr);\n\1373 static inline struct %1$s *open_and_load(); \n\1374 static inline int load(struct %1$s *skel); \n\1375 static inline int attach(struct %1$s *skel); \n\1376 static inline void detach(struct %1$s *skel); \n\1377 static inline void destroy(struct %1$s *skel); \n\1378 static inline const void *elf_bytes(size_t *sz); \n\1379 #endif /* __cplusplus */ \n\1380 }; \n\1381 \n\1382 static void \n\1383 %1$s__destroy(struct %1$s *obj) \n\1384 { \n\1385 if (!obj) \n\1386 return; \n\1387 if (obj->skeleton) \n\1388 bpf_object__destroy_skeleton(obj->skeleton);\n\1389 free(obj); \n\1390 } \n\1391 \n\1392 static inline int \n\1393 %1$s__create_skeleton(struct %1$s *obj); \n\1394 \n\1395 static inline struct %1$s * \n\1396 %1$s__open_opts(const struct bpf_object_open_opts *opts) \n\1397 { \n\1398 struct %1$s *obj; \n\1399 int err; \n\1400 \n\1401 obj = (struct %1$s *)calloc(1, sizeof(*obj)); \n\1402 if (!obj) { \n\1403 errno = ENOMEM; \n\1404 return NULL; \n\1405 } \n\1406 \n\1407 err = %1$s__create_skeleton(obj); \n\1408 if (err) \n\1409 goto err_out; \n\1410 \n\1411 err = bpf_object__open_skeleton(obj->skeleton, opts);\n\1412 if (err) \n\1413 goto err_out; \n\1414 \n\1415 ", obj_name);1416 1417 gen_st_ops_shadow_init(btf, obj);1418 1419 codegen("\1420 \n\1421 return obj; \n\1422 err_out: \n\1423 %1$s__destroy(obj); \n\1424 errno = -err; \n\1425 return NULL; \n\1426 } \n\1427 \n\1428 static inline struct %1$s * \n\1429 %1$s__open(void) \n\1430 { \n\1431 return %1$s__open_opts(NULL); \n\1432 } \n\1433 \n\1434 static inline int \n\1435 %1$s__load(struct %1$s *obj) \n\1436 { \n\1437 return bpf_object__load_skeleton(obj->skeleton); \n\1438 } \n\1439 \n\1440 static inline struct %1$s * \n\1441 %1$s__open_and_load(void) \n\1442 { \n\1443 struct %1$s *obj; \n\1444 int err; \n\1445 \n\1446 obj = %1$s__open(); \n\1447 if (!obj) \n\1448 return NULL; \n\1449 err = %1$s__load(obj); \n\1450 if (err) { \n\1451 %1$s__destroy(obj); \n\1452 errno = -err; \n\1453 return NULL; \n\1454 } \n\1455 return obj; \n\1456 } \n\1457 \n\1458 static inline int \n\1459 %1$s__attach(struct %1$s *obj) \n\1460 { \n\1461 return bpf_object__attach_skeleton(obj->skeleton); \n\1462 } \n\1463 \n\1464 static inline void \n\1465 %1$s__detach(struct %1$s *obj) \n\1466 { \n\1467 bpf_object__detach_skeleton(obj->skeleton); \n\1468 } \n\1469 ",1470 obj_name1471 );1472 1473 codegen("\1474 \n\1475 \n\1476 static inline const void *%1$s__elf_bytes(size_t *sz); \n\1477 \n\1478 static inline int \n\1479 %1$s__create_skeleton(struct %1$s *obj) \n\1480 { \n\1481 struct bpf_object_skeleton *s; \n\1482 struct bpf_map_skeleton *map __attribute__((unused));\n\1483 int err; \n\1484 \n\1485 s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\1486 if (!s) { \n\1487 err = -ENOMEM; \n\1488 goto err; \n\1489 } \n\1490 \n\1491 s->sz = sizeof(*s); \n\1492 s->name = \"%1$s\"; \n\1493 s->obj = &obj->obj; \n\1494 ",1495 obj_name1496 );1497 1498 codegen_maps_skeleton(obj, map_cnt, true /*mmaped*/, true /*links*/);1499 codegen_progs_skeleton(obj, prog_cnt, true /*populate_links*/);1500 1501 codegen("\1502 \n\1503 \n\1504 s->data = %1$s__elf_bytes(&s->data_sz); \n\1505 \n\1506 obj->skeleton = s; \n\1507 return 0; \n\1508 err: \n\1509 bpf_object__destroy_skeleton(s); \n\1510 return err; \n\1511 } \n\1512 \n\1513 static inline const void *%1$s__elf_bytes(size_t *sz) \n\1514 { \n\1515 static const char data[] __attribute__((__aligned__(8))) = \"\\\n\1516 ",1517 obj_name1518 );1519 1520 /* embed contents of BPF object file */1521 print_hex(obj_data, file_sz);1522 1523 codegen("\1524 \n\1525 \"; \n\1526 \n\1527 *sz = sizeof(data) - 1; \n\1528 return (const void *)data; \n\1529 } \n\1530 \n\1531 #ifdef __cplusplus \n\1532 struct %1$s *%1$s::open(const struct bpf_object_open_opts *opts) { return %1$s__open_opts(opts); }\n\1533 struct %1$s *%1$s::open_and_load() { return %1$s__open_and_load(); } \n\1534 int %1$s::load(struct %1$s *skel) { return %1$s__load(skel); } \n\1535 int %1$s::attach(struct %1$s *skel) { return %1$s__attach(skel); } \n\1536 void %1$s::detach(struct %1$s *skel) { %1$s__detach(skel); } \n\1537 void %1$s::destroy(struct %1$s *skel) { %1$s__destroy(skel); } \n\1538 const void *%1$s::elf_bytes(size_t *sz) { return %1$s__elf_bytes(sz); } \n\1539 #endif /* __cplusplus */ \n\1540 \n\1541 ",1542 obj_name);1543 1544 codegen_asserts(obj, obj_name);1545 1546 codegen("\1547 \n\1548 \n\1549 #endif /* %1$s */ \n\1550 ",1551 header_guard);1552 err = 0;1553out:1554 bpf_object__close(obj);1555 if (obj_data)1556 munmap(obj_data, mmap_sz);1557 close(fd);1558 return err;1559}1560 1561/* Subskeletons are like skeletons, except they don't own the bpf_object,1562 * associated maps, links, etc. Instead, they know about the existence of1563 * variables, maps, programs and are able to find their locations1564 * _at runtime_ from an already loaded bpf_object.1565 *1566 * This allows for library-like BPF objects to have userspace counterparts1567 * with access to their own items without having to know anything about the1568 * final BPF object that the library was linked into.1569 */1570static int do_subskeleton(int argc, char **argv)1571{1572 char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SUBSKEL_H__")];1573 size_t i, len, file_sz, map_cnt = 0, prog_cnt = 0, mmap_sz, var_cnt = 0, var_idx = 0;1574 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);1575 char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;1576 struct bpf_object *obj = NULL;1577 const char *file, *var_name;1578 char ident[256];1579 int fd, err = -1, map_type_id;1580 const struct bpf_map *map;1581 struct bpf_program *prog;1582 struct btf *btf;1583 const struct btf_type *map_type, *var_type;1584 const struct btf_var_secinfo *var;1585 struct stat st;1586 1587 if (!REQ_ARGS(1)) {1588 usage();1589 return -1;1590 }1591 file = GET_ARG();1592 1593 while (argc) {1594 if (!REQ_ARGS(2))1595 return -1;1596 1597 if (is_prefix(*argv, "name")) {1598 NEXT_ARG();1599 1600 if (obj_name[0] != '\0') {1601 p_err("object name already specified");1602 return -1;1603 }1604 1605 strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1);1606 obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';1607 } else {1608 p_err("unknown arg %s", *argv);1609 return -1;1610 }1611 1612 NEXT_ARG();1613 }1614 1615 if (argc) {1616 p_err("extra unknown arguments");1617 return -1;1618 }1619 1620 if (use_loader) {1621 p_err("cannot use loader for subskeletons");1622 return -1;1623 }1624 1625 if (stat(file, &st)) {1626 p_err("failed to stat() %s: %s", file, strerror(errno));1627 return -1;1628 }1629 file_sz = st.st_size;1630 mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE));1631 fd = open(file, O_RDONLY);1632 if (fd < 0) {1633 p_err("failed to open() %s: %s", file, strerror(errno));1634 return -1;1635 }1636 obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0);1637 if (obj_data == MAP_FAILED) {1638 obj_data = NULL;1639 p_err("failed to mmap() %s: %s", file, strerror(errno));1640 goto out;1641 }1642 if (obj_name[0] == '\0')1643 get_obj_name(obj_name, file);1644 1645 /* The empty object name allows us to use bpf_map__name and produce1646 * ELF section names out of it. (".data" instead of "obj.data")1647 */1648 opts.object_name = "";1649 obj = bpf_object__open_mem(obj_data, file_sz, &opts);1650 if (!obj) {1651 char err_buf[256];1652 1653 libbpf_strerror(errno, err_buf, sizeof(err_buf));1654 p_err("failed to open BPF object file: %s", err_buf);1655 obj = NULL;1656 goto out;1657 }1658 1659 btf = bpf_object__btf(obj);1660 if (!btf) {1661 err = -1;1662 p_err("need btf type information for %s", obj_name);1663 goto out;1664 }1665 1666 bpf_object__for_each_program(prog, obj) {1667 prog_cnt++;1668 }1669 1670 /* First, count how many variables we have to find.1671 * We need this in advance so the subskel can allocate the right1672 * amount of storage.1673 */1674 bpf_object__for_each_map(map, obj) {1675 if (!get_map_ident(map, ident, sizeof(ident)))1676 continue;1677 1678 /* Also count all maps that have a name */1679 map_cnt++;1680 1681 if (!is_mmapable_map(map, ident, sizeof(ident)))1682 continue;1683 1684 map_type_id = bpf_map__btf_value_type_id(map);1685 if (map_type_id <= 0) {1686 err = map_type_id;1687 goto out;1688 }1689 map_type = btf__type_by_id(btf, map_type_id);1690 1691 var = btf_var_secinfos(map_type);1692 len = btf_vlen(map_type);1693 for (i = 0; i < len; i++, var++) {1694 var_type = btf__type_by_id(btf, var->type);1695 1696 if (btf_var(var_type)->linkage == BTF_VAR_STATIC)1697 continue;1698 1699 var_cnt++;1700 }1701 }1702 1703 get_header_guard(header_guard, obj_name, "SUBSKEL_H");1704 codegen("\1705 \n\1706 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\1707 \n\1708 /* THIS FILE IS AUTOGENERATED! */ \n\1709 #ifndef %2$s \n\1710 #define %2$s \n\1711 \n\1712 #include <errno.h> \n\1713 #include <stdlib.h> \n\1714 #include <bpf/libbpf.h> \n\1715 \n\1716 struct %1$s { \n\1717 struct bpf_object *obj; \n\1718 struct bpf_object_subskeleton *subskel; \n\1719 ", obj_name, header_guard);1720 1721 if (map_cnt) {1722 printf("\tstruct {\n");1723 bpf_object__for_each_map(map, obj) {1724 if (!get_map_ident(map, ident, sizeof(ident)))1725 continue;1726 printf("\t\tstruct bpf_map *%s;\n", ident);1727 }1728 printf("\t} maps;\n");1729 }1730 1731 err = gen_st_ops_shadow(obj_name, btf, obj);1732 if (err)1733 goto out;1734 1735 if (prog_cnt) {1736 printf("\tstruct {\n");1737 bpf_object__for_each_program(prog, obj) {1738 printf("\t\tstruct bpf_program *%s;\n",1739 bpf_program__name(prog));1740 }1741 printf("\t} progs;\n");1742 }1743 1744 err = codegen_subskel_datasecs(obj, obj_name);1745 if (err)1746 goto out;1747 1748 /* emit code that will allocate enough storage for all symbols */1749 codegen("\1750 \n\1751 \n\1752 #ifdef __cplusplus \n\1753 static inline struct %1$s *open(const struct bpf_object *src);\n\1754 static inline void destroy(struct %1$s *skel); \n\1755 #endif /* __cplusplus */ \n\1756 }; \n\1757 \n\1758 static inline void \n\1759 %1$s__destroy(struct %1$s *skel) \n\1760 { \n\1761 if (!skel) \n\1762 return; \n\1763 if (skel->subskel) \n\1764 bpf_object__destroy_subskeleton(skel->subskel);\n\1765 free(skel); \n\1766 } \n\1767 \n\1768 static inline struct %1$s * \n\1769 %1$s__open(const struct bpf_object *src) \n\1770 { \n\1771 struct %1$s *obj; \n\1772 struct bpf_object_subskeleton *s; \n\1773 struct bpf_map_skeleton *map __attribute__((unused));\n\1774 int err; \n\1775 \n\1776 obj = (struct %1$s *)calloc(1, sizeof(*obj)); \n\1777 if (!obj) { \n\1778 err = -ENOMEM; \n\1779 goto err; \n\1780 } \n\1781 s = (struct bpf_object_subskeleton *)calloc(1, sizeof(*s));\n\1782 if (!s) { \n\1783 err = -ENOMEM; \n\1784 goto err; \n\1785 } \n\1786 s->sz = sizeof(*s); \n\1787 s->obj = src; \n\1788 s->var_skel_sz = sizeof(*s->vars); \n\1789 obj->subskel = s; \n\1790 \n\1791 /* vars */ \n\1792 s->var_cnt = %2$d; \n\1793 s->vars = (struct bpf_var_skeleton *)calloc(%2$d, sizeof(*s->vars));\n\1794 if (!s->vars) { \n\1795 err = -ENOMEM; \n\1796 goto err; \n\1797 } \n\1798 ",1799 obj_name, var_cnt1800 );1801 1802 /* walk through each symbol and emit the runtime representation */1803 bpf_object__for_each_map(map, obj) {1804 if (!is_mmapable_map(map, ident, sizeof(ident)))1805 continue;1806 1807 map_type_id = bpf_map__btf_value_type_id(map);1808 if (map_type_id <= 0)1809 /* skip over internal maps with no type*/1810 continue;1811 1812 map_type = btf__type_by_id(btf, map_type_id);1813 var = btf_var_secinfos(map_type);1814 len = btf_vlen(map_type);1815 for (i = 0; i < len; i++, var++) {1816 var_type = btf__type_by_id(btf, var->type);1817 var_name = btf__name_by_offset(btf, var_type->name_off);1818 1819 if (btf_var(var_type)->linkage == BTF_VAR_STATIC)1820 continue;1821 1822 /* Note that we use the dot prefix in .data as the1823 * field access operator i.e. maps%s becomes maps.data1824 */1825 codegen("\1826 \n\1827 \n\1828 s->vars[%3$d].name = \"%1$s\"; \n\1829 s->vars[%3$d].map = &obj->maps.%2$s; \n\1830 s->vars[%3$d].addr = (void **) &obj->%2$s.%1$s;\n\1831 ", var_name, ident, var_idx);1832 1833 var_idx++;1834 }1835 }1836 1837 codegen_maps_skeleton(obj, map_cnt, false /*mmaped*/, false /*links*/);1838 codegen_progs_skeleton(obj, prog_cnt, false /*links*/);1839 1840 codegen("\1841 \n\1842 \n\1843 err = bpf_object__open_subskeleton(s); \n\1844 if (err) \n\1845 goto err; \n\1846 \n\1847 ");1848 1849 gen_st_ops_shadow_init(btf, obj);1850 1851 codegen("\1852 \n\1853 return obj; \n\1854 err: \n\1855 %1$s__destroy(obj); \n\1856 errno = -err; \n\1857 return NULL; \n\1858 } \n\1859 \n\1860 #ifdef __cplusplus \n\1861 struct %1$s *%1$s::open(const struct bpf_object *src) { return %1$s__open(src); }\n\1862 void %1$s::destroy(struct %1$s *skel) { %1$s__destroy(skel); }\n\1863 #endif /* __cplusplus */ \n\1864 \n\1865 #endif /* %2$s */ \n\1866 ",1867 obj_name, header_guard);1868 err = 0;1869out:1870 bpf_object__close(obj);1871 if (obj_data)1872 munmap(obj_data, mmap_sz);1873 close(fd);1874 return err;1875}1876 1877static int do_object(int argc, char **argv)1878{1879 struct bpf_linker *linker;1880 const char *output_file, *file;1881 int err = 0;1882 1883 if (!REQ_ARGS(2)) {1884 usage();1885 return -1;1886 }1887 1888 output_file = GET_ARG();1889 1890 linker = bpf_linker__new(output_file, NULL);1891 if (!linker) {1892 p_err("failed to create BPF linker instance");1893 return -1;1894 }1895 1896 while (argc) {1897 file = GET_ARG();1898 1899 err = bpf_linker__add_file(linker, file, NULL);1900 if (err) {1901 p_err("failed to link '%s': %s (%d)", file, strerror(errno), errno);1902 goto out;1903 }1904 }1905 1906 err = bpf_linker__finalize(linker);1907 if (err) {1908 p_err("failed to finalize ELF file: %s (%d)", strerror(errno), errno);1909 goto out;1910 }1911 1912 err = 0;1913out:1914 bpf_linker__free(linker);1915 return err;1916}1917 1918static int do_help(int argc, char **argv)1919{1920 if (json_output) {1921 jsonw_null(json_wtr);1922 return 0;1923 }1924 1925 fprintf(stderr,1926 "Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n"1927 " %1$s %2$s skeleton FILE [name OBJECT_NAME]\n"1928 " %1$s %2$s subskeleton FILE [name OBJECT_NAME]\n"1929 " %1$s %2$s min_core_btf INPUT OUTPUT OBJECT [OBJECT...]\n"1930 " %1$s %2$s help\n"1931 "\n"1932 " " HELP_SPEC_OPTIONS " |\n"1933 " {-L|--use-loader} }\n"1934 "",1935 bin_name, "gen");1936 1937 return 0;1938}1939 1940static int btf_save_raw(const struct btf *btf, const char *path)1941{1942 const void *data;1943 FILE *f = NULL;1944 __u32 data_sz;1945 int err = 0;1946 1947 data = btf__raw_data(btf, &data_sz);1948 if (!data)1949 return -ENOMEM;1950 1951 f = fopen(path, "wb");1952 if (!f)1953 return -errno;1954 1955 if (fwrite(data, 1, data_sz, f) != data_sz)1956 err = -errno;1957 1958 fclose(f);1959 return err;1960}1961 1962struct btfgen_info {1963 struct btf *src_btf;1964 struct btf *marked_btf; /* btf structure used to mark used types */1965};1966 1967static size_t btfgen_hash_fn(long key, void *ctx)1968{1969 return key;1970}1971 1972static bool btfgen_equal_fn(long k1, long k2, void *ctx)1973{1974 return k1 == k2;1975}1976 1977static void btfgen_free_info(struct btfgen_info *info)1978{1979 if (!info)1980 return;1981 1982 btf__free(info->src_btf);1983 btf__free(info->marked_btf);1984 1985 free(info);1986}1987 1988static struct btfgen_info *1989btfgen_new_info(const char *targ_btf_path)1990{1991 struct btfgen_info *info;1992 int err;1993 1994 info = calloc(1, sizeof(*info));1995 if (!info)1996 return NULL;1997 1998 info->src_btf = btf__parse(targ_btf_path, NULL);1999 if (!info->src_btf) {2000 err = -errno;2001 p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));2002 goto err_out;2003 }2004 2005 info->marked_btf = btf__parse(targ_btf_path, NULL);2006 if (!info->marked_btf) {2007 err = -errno;2008 p_err("failed parsing '%s' BTF file: %s", targ_btf_path, strerror(errno));2009 goto err_out;2010 }2011 2012 return info;2013 2014err_out:2015 btfgen_free_info(info);2016 errno = -err;2017 return NULL;2018}2019 2020#define MARKED UINT32_MAX2021 2022static void btfgen_mark_member(struct btfgen_info *info, int type_id, int idx)2023{2024 const struct btf_type *t = btf__type_by_id(info->marked_btf, type_id);2025 struct btf_member *m = btf_members(t) + idx;2026 2027 m->name_off = MARKED;2028}2029 2030static int2031btfgen_mark_type(struct btfgen_info *info, unsigned int type_id, bool follow_pointers)2032{2033 const struct btf_type *btf_type = btf__type_by_id(info->src_btf, type_id);2034 struct btf_type *cloned_type;2035 struct btf_param *param;2036 struct btf_array *array;2037 int err, i;2038 2039 if (type_id == 0)2040 return 0;2041 2042 /* mark type on cloned BTF as used */2043 cloned_type = (struct btf_type *) btf__type_by_id(info->marked_btf, type_id);2044 cloned_type->name_off = MARKED;2045 2046 /* recursively mark other types needed by it */2047 switch (btf_kind(btf_type)) {2048 case BTF_KIND_UNKN:2049 case BTF_KIND_INT:2050 case BTF_KIND_FLOAT:2051 case BTF_KIND_ENUM:2052 case BTF_KIND_ENUM64:2053 case BTF_KIND_STRUCT:2054 case BTF_KIND_UNION:2055 break;2056 case BTF_KIND_PTR:2057 if (follow_pointers) {2058 err = btfgen_mark_type(info, btf_type->type, follow_pointers);2059 if (err)2060 return err;2061 }2062 break;2063 case BTF_KIND_CONST:2064 case BTF_KIND_RESTRICT:2065 case BTF_KIND_VOLATILE:2066 case BTF_KIND_TYPEDEF:2067 err = btfgen_mark_type(info, btf_type->type, follow_pointers);2068 if (err)2069 return err;2070 break;2071 case BTF_KIND_ARRAY:2072 array = btf_array(btf_type);2073 2074 /* mark array type */2075 err = btfgen_mark_type(info, array->type, follow_pointers);2076 /* mark array's index type */2077 err = err ? : btfgen_mark_type(info, array->index_type, follow_pointers);2078 if (err)2079 return err;2080 break;2081 case BTF_KIND_FUNC_PROTO:2082 /* mark ret type */2083 err = btfgen_mark_type(info, btf_type->type, follow_pointers);2084 if (err)2085 return err;2086 2087 /* mark parameters types */2088 param = btf_params(btf_type);2089 for (i = 0; i < btf_vlen(btf_type); i++) {2090 err = btfgen_mark_type(info, param->type, follow_pointers);2091 if (err)2092 return err;2093 param++;2094 }2095 break;2096 /* tells if some other type needs to be handled */2097 default:2098 p_err("unsupported kind: %s (%d)", btf_kind_str(btf_type), type_id);2099 return -EINVAL;2100 }2101 2102 return 0;2103}2104 2105static int btfgen_record_field_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)2106{2107 struct btf *btf = info->src_btf;2108 const struct btf_type *btf_type;2109 struct btf_member *btf_member;2110 struct btf_array *array;2111 unsigned int type_id = targ_spec->root_type_id;2112 int idx, err;2113 2114 /* mark root type */2115 btf_type = btf__type_by_id(btf, type_id);2116 err = btfgen_mark_type(info, type_id, false);2117 if (err)2118 return err;2119 2120 /* mark types for complex types (arrays, unions, structures) */2121 for (int i = 1; i < targ_spec->raw_len; i++) {2122 /* skip typedefs and mods */2123 while (btf_is_mod(btf_type) || btf_is_typedef(btf_type)) {2124 type_id = btf_type->type;2125 btf_type = btf__type_by_id(btf, type_id);2126 }2127 2128 switch (btf_kind(btf_type)) {2129 case BTF_KIND_STRUCT:2130 case BTF_KIND_UNION:2131 idx = targ_spec->raw_spec[i];2132 btf_member = btf_members(btf_type) + idx;2133 2134 /* mark member */2135 btfgen_mark_member(info, type_id, idx);2136 2137 /* mark member's type */2138 type_id = btf_member->type;2139 btf_type = btf__type_by_id(btf, type_id);2140 err = btfgen_mark_type(info, type_id, false);2141 if (err)2142 return err;2143 break;2144 case BTF_KIND_ARRAY:2145 array = btf_array(btf_type);2146 type_id = array->type;2147 btf_type = btf__type_by_id(btf, type_id);2148 break;2149 default:2150 p_err("unsupported kind: %s (%d)",2151 btf_kind_str(btf_type), btf_type->type);2152 return -EINVAL;2153 }2154 }2155 2156 return 0;2157}2158 2159/* Mark types, members, and member types. Compared to btfgen_record_field_relo,2160 * this function does not rely on the target spec for inferring members, but2161 * uses the associated BTF.2162 *2163 * The `behind_ptr` argument is used to stop marking of composite types reached2164 * through a pointer. This way, we can keep BTF size in check while providing2165 * reasonable match semantics.2166 */2167static int btfgen_mark_type_match(struct btfgen_info *info, __u32 type_id, bool behind_ptr)2168{2169 const struct btf_type *btf_type;2170 struct btf *btf = info->src_btf;2171 struct btf_type *cloned_type;2172 int i, err;2173 2174 if (type_id == 0)2175 return 0;2176 2177 btf_type = btf__type_by_id(btf, type_id);2178 /* mark type on cloned BTF as used */2179 cloned_type = (struct btf_type *)btf__type_by_id(info->marked_btf, type_id);2180 cloned_type->name_off = MARKED;2181 2182 switch (btf_kind(btf_type)) {2183 case BTF_KIND_UNKN:2184 case BTF_KIND_INT:2185 case BTF_KIND_FLOAT:2186 case BTF_KIND_ENUM:2187 case BTF_KIND_ENUM64:2188 break;2189 case BTF_KIND_STRUCT:2190 case BTF_KIND_UNION: {2191 struct btf_member *m = btf_members(btf_type);2192 __u16 vlen = btf_vlen(btf_type);2193 2194 if (behind_ptr)2195 break;2196 2197 for (i = 0; i < vlen; i++, m++) {2198 /* mark member */2199 btfgen_mark_member(info, type_id, i);2200 2201 /* mark member's type */2202 err = btfgen_mark_type_match(info, m->type, false);2203 if (err)2204 return err;2205 }2206 break;2207 }2208 case BTF_KIND_CONST:2209 case BTF_KIND_FWD:2210 case BTF_KIND_RESTRICT:2211 case BTF_KIND_TYPEDEF:2212 case BTF_KIND_VOLATILE:2213 return btfgen_mark_type_match(info, btf_type->type, behind_ptr);2214 case BTF_KIND_PTR:2215 return btfgen_mark_type_match(info, btf_type->type, true);2216 case BTF_KIND_ARRAY: {2217 struct btf_array *array;2218 2219 array = btf_array(btf_type);2220 /* mark array type */2221 err = btfgen_mark_type_match(info, array->type, false);2222 /* mark array's index type */2223 err = err ? : btfgen_mark_type_match(info, array->index_type, false);2224 if (err)2225 return err;2226 break;2227 }2228 case BTF_KIND_FUNC_PROTO: {2229 __u16 vlen = btf_vlen(btf_type);2230 struct btf_param *param;2231 2232 /* mark ret type */2233 err = btfgen_mark_type_match(info, btf_type->type, false);2234 if (err)2235 return err;2236 2237 /* mark parameters types */2238 param = btf_params(btf_type);2239 for (i = 0; i < vlen; i++) {2240 err = btfgen_mark_type_match(info, param->type, false);2241 if (err)2242 return err;2243 param++;2244 }2245 break;2246 }2247 /* tells if some other type needs to be handled */2248 default:2249 p_err("unsupported kind: %s (%d)", btf_kind_str(btf_type), type_id);2250 return -EINVAL;2251 }2252 2253 return 0;2254}2255 2256/* Mark types, members, and member types. Compared to btfgen_record_field_relo,2257 * this function does not rely on the target spec for inferring members, but2258 * uses the associated BTF.2259 */2260static int btfgen_record_type_match_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)2261{2262 return btfgen_mark_type_match(info, targ_spec->root_type_id, false);2263}2264 2265static int btfgen_record_type_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)2266{2267 return btfgen_mark_type(info, targ_spec->root_type_id, true);2268}2269 2270static int btfgen_record_enumval_relo(struct btfgen_info *info, struct bpf_core_spec *targ_spec)2271{2272 return btfgen_mark_type(info, targ_spec->root_type_id, false);2273}2274 2275static int btfgen_record_reloc(struct btfgen_info *info, struct bpf_core_spec *res)2276{2277 switch (res->relo_kind) {2278 case BPF_CORE_FIELD_BYTE_OFFSET:2279 case BPF_CORE_FIELD_BYTE_SIZE:2280 case BPF_CORE_FIELD_EXISTS:2281 case BPF_CORE_FIELD_SIGNED:2282 case BPF_CORE_FIELD_LSHIFT_U64:2283 case BPF_CORE_FIELD_RSHIFT_U64:2284 return btfgen_record_field_relo(info, res);2285 case BPF_CORE_TYPE_ID_LOCAL: /* BPF_CORE_TYPE_ID_LOCAL doesn't require kernel BTF */2286 return 0;2287 case BPF_CORE_TYPE_ID_TARGET:2288 case BPF_CORE_TYPE_EXISTS:2289 case BPF_CORE_TYPE_SIZE:2290 return btfgen_record_type_relo(info, res);2291 case BPF_CORE_TYPE_MATCHES:2292 return btfgen_record_type_match_relo(info, res);2293 case BPF_CORE_ENUMVAL_EXISTS:2294 case BPF_CORE_ENUMVAL_VALUE:2295 return btfgen_record_enumval_relo(info, res);2296 default:2297 return -EINVAL;2298 }2299}2300 2301static struct bpf_core_cand_list *2302btfgen_find_cands(const struct btf *local_btf, const struct btf *targ_btf, __u32 local_id)2303{2304 const struct btf_type *local_type;2305 struct bpf_core_cand_list *cands = NULL;2306 struct bpf_core_cand local_cand = {};2307 size_t local_essent_len;2308 const char *local_name;2309 int err;2310 2311 local_cand.btf = local_btf;2312 local_cand.id = local_id;2313 2314 local_type = btf__type_by_id(local_btf, local_id);2315 if (!local_type) {2316 err = -EINVAL;2317 goto err_out;2318 }2319 2320 local_name = btf__name_by_offset(local_btf, local_type->name_off);2321 if (!local_name) {2322 err = -EINVAL;2323 goto err_out;2324 }2325 local_essent_len = bpf_core_essential_name_len(local_name);2326 2327 cands = calloc(1, sizeof(*cands));2328 if (!cands)2329 return NULL;2330 2331 err = bpf_core_add_cands(&local_cand, local_essent_len, targ_btf, "vmlinux", 1, cands);2332 if (err)2333 goto err_out;2334 2335 return cands;2336 2337err_out:2338 bpf_core_free_cands(cands);2339 errno = -err;2340 return NULL;2341}2342 2343/* Record relocation information for a single BPF object */2344static int btfgen_record_obj(struct btfgen_info *info, const char *obj_path)2345{2346 const struct btf_ext_info_sec *sec;2347 const struct bpf_core_relo *relo;2348 const struct btf_ext_info *seg;2349 struct hashmap_entry *entry;2350 struct hashmap *cand_cache = NULL;2351 struct btf_ext *btf_ext = NULL;2352 unsigned int relo_idx;2353 struct btf *btf = NULL;2354 size_t i;2355 int err;2356 2357 btf = btf__parse(obj_path, &btf_ext);2358 if (!btf) {2359 err = -errno;2360 p_err("failed to parse BPF object '%s': %s", obj_path, strerror(errno));2361 return err;2362 }2363 2364 if (!btf_ext) {2365 p_err("failed to parse BPF object '%s': section %s not found",2366 obj_path, BTF_EXT_ELF_SEC);2367 err = -EINVAL;2368 goto out;2369 }2370 2371 if (btf_ext->core_relo_info.len == 0) {2372 err = 0;2373 goto out;2374 }2375 2376 cand_cache = hashmap__new(btfgen_hash_fn, btfgen_equal_fn, NULL);2377 if (IS_ERR(cand_cache)) {2378 err = PTR_ERR(cand_cache);2379 goto out;2380 }2381 2382 seg = &btf_ext->core_relo_info;2383 for_each_btf_ext_sec(seg, sec) {2384 for_each_btf_ext_rec(seg, sec, relo_idx, relo) {2385 struct bpf_core_spec specs_scratch[3] = {};2386 struct bpf_core_relo_res targ_res = {};2387 struct bpf_core_cand_list *cands = NULL;2388 const char *sec_name = btf__name_by_offset(btf, sec->sec_name_off);2389 2390 if (relo->kind != BPF_CORE_TYPE_ID_LOCAL &&2391 !hashmap__find(cand_cache, relo->type_id, &cands)) {2392 cands = btfgen_find_cands(btf, info->src_btf, relo->type_id);2393 if (!cands) {2394 err = -errno;2395 goto out;2396 }2397 2398 err = hashmap__set(cand_cache, relo->type_id, cands,2399 NULL, NULL);2400 if (err)2401 goto out;2402 }2403 2404 err = bpf_core_calc_relo_insn(sec_name, relo, relo_idx, btf, cands,2405 specs_scratch, &targ_res);2406 if (err)2407 goto out;2408 2409 /* specs_scratch[2] is the target spec */2410 err = btfgen_record_reloc(info, &specs_scratch[2]);2411 if (err)2412 goto out;2413 }2414 }2415 2416out:2417 btf__free(btf);2418 btf_ext__free(btf_ext);2419 2420 if (!IS_ERR_OR_NULL(cand_cache)) {2421 hashmap__for_each_entry(cand_cache, entry, i) {2422 bpf_core_free_cands(entry->pvalue);2423 }2424 hashmap__free(cand_cache);2425 }2426 2427 return err;2428}2429 2430/* Generate BTF from relocation information previously recorded */2431static struct btf *btfgen_get_btf(struct btfgen_info *info)2432{2433 struct btf *btf_new = NULL;2434 unsigned int *ids = NULL;2435 unsigned int i, n = btf__type_cnt(info->marked_btf);2436 int err = 0;2437 2438 btf_new = btf__new_empty();2439 if (!btf_new) {2440 err = -errno;2441 goto err_out;2442 }2443 2444 ids = calloc(n, sizeof(*ids));2445 if (!ids) {2446 err = -errno;2447 goto err_out;2448 }2449 2450 /* first pass: add all marked types to btf_new and add their new ids to the ids map */2451 for (i = 1; i < n; i++) {2452 const struct btf_type *cloned_type, *type;2453 const char *name;2454 int new_id;2455 2456 cloned_type = btf__type_by_id(info->marked_btf, i);2457 2458 if (cloned_type->name_off != MARKED)2459 continue;2460 2461 type = btf__type_by_id(info->src_btf, i);2462 2463 /* add members for struct and union */2464 if (btf_is_composite(type)) {2465 struct btf_member *cloned_m, *m;2466 unsigned short vlen;2467 int idx_src;2468 2469 name = btf__str_by_offset(info->src_btf, type->name_off);2470 2471 if (btf_is_struct(type))2472 err = btf__add_struct(btf_new, name, type->size);2473 else2474 err = btf__add_union(btf_new, name, type->size);2475 2476 if (err < 0)2477 goto err_out;2478 new_id = err;2479 2480 cloned_m = btf_members(cloned_type);2481 m = btf_members(type);2482 vlen = btf_vlen(cloned_type);2483 for (idx_src = 0; idx_src < vlen; idx_src++, cloned_m++, m++) {2484 /* add only members that are marked as used */2485 if (cloned_m->name_off != MARKED)2486 continue;2487 2488 name = btf__str_by_offset(info->src_btf, m->name_off);2489 err = btf__add_field(btf_new, name, m->type,2490 btf_member_bit_offset(cloned_type, idx_src),2491 btf_member_bitfield_size(cloned_type, idx_src));2492 if (err < 0)2493 goto err_out;2494 }2495 } else {2496 err = btf__add_type(btf_new, info->src_btf, type);2497 if (err < 0)2498 goto err_out;2499 new_id = err;2500 }2501 2502 /* add ID mapping */2503 ids[i] = new_id;2504 }2505 2506 /* second pass: fix up type ids */2507 for (i = 1; i < btf__type_cnt(btf_new); i++) {2508 struct btf_type *btf_type = (struct btf_type *) btf__type_by_id(btf_new, i);2509 struct btf_field_iter it;2510 __u32 *type_id;2511 2512 err = btf_field_iter_init(&it, btf_type, BTF_FIELD_ITER_IDS);2513 if (err)2514 goto err_out;2515 2516 while ((type_id = btf_field_iter_next(&it)))2517 *type_id = ids[*type_id];2518 }2519 2520 free(ids);2521 return btf_new;2522 2523err_out:2524 btf__free(btf_new);2525 free(ids);2526 errno = -err;2527 return NULL;2528}2529 2530/* Create minimized BTF file for a set of BPF objects.2531 *2532 * The BTFGen algorithm is divided in two main parts: (1) collect the2533 * BTF types that are involved in relocations and (2) generate the BTF2534 * object using the collected types.2535 *2536 * In order to collect the types involved in the relocations, we parse2537 * the BTF and BTF.ext sections of the BPF objects and use2538 * bpf_core_calc_relo_insn() to get the target specification, this2539 * indicates how the types and fields are used in a relocation.2540 *2541 * Types are recorded in different ways according to the kind of the2542 * relocation. For field-based relocations only the members that are2543 * actually used are saved in order to reduce the size of the generated2544 * BTF file. For type-based relocations empty struct / unions are2545 * generated and for enum-based relocations the whole type is saved.2546 *2547 * The second part of the algorithm generates the BTF object. It creates2548 * an empty BTF object and fills it with the types recorded in the2549 * previous step. This function takes care of only adding the structure2550 * and union members that were marked as used and it also fixes up the2551 * type IDs on the generated BTF object.2552 */2553static int minimize_btf(const char *src_btf, const char *dst_btf, const char *objspaths[])2554{2555 struct btfgen_info *info;2556 struct btf *btf_new = NULL;2557 int err, i;2558 2559 info = btfgen_new_info(src_btf);2560 if (!info) {2561 err = -errno;2562 p_err("failed to allocate info structure: %s", strerror(errno));2563 goto out;2564 }2565 2566 for (i = 0; objspaths[i] != NULL; i++) {2567 err = btfgen_record_obj(info, objspaths[i]);2568 if (err) {2569 p_err("error recording relocations for %s: %s", objspaths[i],2570 strerror(errno));2571 goto out;2572 }2573 }2574 2575 btf_new = btfgen_get_btf(info);2576 if (!btf_new) {2577 err = -errno;2578 p_err("error generating BTF: %s", strerror(errno));2579 goto out;2580 }2581 2582 err = btf_save_raw(btf_new, dst_btf);2583 if (err) {2584 p_err("error saving btf file: %s", strerror(errno));2585 goto out;2586 }2587 2588out:2589 btf__free(btf_new);2590 btfgen_free_info(info);2591 2592 return err;2593}2594 2595static int do_min_core_btf(int argc, char **argv)2596{2597 const char *input, *output, **objs;2598 int i, err;2599 2600 if (!REQ_ARGS(3)) {2601 usage();2602 return -1;2603 }2604 2605 input = GET_ARG();2606 output = GET_ARG();2607 2608 objs = (const char **) calloc(argc + 1, sizeof(*objs));2609 if (!objs) {2610 p_err("failed to allocate array for object names");2611 return -ENOMEM;2612 }2613 2614 i = 0;2615 while (argc)2616 objs[i++] = GET_ARG();2617 2618 err = minimize_btf(input, output, objs);2619 free(objs);2620 return err;2621}2622 2623static const struct cmd cmds[] = {2624 { "object", do_object },2625 { "skeleton", do_skeleton },2626 { "subskeleton", do_subskeleton },2627 { "min_core_btf", do_min_core_btf},2628 { "help", do_help },2629 { 0 }2630};2631 2632int do_gen(int argc, char **argv)2633{2634 return cmd_select(cmds, argc, argv, do_help);2635}2636