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 <sys/types.h> 18 #include <sys/stat.h> 19 #include <sys/mman.h> 20 #include <bpf/btf.h> 21 #include <bpf/bpf_gen_internal.h> 22 23 #include "json_writer.h" 24 #include "main.h" 25 26 #define MAX_OBJ_NAME_LEN 64 27 28 static 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 37 static bool str_has_suffix(const char *str, const char *suffix) 38 { 39 size_t i, n1 = strlen(str), n2 = strlen(suffix); 40 41 if (n1 < n2) 42 return false; 43 44 for (i = 0; i < n2; i++) { 45 if (str[n1 - i - 1] != suffix[n2 - i - 1]) 46 return false; 47 } 48 49 return true; 50 } 51 52 static void get_obj_name(char *name, const char *file) 53 { 54 /* Using basename() GNU version which doesn't modify arg. */ 55 strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1); 56 name[MAX_OBJ_NAME_LEN - 1] = '\0'; 57 if (str_has_suffix(name, ".o")) 58 name[strlen(name) - 2] = '\0'; 59 sanitize_identifier(name); 60 } 61 62 static void get_header_guard(char *guard, const char *obj_name) 63 { 64 int i; 65 66 sprintf(guard, "__%s_SKEL_H__", obj_name); 67 for (i = 0; guard[i]; i++) 68 guard[i] = toupper(guard[i]); 69 } 70 71 static const char *get_map_ident(const struct bpf_map *map) 72 { 73 const char *name = bpf_map__name(map); 74 75 if (!bpf_map__is_internal(map)) 76 return name; 77 78 if (str_has_suffix(name, ".data")) 79 return "data"; 80 else if (str_has_suffix(name, ".rodata")) 81 return "rodata"; 82 else if (str_has_suffix(name, ".bss")) 83 return "bss"; 84 else if (str_has_suffix(name, ".kconfig")) 85 return "kconfig"; 86 else 87 return NULL; 88 } 89 90 static void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args) 91 { 92 vprintf(fmt, args); 93 } 94 95 static int codegen_datasec_def(struct bpf_object *obj, 96 struct btf *btf, 97 struct btf_dump *d, 98 const struct btf_type *sec, 99 const char *obj_name) 100 { 101 const char *sec_name = btf__name_by_offset(btf, sec->name_off); 102 const struct btf_var_secinfo *sec_var = btf_var_secinfos(sec); 103 int i, err, off = 0, pad_cnt = 0, vlen = btf_vlen(sec); 104 const char *sec_ident; 105 char var_ident[256]; 106 bool strip_mods = false; 107 108 if (strcmp(sec_name, ".data") == 0) { 109 sec_ident = "data"; 110 strip_mods = true; 111 } else if (strcmp(sec_name, ".bss") == 0) { 112 sec_ident = "bss"; 113 strip_mods = true; 114 } else if (strcmp(sec_name, ".rodata") == 0) { 115 sec_ident = "rodata"; 116 strip_mods = true; 117 } else if (strcmp(sec_name, ".kconfig") == 0) { 118 sec_ident = "kconfig"; 119 } else { 120 return 0; 121 } 122 123 printf(" struct %s__%s {\n", obj_name, sec_ident); 124 for (i = 0; i < vlen; i++, sec_var++) { 125 const struct btf_type *var = btf__type_by_id(btf, sec_var->type); 126 const char *var_name = btf__name_by_offset(btf, var->name_off); 127 DECLARE_LIBBPF_OPTS(btf_dump_emit_type_decl_opts, opts, 128 .field_name = var_ident, 129 .indent_level = 2, 130 .strip_mods = strip_mods, 131 ); 132 int need_off = sec_var->offset, align_off, align; 133 __u32 var_type_id = var->type; 134 135 /* static variables are not exposed through BPF skeleton */ 136 if (btf_var(var)->linkage == BTF_VAR_STATIC) 137 continue; 138 139 if (off > need_off) { 140 p_err("Something is wrong for %s's variable #%d: need offset %d, already at %d.\n", 141 sec_name, i, need_off, off); 142 return -EINVAL; 143 } 144 145 align = btf__align_of(btf, var->type); 146 if (align <= 0) { 147 p_err("Failed to determine alignment of variable '%s': %d", 148 var_name, align); 149 return -EINVAL; 150 } 151 /* Assume 32-bit architectures when generating data section 152 * struct memory layout. Given bpftool can't know which target 153 * host architecture it's emitting skeleton for, we need to be 154 * conservative and assume 32-bit one to ensure enough padding 155 * bytes are generated for pointer and long types. This will 156 * still work correctly for 64-bit architectures, because in 157 * the worst case we'll generate unnecessary padding field, 158 * which on 64-bit architectures is not strictly necessary and 159 * would be handled by natural 8-byte alignment. But it still 160 * will be a correct memory layout, based on recorded offsets 161 * in BTF. 162 */ 163 if (align > 4) 164 align = 4; 165 166 align_off = (off + align - 1) / align * align; 167 if (align_off != need_off) { 168 printf("\t\tchar __pad%d[%d];\n", 169 pad_cnt, need_off - off); 170 pad_cnt++; 171 } 172 173 /* sanitize variable name, e.g., for static vars inside 174 * a function, it's name is '<function name>.<variable name>', 175 * which we'll turn into a '<function name>_<variable name>' 176 */ 177 var_ident[0] = '\0'; 178 strncat(var_ident, var_name, sizeof(var_ident) - 1); 179 sanitize_identifier(var_ident); 180 181 printf("\t\t"); 182 err = btf_dump__emit_type_decl(d, var_type_id, &opts); 183 if (err) 184 return err; 185 printf(";\n"); 186 187 off = sec_var->offset + sec_var->size; 188 } 189 printf(" } *%s;\n", sec_ident); 190 return 0; 191 } 192 193 static int codegen_datasecs(struct bpf_object *obj, const char *obj_name) 194 { 195 struct btf *btf = bpf_object__btf(obj); 196 int n = btf__get_nr_types(btf); 197 struct btf_dump *d; 198 int i, err = 0; 199 200 d = btf_dump__new(btf, NULL, NULL, codegen_btf_dump_printf); 201 if (IS_ERR(d)) 202 return PTR_ERR(d); 203 204 for (i = 1; i <= n; i++) { 205 const struct btf_type *t = btf__type_by_id(btf, i); 206 207 if (!btf_is_datasec(t)) 208 continue; 209 210 err = codegen_datasec_def(obj, btf, d, t, obj_name); 211 if (err) 212 goto out; 213 } 214 out: 215 btf_dump__free(d); 216 return err; 217 } 218 219 static void codegen(const char *template, ...) 220 { 221 const char *src, *end; 222 int skip_tabs = 0, n; 223 char *s, *dst; 224 va_list args; 225 char c; 226 227 n = strlen(template); 228 s = malloc(n + 1); 229 if (!s) 230 exit(-1); 231 src = template; 232 dst = s; 233 234 /* find out "baseline" indentation to skip */ 235 while ((c = *src++)) { 236 if (c == '\t') { 237 skip_tabs++; 238 } else if (c == '\n') { 239 break; 240 } else { 241 p_err("unrecognized character at pos %td in template '%s'", 242 src - template - 1, template); 243 free(s); 244 exit(-1); 245 } 246 } 247 248 while (*src) { 249 /* skip baseline indentation tabs */ 250 for (n = skip_tabs; n > 0; n--, src++) { 251 if (*src != '\t') { 252 p_err("not enough tabs at pos %td in template '%s'", 253 src - template - 1, template); 254 free(s); 255 exit(-1); 256 } 257 } 258 /* trim trailing whitespace */ 259 end = strchrnul(src, '\n'); 260 for (n = end - src; n > 0 && isspace(src[n - 1]); n--) 261 ; 262 memcpy(dst, src, n); 263 dst += n; 264 if (*end) 265 *dst++ = '\n'; 266 src = *end ? end + 1 : end; 267 } 268 *dst++ = '\0'; 269 270 /* print out using adjusted template */ 271 va_start(args, template); 272 n = vprintf(s, args); 273 va_end(args); 274 275 free(s); 276 } 277 278 static void print_hex(const char *data, int data_sz) 279 { 280 int i, len; 281 282 for (i = 0, len = 0; i < data_sz; i++) { 283 int w = data[i] ? 4 : 2; 284 285 len += w; 286 if (len > 78) { 287 printf("\\\n"); 288 len = w; 289 } 290 if (!data[i]) 291 printf("\\0"); 292 else 293 printf("\\x%02x", (unsigned char)data[i]); 294 } 295 } 296 297 static size_t bpf_map_mmap_sz(const struct bpf_map *map) 298 { 299 long page_sz = sysconf(_SC_PAGE_SIZE); 300 size_t map_sz; 301 302 map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map); 303 map_sz = roundup(map_sz, page_sz); 304 return map_sz; 305 } 306 307 static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name) 308 { 309 struct bpf_program *prog; 310 311 bpf_object__for_each_program(prog, obj) { 312 const char *tp_name; 313 314 codegen("\ 315 \n\ 316 \n\ 317 static inline int \n\ 318 %1$s__%2$s__attach(struct %1$s *skel) \n\ 319 { \n\ 320 int prog_fd = skel->progs.%2$s.prog_fd; \n\ 321 ", obj_name, bpf_program__name(prog)); 322 323 switch (bpf_program__get_type(prog)) { 324 case BPF_PROG_TYPE_RAW_TRACEPOINT: 325 tp_name = strchr(bpf_program__section_name(prog), '/') + 1; 326 printf("\tint fd = bpf_raw_tracepoint_open(\"%s\", prog_fd);\n", tp_name); 327 break; 328 case BPF_PROG_TYPE_TRACING: 329 printf("\tint fd = bpf_raw_tracepoint_open(NULL, prog_fd);\n"); 330 break; 331 default: 332 printf("\tint fd = ((void)prog_fd, 0); /* auto-attach not supported */\n"); 333 break; 334 } 335 codegen("\ 336 \n\ 337 \n\ 338 if (fd > 0) \n\ 339 skel->links.%1$s_fd = fd; \n\ 340 return fd; \n\ 341 } \n\ 342 ", bpf_program__name(prog)); 343 } 344 345 codegen("\ 346 \n\ 347 \n\ 348 static inline int \n\ 349 %1$s__attach(struct %1$s *skel) \n\ 350 { \n\ 351 int ret = 0; \n\ 352 \n\ 353 ", obj_name); 354 355 bpf_object__for_each_program(prog, obj) { 356 codegen("\ 357 \n\ 358 ret = ret < 0 ? ret : %1$s__%2$s__attach(skel); \n\ 359 ", obj_name, bpf_program__name(prog)); 360 } 361 362 codegen("\ 363 \n\ 364 return ret < 0 ? ret : 0; \n\ 365 } \n\ 366 \n\ 367 static inline void \n\ 368 %1$s__detach(struct %1$s *skel) \n\ 369 { \n\ 370 ", obj_name); 371 372 bpf_object__for_each_program(prog, obj) { 373 codegen("\ 374 \n\ 375 skel_closenz(skel->links.%1$s_fd); \n\ 376 ", bpf_program__name(prog)); 377 } 378 379 codegen("\ 380 \n\ 381 } \n\ 382 "); 383 } 384 385 static void codegen_destroy(struct bpf_object *obj, const char *obj_name) 386 { 387 struct bpf_program *prog; 388 struct bpf_map *map; 389 390 codegen("\ 391 \n\ 392 static void \n\ 393 %1$s__destroy(struct %1$s *skel) \n\ 394 { \n\ 395 if (!skel) \n\ 396 return; \n\ 397 %1$s__detach(skel); \n\ 398 ", 399 obj_name); 400 401 bpf_object__for_each_program(prog, obj) { 402 codegen("\ 403 \n\ 404 skel_closenz(skel->progs.%1$s.prog_fd); \n\ 405 ", bpf_program__name(prog)); 406 } 407 408 bpf_object__for_each_map(map, obj) { 409 const char * ident; 410 411 ident = get_map_ident(map); 412 if (!ident) 413 continue; 414 if (bpf_map__is_internal(map) && 415 (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) 416 printf("\tmunmap(skel->%1$s, %2$zd);\n", 417 ident, bpf_map_mmap_sz(map)); 418 codegen("\ 419 \n\ 420 skel_closenz(skel->maps.%1$s.map_fd); \n\ 421 ", ident); 422 } 423 codegen("\ 424 \n\ 425 free(skel); \n\ 426 } \n\ 427 ", 428 obj_name); 429 } 430 431 static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard) 432 { 433 struct bpf_object_load_attr load_attr = {}; 434 DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); 435 struct bpf_map *map; 436 int err = 0; 437 438 err = bpf_object__gen_loader(obj, &opts); 439 if (err) 440 return err; 441 442 load_attr.obj = obj; 443 if (verifier_logs) 444 /* log_level1 + log_level2 + stats, but not stable UAPI */ 445 load_attr.log_level = 1 + 2 + 4; 446 447 err = bpf_object__load_xattr(&load_attr); 448 if (err) { 449 p_err("failed to load object file"); 450 goto out; 451 } 452 /* If there was no error during load then gen_loader_opts 453 * are populated with the loader program. 454 */ 455 456 /* finish generating 'struct skel' */ 457 codegen("\ 458 \n\ 459 }; \n\ 460 ", obj_name); 461 462 463 codegen_attach_detach(obj, obj_name); 464 465 codegen_destroy(obj, obj_name); 466 467 codegen("\ 468 \n\ 469 static inline struct %1$s * \n\ 470 %1$s__open(void) \n\ 471 { \n\ 472 struct %1$s *skel; \n\ 473 \n\ 474 skel = calloc(sizeof(*skel), 1); \n\ 475 if (!skel) \n\ 476 goto cleanup; \n\ 477 skel->ctx.sz = (void *)&skel->links - (void *)skel; \n\ 478 ", 479 obj_name, opts.data_sz); 480 bpf_object__for_each_map(map, obj) { 481 const char *ident; 482 const void *mmap_data = NULL; 483 size_t mmap_size = 0; 484 485 ident = get_map_ident(map); 486 if (!ident) 487 continue; 488 489 if (!bpf_map__is_internal(map) || 490 !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) 491 continue; 492 493 codegen("\ 494 \n\ 495 skel->%1$s = \n\ 496 mmap(NULL, %2$zd, PROT_READ | PROT_WRITE,\n\ 497 MAP_SHARED | MAP_ANONYMOUS, -1, 0); \n\ 498 if (skel->%1$s == (void *) -1) \n\ 499 goto cleanup; \n\ 500 memcpy(skel->%1$s, (void *)\"\\ \n\ 501 ", ident, bpf_map_mmap_sz(map)); 502 mmap_data = bpf_map__initial_value(map, &mmap_size); 503 print_hex(mmap_data, mmap_size); 504 printf("\", %2$zd);\n" 505 "\tskel->maps.%1$s.initial_value = (__u64)(long)skel->%1$s;\n", 506 ident, mmap_size); 507 } 508 codegen("\ 509 \n\ 510 return skel; \n\ 511 cleanup: \n\ 512 %1$s__destroy(skel); \n\ 513 return NULL; \n\ 514 } \n\ 515 \n\ 516 static inline int \n\ 517 %1$s__load(struct %1$s *skel) \n\ 518 { \n\ 519 struct bpf_load_and_run_opts opts = {}; \n\ 520 int err; \n\ 521 \n\ 522 opts.ctx = (struct bpf_loader_ctx *)skel; \n\ 523 opts.data_sz = %2$d; \n\ 524 opts.data = (void *)\"\\ \n\ 525 ", 526 obj_name, opts.data_sz); 527 print_hex(opts.data, opts.data_sz); 528 codegen("\ 529 \n\ 530 \"; \n\ 531 "); 532 533 codegen("\ 534 \n\ 535 opts.insns_sz = %d; \n\ 536 opts.insns = (void *)\"\\ \n\ 537 ", 538 opts.insns_sz); 539 print_hex(opts.insns, opts.insns_sz); 540 codegen("\ 541 \n\ 542 \"; \n\ 543 err = bpf_load_and_run(&opts); \n\ 544 if (err < 0) \n\ 545 return err; \n\ 546 ", obj_name); 547 bpf_object__for_each_map(map, obj) { 548 const char *ident, *mmap_flags; 549 550 ident = get_map_ident(map); 551 if (!ident) 552 continue; 553 554 if (!bpf_map__is_internal(map) || 555 !(bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) 556 continue; 557 if (bpf_map__def(map)->map_flags & BPF_F_RDONLY_PROG) 558 mmap_flags = "PROT_READ"; 559 else 560 mmap_flags = "PROT_READ | PROT_WRITE"; 561 562 printf("\tskel->%1$s =\n" 563 "\t\tmmap(skel->%1$s, %2$zd, %3$s, MAP_SHARED | MAP_FIXED,\n" 564 "\t\t\tskel->maps.%1$s.map_fd, 0);\n", 565 ident, bpf_map_mmap_sz(map), mmap_flags); 566 } 567 codegen("\ 568 \n\ 569 return 0; \n\ 570 } \n\ 571 \n\ 572 static inline struct %1$s * \n\ 573 %1$s__open_and_load(void) \n\ 574 { \n\ 575 struct %1$s *skel; \n\ 576 \n\ 577 skel = %1$s__open(); \n\ 578 if (!skel) \n\ 579 return NULL; \n\ 580 if (%1$s__load(skel)) { \n\ 581 %1$s__destroy(skel); \n\ 582 return NULL; \n\ 583 } \n\ 584 return skel; \n\ 585 } \n\ 586 ", obj_name); 587 588 codegen("\ 589 \n\ 590 \n\ 591 #endif /* %s */ \n\ 592 ", 593 header_guard); 594 err = 0; 595 out: 596 return err; 597 } 598 599 static int do_skeleton(int argc, char **argv) 600 { 601 char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")]; 602 size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz; 603 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts); 604 char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data; 605 struct bpf_object *obj = NULL; 606 const char *file, *ident; 607 struct bpf_program *prog; 608 int fd, err = -1; 609 struct bpf_map *map; 610 struct btf *btf; 611 struct stat st; 612 613 if (!REQ_ARGS(1)) { 614 usage(); 615 return -1; 616 } 617 file = GET_ARG(); 618 619 while (argc) { 620 if (!REQ_ARGS(2)) 621 return -1; 622 623 if (is_prefix(*argv, "name")) { 624 NEXT_ARG(); 625 626 if (obj_name[0] != '\0') { 627 p_err("object name already specified"); 628 return -1; 629 } 630 631 strncpy(obj_name, *argv, MAX_OBJ_NAME_LEN - 1); 632 obj_name[MAX_OBJ_NAME_LEN - 1] = '\0'; 633 } else { 634 p_err("unknown arg %s", *argv); 635 return -1; 636 } 637 638 NEXT_ARG(); 639 } 640 641 if (argc) { 642 p_err("extra unknown arguments"); 643 return -1; 644 } 645 646 if (stat(file, &st)) { 647 p_err("failed to stat() %s: %s", file, strerror(errno)); 648 return -1; 649 } 650 file_sz = st.st_size; 651 mmap_sz = roundup(file_sz, sysconf(_SC_PAGE_SIZE)); 652 fd = open(file, O_RDONLY); 653 if (fd < 0) { 654 p_err("failed to open() %s: %s", file, strerror(errno)); 655 return -1; 656 } 657 obj_data = mmap(NULL, mmap_sz, PROT_READ, MAP_PRIVATE, fd, 0); 658 if (obj_data == MAP_FAILED) { 659 obj_data = NULL; 660 p_err("failed to mmap() %s: %s", file, strerror(errno)); 661 goto out; 662 } 663 if (obj_name[0] == '\0') 664 get_obj_name(obj_name, file); 665 opts.object_name = obj_name; 666 obj = bpf_object__open_mem(obj_data, file_sz, &opts); 667 if (IS_ERR(obj)) { 668 char err_buf[256]; 669 670 libbpf_strerror(PTR_ERR(obj), err_buf, sizeof(err_buf)); 671 p_err("failed to open BPF object file: %s", err_buf); 672 obj = NULL; 673 goto out; 674 } 675 676 bpf_object__for_each_map(map, obj) { 677 ident = get_map_ident(map); 678 if (!ident) { 679 p_err("ignoring unrecognized internal map '%s'...", 680 bpf_map__name(map)); 681 continue; 682 } 683 map_cnt++; 684 } 685 bpf_object__for_each_program(prog, obj) { 686 prog_cnt++; 687 } 688 689 get_header_guard(header_guard, obj_name); 690 if (use_loader) { 691 codegen("\ 692 \n\ 693 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\ 694 /* THIS FILE IS AUTOGENERATED! */ \n\ 695 #ifndef %2$s \n\ 696 #define %2$s \n\ 697 \n\ 698 #include <stdlib.h> \n\ 699 #include <bpf/bpf.h> \n\ 700 #include <bpf/skel_internal.h> \n\ 701 \n\ 702 struct %1$s { \n\ 703 struct bpf_loader_ctx ctx; \n\ 704 ", 705 obj_name, header_guard 706 ); 707 } else { 708 codegen("\ 709 \n\ 710 /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ \n\ 711 \n\ 712 /* THIS FILE IS AUTOGENERATED! */ \n\ 713 #ifndef %2$s \n\ 714 #define %2$s \n\ 715 \n\ 716 #include <errno.h> \n\ 717 #include <stdlib.h> \n\ 718 #include <bpf/libbpf.h> \n\ 719 \n\ 720 struct %1$s { \n\ 721 struct bpf_object_skeleton *skeleton; \n\ 722 struct bpf_object *obj; \n\ 723 ", 724 obj_name, header_guard 725 ); 726 } 727 728 if (map_cnt) { 729 printf("\tstruct {\n"); 730 bpf_object__for_each_map(map, obj) { 731 ident = get_map_ident(map); 732 if (!ident) 733 continue; 734 if (use_loader) 735 printf("\t\tstruct bpf_map_desc %s;\n", ident); 736 else 737 printf("\t\tstruct bpf_map *%s;\n", ident); 738 } 739 printf("\t} maps;\n"); 740 } 741 742 if (prog_cnt) { 743 printf("\tstruct {\n"); 744 bpf_object__for_each_program(prog, obj) { 745 if (use_loader) 746 printf("\t\tstruct bpf_prog_desc %s;\n", 747 bpf_program__name(prog)); 748 else 749 printf("\t\tstruct bpf_program *%s;\n", 750 bpf_program__name(prog)); 751 } 752 printf("\t} progs;\n"); 753 printf("\tstruct {\n"); 754 bpf_object__for_each_program(prog, obj) { 755 if (use_loader) 756 printf("\t\tint %s_fd;\n", 757 bpf_program__name(prog)); 758 else 759 printf("\t\tstruct bpf_link *%s;\n", 760 bpf_program__name(prog)); 761 } 762 printf("\t} links;\n"); 763 } 764 765 btf = bpf_object__btf(obj); 766 if (btf) { 767 err = codegen_datasecs(obj, obj_name); 768 if (err) 769 goto out; 770 } 771 if (use_loader) { 772 err = gen_trace(obj, obj_name, header_guard); 773 goto out; 774 } 775 776 codegen("\ 777 \n\ 778 }; \n\ 779 \n\ 780 static void \n\ 781 %1$s__destroy(struct %1$s *obj) \n\ 782 { \n\ 783 if (!obj) \n\ 784 return; \n\ 785 if (obj->skeleton) \n\ 786 bpf_object__destroy_skeleton(obj->skeleton);\n\ 787 free(obj); \n\ 788 } \n\ 789 \n\ 790 static inline int \n\ 791 %1$s__create_skeleton(struct %1$s *obj); \n\ 792 \n\ 793 static inline struct %1$s * \n\ 794 %1$s__open_opts(const struct bpf_object_open_opts *opts) \n\ 795 { \n\ 796 struct %1$s *obj; \n\ 797 int err; \n\ 798 \n\ 799 obj = (struct %1$s *)calloc(1, sizeof(*obj)); \n\ 800 if (!obj) { \n\ 801 errno = ENOMEM; \n\ 802 return NULL; \n\ 803 } \n\ 804 \n\ 805 err = %1$s__create_skeleton(obj); \n\ 806 err = err ?: bpf_object__open_skeleton(obj->skeleton, opts);\n\ 807 if (err) \n\ 808 goto err_out; \n\ 809 \n\ 810 return obj; \n\ 811 err_out: \n\ 812 %1$s__destroy(obj); \n\ 813 errno = -err; \n\ 814 return NULL; \n\ 815 } \n\ 816 \n\ 817 static inline struct %1$s * \n\ 818 %1$s__open(void) \n\ 819 { \n\ 820 return %1$s__open_opts(NULL); \n\ 821 } \n\ 822 \n\ 823 static inline int \n\ 824 %1$s__load(struct %1$s *obj) \n\ 825 { \n\ 826 return bpf_object__load_skeleton(obj->skeleton); \n\ 827 } \n\ 828 \n\ 829 static inline struct %1$s * \n\ 830 %1$s__open_and_load(void) \n\ 831 { \n\ 832 struct %1$s *obj; \n\ 833 int err; \n\ 834 \n\ 835 obj = %1$s__open(); \n\ 836 if (!obj) \n\ 837 return NULL; \n\ 838 err = %1$s__load(obj); \n\ 839 if (err) { \n\ 840 %1$s__destroy(obj); \n\ 841 errno = -err; \n\ 842 return NULL; \n\ 843 } \n\ 844 return obj; \n\ 845 } \n\ 846 \n\ 847 static inline int \n\ 848 %1$s__attach(struct %1$s *obj) \n\ 849 { \n\ 850 return bpf_object__attach_skeleton(obj->skeleton); \n\ 851 } \n\ 852 \n\ 853 static inline void \n\ 854 %1$s__detach(struct %1$s *obj) \n\ 855 { \n\ 856 return bpf_object__detach_skeleton(obj->skeleton); \n\ 857 } \n\ 858 ", 859 obj_name 860 ); 861 862 codegen("\ 863 \n\ 864 \n\ 865 static inline int \n\ 866 %1$s__create_skeleton(struct %1$s *obj) \n\ 867 { \n\ 868 struct bpf_object_skeleton *s; \n\ 869 \n\ 870 s = (struct bpf_object_skeleton *)calloc(1, sizeof(*s));\n\ 871 if (!s) \n\ 872 goto err; \n\ 873 obj->skeleton = s; \n\ 874 \n\ 875 s->sz = sizeof(*s); \n\ 876 s->name = \"%1$s\"; \n\ 877 s->obj = &obj->obj; \n\ 878 ", 879 obj_name 880 ); 881 if (map_cnt) { 882 codegen("\ 883 \n\ 884 \n\ 885 /* maps */ \n\ 886 s->map_cnt = %zu; \n\ 887 s->map_skel_sz = sizeof(*s->maps); \n\ 888 s->maps = (struct bpf_map_skeleton *)calloc(s->map_cnt, s->map_skel_sz);\n\ 889 if (!s->maps) \n\ 890 goto err; \n\ 891 ", 892 map_cnt 893 ); 894 i = 0; 895 bpf_object__for_each_map(map, obj) { 896 ident = get_map_ident(map); 897 898 if (!ident) 899 continue; 900 901 codegen("\ 902 \n\ 903 \n\ 904 s->maps[%zu].name = \"%s\"; \n\ 905 s->maps[%zu].map = &obj->maps.%s; \n\ 906 ", 907 i, bpf_map__name(map), i, ident); 908 /* memory-mapped internal maps */ 909 if (bpf_map__is_internal(map) && 910 (bpf_map__def(map)->map_flags & BPF_F_MMAPABLE)) { 911 printf("\ts->maps[%zu].mmaped = (void **)&obj->%s;\n", 912 i, ident); 913 } 914 i++; 915 } 916 } 917 if (prog_cnt) { 918 codegen("\ 919 \n\ 920 \n\ 921 /* programs */ \n\ 922 s->prog_cnt = %zu; \n\ 923 s->prog_skel_sz = sizeof(*s->progs); \n\ 924 s->progs = (struct bpf_prog_skeleton *)calloc(s->prog_cnt, s->prog_skel_sz);\n\ 925 if (!s->progs) \n\ 926 goto err; \n\ 927 ", 928 prog_cnt 929 ); 930 i = 0; 931 bpf_object__for_each_program(prog, obj) { 932 codegen("\ 933 \n\ 934 \n\ 935 s->progs[%1$zu].name = \"%2$s\"; \n\ 936 s->progs[%1$zu].prog = &obj->progs.%2$s;\n\ 937 s->progs[%1$zu].link = &obj->links.%2$s;\n\ 938 ", 939 i, bpf_program__name(prog)); 940 i++; 941 } 942 } 943 codegen("\ 944 \n\ 945 \n\ 946 s->data_sz = %d; \n\ 947 s->data = (void *)\"\\ \n\ 948 ", 949 file_sz); 950 951 /* embed contents of BPF object file */ 952 print_hex(obj_data, file_sz); 953 954 codegen("\ 955 \n\ 956 \"; \n\ 957 \n\ 958 return 0; \n\ 959 err: \n\ 960 bpf_object__destroy_skeleton(s); \n\ 961 return -ENOMEM; \n\ 962 } \n\ 963 \n\ 964 #endif /* %s */ \n\ 965 ", 966 header_guard); 967 err = 0; 968 out: 969 bpf_object__close(obj); 970 if (obj_data) 971 munmap(obj_data, mmap_sz); 972 close(fd); 973 return err; 974 } 975 976 static int do_object(int argc, char **argv) 977 { 978 struct bpf_linker *linker; 979 const char *output_file, *file; 980 int err = 0; 981 982 if (!REQ_ARGS(2)) { 983 usage(); 984 return -1; 985 } 986 987 output_file = GET_ARG(); 988 989 linker = bpf_linker__new(output_file, NULL); 990 if (!linker) { 991 p_err("failed to create BPF linker instance"); 992 return -1; 993 } 994 995 while (argc) { 996 file = GET_ARG(); 997 998 err = bpf_linker__add_file(linker, file, NULL); 999 if (err) { 1000 p_err("failed to link '%s': %s (%d)", file, strerror(err), err); 1001 goto out; 1002 } 1003 } 1004 1005 err = bpf_linker__finalize(linker); 1006 if (err) { 1007 p_err("failed to finalize ELF file: %s (%d)", strerror(err), err); 1008 goto out; 1009 } 1010 1011 err = 0; 1012 out: 1013 bpf_linker__free(linker); 1014 return err; 1015 } 1016 1017 static int do_help(int argc, char **argv) 1018 { 1019 if (json_output) { 1020 jsonw_null(json_wtr); 1021 return 0; 1022 } 1023 1024 fprintf(stderr, 1025 "Usage: %1$s %2$s object OUTPUT_FILE INPUT_FILE [INPUT_FILE...]\n" 1026 " %1$s %2$s skeleton FILE [name OBJECT_NAME]\n" 1027 " %1$s %2$s help\n" 1028 "\n" 1029 " " HELP_SPEC_OPTIONS " |\n" 1030 " {-L|--use-loader} }\n" 1031 "", 1032 bin_name, "gen"); 1033 1034 return 0; 1035 } 1036 1037 static const struct cmd cmds[] = { 1038 { "object", do_object }, 1039 { "skeleton", do_skeleton }, 1040 { "help", do_help }, 1041 { 0 } 1042 }; 1043 1044 int do_gen(int argc, char **argv) 1045 { 1046 return cmd_select(cmds, argc, argv, do_help); 1047 } 1048