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