1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 3 4 #define _GNU_SOURCE 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <stdarg.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <time.h> 12 #include <unistd.h> 13 #include <net/if.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 17 #include <linux/err.h> 18 #include <linux/sizes.h> 19 20 #include <bpf/bpf.h> 21 #include <bpf/btf.h> 22 #include <bpf/libbpf.h> 23 24 #include "cfg.h" 25 #include "main.h" 26 #include "xlated_dumper.h" 27 28 enum dump_mode { 29 DUMP_JITED, 30 DUMP_XLATED, 31 }; 32 33 static const char * const attach_type_strings[] = { 34 [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 35 [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 36 [BPF_SK_MSG_VERDICT] = "msg_verdict", 37 [BPF_FLOW_DISSECTOR] = "flow_dissector", 38 [__MAX_BPF_ATTACH_TYPE] = NULL, 39 }; 40 41 static enum bpf_attach_type parse_attach_type(const char *str) 42 { 43 enum bpf_attach_type type; 44 45 for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 46 if (attach_type_strings[type] && 47 is_prefix(str, attach_type_strings[type])) 48 return type; 49 } 50 51 return __MAX_BPF_ATTACH_TYPE; 52 } 53 54 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 55 { 56 struct timespec real_time_ts, boot_time_ts; 57 time_t wallclock_secs; 58 struct tm load_tm; 59 60 buf[--size] = '\0'; 61 62 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 63 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 64 perror("Can't read clocks"); 65 snprintf(buf, size, "%llu", nsecs / 1000000000); 66 return; 67 } 68 69 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 70 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 71 1000000000; 72 73 74 if (!localtime_r(&wallclock_secs, &load_tm)) { 75 snprintf(buf, size, "%llu", nsecs / 1000000000); 76 return; 77 } 78 79 if (json_output) 80 strftime(buf, size, "%s", &load_tm); 81 else 82 strftime(buf, size, "%FT%T%z", &load_tm); 83 } 84 85 static int prog_fd_by_nametag(void *nametag, int **fds, bool tag) 86 { 87 unsigned int id = 0; 88 int fd, nb_fds = 0; 89 void *tmp; 90 int err; 91 92 while (true) { 93 struct bpf_prog_info info = {}; 94 __u32 len = sizeof(info); 95 96 err = bpf_prog_get_next_id(id, &id); 97 if (err) { 98 if (errno != ENOENT) { 99 p_err("%s", strerror(errno)); 100 goto err_close_fds; 101 } 102 return nb_fds; 103 } 104 105 fd = bpf_prog_get_fd_by_id(id); 106 if (fd < 0) { 107 p_err("can't get prog by id (%u): %s", 108 id, strerror(errno)); 109 goto err_close_fds; 110 } 111 112 err = bpf_obj_get_info_by_fd(fd, &info, &len); 113 if (err) { 114 p_err("can't get prog info (%u): %s", 115 id, strerror(errno)); 116 goto err_close_fd; 117 } 118 119 if ((tag && memcmp(nametag, info.tag, BPF_TAG_SIZE)) || 120 (!tag && strncmp(nametag, info.name, BPF_OBJ_NAME_LEN))) { 121 close(fd); 122 continue; 123 } 124 125 if (nb_fds > 0) { 126 tmp = realloc(*fds, (nb_fds + 1) * sizeof(int)); 127 if (!tmp) { 128 p_err("failed to realloc"); 129 goto err_close_fd; 130 } 131 *fds = tmp; 132 } 133 (*fds)[nb_fds++] = fd; 134 } 135 136 err_close_fd: 137 close(fd); 138 err_close_fds: 139 while (--nb_fds >= 0) 140 close((*fds)[nb_fds]); 141 return -1; 142 } 143 144 static int prog_parse_fds(int *argc, char ***argv, int **fds) 145 { 146 if (is_prefix(**argv, "id")) { 147 unsigned int id; 148 char *endptr; 149 150 NEXT_ARGP(); 151 152 id = strtoul(**argv, &endptr, 0); 153 if (*endptr) { 154 p_err("can't parse %s as ID", **argv); 155 return -1; 156 } 157 NEXT_ARGP(); 158 159 (*fds)[0] = bpf_prog_get_fd_by_id(id); 160 if ((*fds)[0] < 0) { 161 p_err("get by id (%u): %s", id, strerror(errno)); 162 return -1; 163 } 164 return 1; 165 } else if (is_prefix(**argv, "tag")) { 166 unsigned char tag[BPF_TAG_SIZE]; 167 168 NEXT_ARGP(); 169 170 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 171 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 172 != BPF_TAG_SIZE) { 173 p_err("can't parse tag"); 174 return -1; 175 } 176 NEXT_ARGP(); 177 178 return prog_fd_by_nametag(tag, fds, true); 179 } else if (is_prefix(**argv, "name")) { 180 char *name; 181 182 NEXT_ARGP(); 183 184 name = **argv; 185 if (strlen(name) > BPF_OBJ_NAME_LEN - 1) { 186 p_err("can't parse name"); 187 return -1; 188 } 189 NEXT_ARGP(); 190 191 return prog_fd_by_nametag(name, fds, false); 192 } else if (is_prefix(**argv, "pinned")) { 193 char *path; 194 195 NEXT_ARGP(); 196 197 path = **argv; 198 NEXT_ARGP(); 199 200 (*fds)[0] = open_obj_pinned_any(path, BPF_OBJ_PROG); 201 if ((*fds)[0] < 0) 202 return -1; 203 return 1; 204 } 205 206 p_err("expected 'id', 'tag', 'name' or 'pinned', got: '%s'?", **argv); 207 return -1; 208 } 209 210 int prog_parse_fd(int *argc, char ***argv) 211 { 212 int *fds = NULL; 213 int nb_fds, fd; 214 215 fds = malloc(sizeof(int)); 216 if (!fds) { 217 p_err("mem alloc failed"); 218 return -1; 219 } 220 nb_fds = prog_parse_fds(argc, argv, &fds); 221 if (nb_fds != 1) { 222 if (nb_fds > 1) { 223 p_err("several programs match this handle"); 224 while (nb_fds--) 225 close(fds[nb_fds]); 226 } 227 fd = -1; 228 goto exit_free; 229 } 230 231 fd = fds[0]; 232 exit_free: 233 free(fds); 234 return fd; 235 } 236 237 static void show_prog_maps(int fd, u32 num_maps) 238 { 239 struct bpf_prog_info info = {}; 240 __u32 len = sizeof(info); 241 __u32 map_ids[num_maps]; 242 unsigned int i; 243 int err; 244 245 info.nr_map_ids = num_maps; 246 info.map_ids = ptr_to_u64(map_ids); 247 248 err = bpf_obj_get_info_by_fd(fd, &info, &len); 249 if (err || !info.nr_map_ids) 250 return; 251 252 if (json_output) { 253 jsonw_name(json_wtr, "map_ids"); 254 jsonw_start_array(json_wtr); 255 for (i = 0; i < info.nr_map_ids; i++) 256 jsonw_uint(json_wtr, map_ids[i]); 257 jsonw_end_array(json_wtr); 258 } else { 259 printf(" map_ids "); 260 for (i = 0; i < info.nr_map_ids; i++) 261 printf("%u%s", map_ids[i], 262 i == info.nr_map_ids - 1 ? "" : ","); 263 } 264 } 265 266 static void print_prog_header_json(struct bpf_prog_info *info) 267 { 268 jsonw_uint_field(json_wtr, "id", info->id); 269 if (info->type < ARRAY_SIZE(prog_type_name)) 270 jsonw_string_field(json_wtr, "type", 271 prog_type_name[info->type]); 272 else 273 jsonw_uint_field(json_wtr, "type", info->type); 274 275 if (*info->name) 276 jsonw_string_field(json_wtr, "name", info->name); 277 278 jsonw_name(json_wtr, "tag"); 279 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 280 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 281 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 282 283 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 284 if (info->run_time_ns) { 285 jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 286 jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 287 } 288 } 289 290 static void print_prog_json(struct bpf_prog_info *info, int fd) 291 { 292 char *memlock; 293 294 jsonw_start_object(json_wtr); 295 print_prog_header_json(info); 296 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 297 298 if (info->load_time) { 299 char buf[32]; 300 301 print_boot_time(info->load_time, buf, sizeof(buf)); 302 303 /* Piggy back on load_time, since 0 uid is a valid one */ 304 jsonw_name(json_wtr, "loaded_at"); 305 jsonw_printf(json_wtr, "%s", buf); 306 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 307 } 308 309 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 310 311 if (info->jited_prog_len) { 312 jsonw_bool_field(json_wtr, "jited", true); 313 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 314 } else { 315 jsonw_bool_field(json_wtr, "jited", false); 316 } 317 318 memlock = get_fdinfo(fd, "memlock"); 319 if (memlock) 320 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 321 free(memlock); 322 323 if (info->nr_map_ids) 324 show_prog_maps(fd, info->nr_map_ids); 325 326 if (info->btf_id) 327 jsonw_int_field(json_wtr, "btf_id", info->btf_id); 328 329 if (!hash_empty(prog_table.table)) { 330 struct pinned_obj *obj; 331 332 jsonw_name(json_wtr, "pinned"); 333 jsonw_start_array(json_wtr); 334 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 335 if (obj->id == info->id) 336 jsonw_string(json_wtr, obj->path); 337 } 338 jsonw_end_array(json_wtr); 339 } 340 341 jsonw_end_object(json_wtr); 342 } 343 344 static void print_prog_header_plain(struct bpf_prog_info *info) 345 { 346 printf("%u: ", info->id); 347 if (info->type < ARRAY_SIZE(prog_type_name)) 348 printf("%s ", prog_type_name[info->type]); 349 else 350 printf("type %u ", info->type); 351 352 if (*info->name) 353 printf("name %s ", info->name); 354 355 printf("tag "); 356 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 357 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 358 printf("%s", info->gpl_compatible ? " gpl" : ""); 359 if (info->run_time_ns) 360 printf(" run_time_ns %lld run_cnt %lld", 361 info->run_time_ns, info->run_cnt); 362 printf("\n"); 363 } 364 365 static void print_prog_plain(struct bpf_prog_info *info, int fd) 366 { 367 char *memlock; 368 369 print_prog_header_plain(info); 370 371 if (info->load_time) { 372 char buf[32]; 373 374 print_boot_time(info->load_time, buf, sizeof(buf)); 375 376 /* Piggy back on load_time, since 0 uid is a valid one */ 377 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 378 } 379 380 printf("\txlated %uB", info->xlated_prog_len); 381 382 if (info->jited_prog_len) 383 printf(" jited %uB", info->jited_prog_len); 384 else 385 printf(" not jited"); 386 387 memlock = get_fdinfo(fd, "memlock"); 388 if (memlock) 389 printf(" memlock %sB", memlock); 390 free(memlock); 391 392 if (info->nr_map_ids) 393 show_prog_maps(fd, info->nr_map_ids); 394 395 if (!hash_empty(prog_table.table)) { 396 struct pinned_obj *obj; 397 398 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 399 if (obj->id == info->id) 400 printf("\n\tpinned %s", obj->path); 401 } 402 } 403 404 if (info->btf_id) 405 printf("\n\tbtf_id %d", info->btf_id); 406 407 printf("\n"); 408 } 409 410 static int show_prog(int fd) 411 { 412 struct bpf_prog_info info = {}; 413 __u32 len = sizeof(info); 414 int err; 415 416 err = bpf_obj_get_info_by_fd(fd, &info, &len); 417 if (err) { 418 p_err("can't get prog info: %s", strerror(errno)); 419 return -1; 420 } 421 422 if (json_output) 423 print_prog_json(&info, fd); 424 else 425 print_prog_plain(&info, fd); 426 427 return 0; 428 } 429 430 static int do_show_subset(int argc, char **argv) 431 { 432 int *fds = NULL; 433 int nb_fds, i; 434 int err = -1; 435 436 fds = malloc(sizeof(int)); 437 if (!fds) { 438 p_err("mem alloc failed"); 439 return -1; 440 } 441 nb_fds = prog_parse_fds(&argc, &argv, &fds); 442 if (nb_fds < 1) 443 goto exit_free; 444 445 if (json_output && nb_fds > 1) 446 jsonw_start_array(json_wtr); /* root array */ 447 for (i = 0; i < nb_fds; i++) { 448 err = show_prog(fds[i]); 449 if (err) { 450 for (; i < nb_fds; i++) 451 close(fds[i]); 452 break; 453 } 454 close(fds[i]); 455 } 456 if (json_output && nb_fds > 1) 457 jsonw_end_array(json_wtr); /* root array */ 458 459 exit_free: 460 free(fds); 461 return err; 462 } 463 464 static int do_show(int argc, char **argv) 465 { 466 __u32 id = 0; 467 int err; 468 int fd; 469 470 if (show_pinned) 471 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 472 473 if (argc == 2) 474 return do_show_subset(argc, argv); 475 476 if (argc) 477 return BAD_ARG(); 478 479 if (json_output) 480 jsonw_start_array(json_wtr); 481 while (true) { 482 err = bpf_prog_get_next_id(id, &id); 483 if (err) { 484 if (errno == ENOENT) { 485 err = 0; 486 break; 487 } 488 p_err("can't get next program: %s%s", strerror(errno), 489 errno == EINVAL ? " -- kernel too old?" : ""); 490 err = -1; 491 break; 492 } 493 494 fd = bpf_prog_get_fd_by_id(id); 495 if (fd < 0) { 496 if (errno == ENOENT) 497 continue; 498 p_err("can't get prog by id (%u): %s", 499 id, strerror(errno)); 500 err = -1; 501 break; 502 } 503 504 err = show_prog(fd); 505 close(fd); 506 if (err) 507 break; 508 } 509 510 if (json_output) 511 jsonw_end_array(json_wtr); 512 513 return err; 514 } 515 516 static int 517 prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 518 char *filepath, bool opcodes, bool visual, bool linum) 519 { 520 struct bpf_prog_linfo *prog_linfo = NULL; 521 const char *disasm_opt = NULL; 522 struct dump_data dd = {}; 523 void *func_info = NULL; 524 struct btf *btf = NULL; 525 char func_sig[1024]; 526 unsigned char *buf; 527 __u32 member_len; 528 ssize_t n; 529 int fd; 530 531 if (mode == DUMP_JITED) { 532 if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 533 p_info("no instructions returned"); 534 return -1; 535 } 536 buf = (unsigned char *)(info->jited_prog_insns); 537 member_len = info->jited_prog_len; 538 } else { /* DUMP_XLATED */ 539 if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 540 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 541 return -1; 542 } 543 buf = (unsigned char *)info->xlated_prog_insns; 544 member_len = info->xlated_prog_len; 545 } 546 547 if (info->btf_id && btf__get_from_id(info->btf_id, &btf)) { 548 p_err("failed to get btf"); 549 return -1; 550 } 551 552 func_info = (void *)info->func_info; 553 554 if (info->nr_line_info) { 555 prog_linfo = bpf_prog_linfo__new(info); 556 if (!prog_linfo) 557 p_info("error in processing bpf_line_info. continue without it."); 558 } 559 560 if (filepath) { 561 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 562 if (fd < 0) { 563 p_err("can't open file %s: %s", filepath, 564 strerror(errno)); 565 return -1; 566 } 567 568 n = write(fd, buf, member_len); 569 close(fd); 570 if (n != member_len) { 571 p_err("error writing output file: %s", 572 n < 0 ? strerror(errno) : "short write"); 573 return -1; 574 } 575 576 if (json_output) 577 jsonw_null(json_wtr); 578 } else if (mode == DUMP_JITED) { 579 const char *name = NULL; 580 581 if (info->ifindex) { 582 name = ifindex_to_bfd_params(info->ifindex, 583 info->netns_dev, 584 info->netns_ino, 585 &disasm_opt); 586 if (!name) 587 return -1; 588 } 589 590 if (info->nr_jited_func_lens && info->jited_func_lens) { 591 struct kernel_sym *sym = NULL; 592 struct bpf_func_info *record; 593 char sym_name[SYM_MAX_NAME]; 594 unsigned char *img = buf; 595 __u64 *ksyms = NULL; 596 __u32 *lens; 597 __u32 i; 598 if (info->nr_jited_ksyms) { 599 kernel_syms_load(&dd); 600 ksyms = (__u64 *) info->jited_ksyms; 601 } 602 603 if (json_output) 604 jsonw_start_array(json_wtr); 605 606 lens = (__u32 *) info->jited_func_lens; 607 for (i = 0; i < info->nr_jited_func_lens; i++) { 608 if (ksyms) { 609 sym = kernel_syms_search(&dd, ksyms[i]); 610 if (sym) 611 sprintf(sym_name, "%s", sym->name); 612 else 613 sprintf(sym_name, "0x%016llx", ksyms[i]); 614 } else { 615 strcpy(sym_name, "unknown"); 616 } 617 618 if (func_info) { 619 record = func_info + i * info->func_info_rec_size; 620 btf_dumper_type_only(btf, record->type_id, 621 func_sig, 622 sizeof(func_sig)); 623 } 624 625 if (json_output) { 626 jsonw_start_object(json_wtr); 627 if (func_info && func_sig[0] != '\0') { 628 jsonw_name(json_wtr, "proto"); 629 jsonw_string(json_wtr, func_sig); 630 } 631 jsonw_name(json_wtr, "name"); 632 jsonw_string(json_wtr, sym_name); 633 jsonw_name(json_wtr, "insns"); 634 } else { 635 if (func_info && func_sig[0] != '\0') 636 printf("%s:\n", func_sig); 637 printf("%s:\n", sym_name); 638 } 639 640 disasm_print_insn(img, lens[i], opcodes, 641 name, disasm_opt, btf, 642 prog_linfo, ksyms[i], i, 643 linum); 644 645 img += lens[i]; 646 647 if (json_output) 648 jsonw_end_object(json_wtr); 649 else 650 printf("\n"); 651 } 652 653 if (json_output) 654 jsonw_end_array(json_wtr); 655 } else { 656 disasm_print_insn(buf, member_len, opcodes, name, 657 disasm_opt, btf, NULL, 0, 0, false); 658 } 659 } else if (visual) { 660 if (json_output) 661 jsonw_null(json_wtr); 662 else 663 dump_xlated_cfg(buf, member_len); 664 } else { 665 kernel_syms_load(&dd); 666 dd.nr_jited_ksyms = info->nr_jited_ksyms; 667 dd.jited_ksyms = (__u64 *) info->jited_ksyms; 668 dd.btf = btf; 669 dd.func_info = func_info; 670 dd.finfo_rec_size = info->func_info_rec_size; 671 dd.prog_linfo = prog_linfo; 672 673 if (json_output) 674 dump_xlated_json(&dd, buf, member_len, opcodes, 675 linum); 676 else 677 dump_xlated_plain(&dd, buf, member_len, opcodes, 678 linum); 679 kernel_syms_destroy(&dd); 680 } 681 682 return 0; 683 } 684 685 static int do_dump(int argc, char **argv) 686 { 687 struct bpf_prog_info_linear *info_linear; 688 char *filepath = NULL; 689 bool opcodes = false; 690 bool visual = false; 691 enum dump_mode mode; 692 bool linum = false; 693 int *fds = NULL; 694 int nb_fds, i = 0; 695 int err = -1; 696 __u64 arrays; 697 698 if (is_prefix(*argv, "jited")) { 699 if (disasm_init()) 700 return -1; 701 mode = DUMP_JITED; 702 } else if (is_prefix(*argv, "xlated")) { 703 mode = DUMP_XLATED; 704 } else { 705 p_err("expected 'xlated' or 'jited', got: %s", *argv); 706 return -1; 707 } 708 NEXT_ARG(); 709 710 if (argc < 2) 711 usage(); 712 713 fds = malloc(sizeof(int)); 714 if (!fds) { 715 p_err("mem alloc failed"); 716 return -1; 717 } 718 nb_fds = prog_parse_fds(&argc, &argv, &fds); 719 if (nb_fds < 1) 720 goto exit_free; 721 722 if (is_prefix(*argv, "file")) { 723 NEXT_ARG(); 724 if (!argc) { 725 p_err("expected file path"); 726 goto exit_close; 727 } 728 if (nb_fds > 1) { 729 p_err("several programs matched"); 730 goto exit_close; 731 } 732 733 filepath = *argv; 734 NEXT_ARG(); 735 } else if (is_prefix(*argv, "opcodes")) { 736 opcodes = true; 737 NEXT_ARG(); 738 } else if (is_prefix(*argv, "visual")) { 739 if (nb_fds > 1) { 740 p_err("several programs matched"); 741 goto exit_close; 742 } 743 744 visual = true; 745 NEXT_ARG(); 746 } else if (is_prefix(*argv, "linum")) { 747 linum = true; 748 NEXT_ARG(); 749 } 750 751 if (argc) { 752 usage(); 753 goto exit_close; 754 } 755 756 if (mode == DUMP_JITED) 757 arrays = 1UL << BPF_PROG_INFO_JITED_INSNS; 758 else 759 arrays = 1UL << BPF_PROG_INFO_XLATED_INSNS; 760 761 arrays |= 1UL << BPF_PROG_INFO_JITED_KSYMS; 762 arrays |= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS; 763 arrays |= 1UL << BPF_PROG_INFO_FUNC_INFO; 764 arrays |= 1UL << BPF_PROG_INFO_LINE_INFO; 765 arrays |= 1UL << BPF_PROG_INFO_JITED_LINE_INFO; 766 767 if (json_output && nb_fds > 1) 768 jsonw_start_array(json_wtr); /* root array */ 769 for (i = 0; i < nb_fds; i++) { 770 info_linear = bpf_program__get_prog_info_linear(fds[i], arrays); 771 if (IS_ERR_OR_NULL(info_linear)) { 772 p_err("can't get prog info: %s", strerror(errno)); 773 break; 774 } 775 776 if (json_output && nb_fds > 1) { 777 jsonw_start_object(json_wtr); /* prog object */ 778 print_prog_header_json(&info_linear->info); 779 jsonw_name(json_wtr, "insns"); 780 } else if (nb_fds > 1) { 781 print_prog_header_plain(&info_linear->info); 782 } 783 784 err = prog_dump(&info_linear->info, mode, filepath, opcodes, 785 visual, linum); 786 787 if (json_output && nb_fds > 1) 788 jsonw_end_object(json_wtr); /* prog object */ 789 else if (i != nb_fds - 1 && nb_fds > 1) 790 printf("\n"); 791 792 free(info_linear); 793 if (err) 794 break; 795 close(fds[i]); 796 } 797 if (json_output && nb_fds > 1) 798 jsonw_end_array(json_wtr); /* root array */ 799 800 exit_close: 801 for (; i < nb_fds; i++) 802 close(fds[i]); 803 exit_free: 804 free(fds); 805 return err; 806 } 807 808 static int do_pin(int argc, char **argv) 809 { 810 int err; 811 812 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 813 if (!err && json_output) 814 jsonw_null(json_wtr); 815 return err; 816 } 817 818 struct map_replace { 819 int idx; 820 int fd; 821 char *name; 822 }; 823 824 static int map_replace_compar(const void *p1, const void *p2) 825 { 826 const struct map_replace *a = p1, *b = p2; 827 828 return a->idx - b->idx; 829 } 830 831 static int parse_attach_detach_args(int argc, char **argv, int *progfd, 832 enum bpf_attach_type *attach_type, 833 int *mapfd) 834 { 835 if (!REQ_ARGS(3)) 836 return -EINVAL; 837 838 *progfd = prog_parse_fd(&argc, &argv); 839 if (*progfd < 0) 840 return *progfd; 841 842 *attach_type = parse_attach_type(*argv); 843 if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 844 p_err("invalid attach/detach type"); 845 return -EINVAL; 846 } 847 848 if (*attach_type == BPF_FLOW_DISSECTOR) { 849 *mapfd = -1; 850 return 0; 851 } 852 853 NEXT_ARG(); 854 if (!REQ_ARGS(2)) 855 return -EINVAL; 856 857 *mapfd = map_parse_fd(&argc, &argv); 858 if (*mapfd < 0) 859 return *mapfd; 860 861 return 0; 862 } 863 864 static int do_attach(int argc, char **argv) 865 { 866 enum bpf_attach_type attach_type; 867 int err, progfd; 868 int mapfd; 869 870 err = parse_attach_detach_args(argc, argv, 871 &progfd, &attach_type, &mapfd); 872 if (err) 873 return err; 874 875 err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 876 if (err) { 877 p_err("failed prog attach to map"); 878 return -EINVAL; 879 } 880 881 if (json_output) 882 jsonw_null(json_wtr); 883 return 0; 884 } 885 886 static int do_detach(int argc, char **argv) 887 { 888 enum bpf_attach_type attach_type; 889 int err, progfd; 890 int mapfd; 891 892 err = parse_attach_detach_args(argc, argv, 893 &progfd, &attach_type, &mapfd); 894 if (err) 895 return err; 896 897 err = bpf_prog_detach2(progfd, mapfd, attach_type); 898 if (err) { 899 p_err("failed prog detach from map"); 900 return -EINVAL; 901 } 902 903 if (json_output) 904 jsonw_null(json_wtr); 905 return 0; 906 } 907 908 static int check_single_stdin(char *file_data_in, char *file_ctx_in) 909 { 910 if (file_data_in && file_ctx_in && 911 !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 912 p_err("cannot use standard input for both data_in and ctx_in"); 913 return -1; 914 } 915 916 return 0; 917 } 918 919 static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 920 { 921 size_t block_size = 256; 922 size_t buf_size = block_size; 923 size_t nb_read = 0; 924 void *tmp; 925 FILE *f; 926 927 if (!fname) { 928 *data_ptr = NULL; 929 *size = 0; 930 return 0; 931 } 932 933 if (!strcmp(fname, "-")) 934 f = stdin; 935 else 936 f = fopen(fname, "r"); 937 if (!f) { 938 p_err("failed to open %s: %s", fname, strerror(errno)); 939 return -1; 940 } 941 942 *data_ptr = malloc(block_size); 943 if (!*data_ptr) { 944 p_err("failed to allocate memory for data_in/ctx_in: %s", 945 strerror(errno)); 946 goto err_fclose; 947 } 948 949 while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 950 if (feof(f)) 951 break; 952 if (ferror(f)) { 953 p_err("failed to read data_in/ctx_in from %s: %s", 954 fname, strerror(errno)); 955 goto err_free; 956 } 957 if (nb_read > buf_size - block_size) { 958 if (buf_size == UINT32_MAX) { 959 p_err("data_in/ctx_in is too long (max: %d)", 960 UINT32_MAX); 961 goto err_free; 962 } 963 /* No space for fread()-ing next chunk; realloc() */ 964 buf_size *= 2; 965 tmp = realloc(*data_ptr, buf_size); 966 if (!tmp) { 967 p_err("failed to reallocate data_in/ctx_in: %s", 968 strerror(errno)); 969 goto err_free; 970 } 971 *data_ptr = tmp; 972 } 973 } 974 if (f != stdin) 975 fclose(f); 976 977 *size = nb_read; 978 return 0; 979 980 err_free: 981 free(*data_ptr); 982 *data_ptr = NULL; 983 err_fclose: 984 if (f != stdin) 985 fclose(f); 986 return -1; 987 } 988 989 static void hex_print(void *data, unsigned int size, FILE *f) 990 { 991 size_t i, j; 992 char c; 993 994 for (i = 0; i < size; i += 16) { 995 /* Row offset */ 996 fprintf(f, "%07zx\t", i); 997 998 /* Hexadecimal values */ 999 for (j = i; j < i + 16 && j < size; j++) 1000 fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1001 j % 2 ? " " : ""); 1002 for (; j < i + 16; j++) 1003 fprintf(f, " %s", j % 2 ? " " : ""); 1004 1005 /* ASCII values (if relevant), '.' otherwise */ 1006 fprintf(f, "| "); 1007 for (j = i; j < i + 16 && j < size; j++) { 1008 c = *(char *)(data + j); 1009 if (c < ' ' || c > '~') 1010 c = '.'; 1011 fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1012 } 1013 1014 fprintf(f, "\n"); 1015 } 1016 } 1017 1018 static int 1019 print_run_output(void *data, unsigned int size, const char *fname, 1020 const char *json_key) 1021 { 1022 size_t nb_written; 1023 FILE *f; 1024 1025 if (!fname) 1026 return 0; 1027 1028 if (!strcmp(fname, "-")) { 1029 f = stdout; 1030 if (json_output) { 1031 jsonw_name(json_wtr, json_key); 1032 print_data_json(data, size); 1033 } else { 1034 hex_print(data, size, f); 1035 } 1036 return 0; 1037 } 1038 1039 f = fopen(fname, "w"); 1040 if (!f) { 1041 p_err("failed to open %s: %s", fname, strerror(errno)); 1042 return -1; 1043 } 1044 1045 nb_written = fwrite(data, 1, size, f); 1046 fclose(f); 1047 if (nb_written != size) { 1048 p_err("failed to write output data/ctx: %s", strerror(errno)); 1049 return -1; 1050 } 1051 1052 return 0; 1053 } 1054 1055 static int alloc_run_data(void **data_ptr, unsigned int size_out) 1056 { 1057 *data_ptr = calloc(size_out, 1); 1058 if (!*data_ptr) { 1059 p_err("failed to allocate memory for output data/ctx: %s", 1060 strerror(errno)); 1061 return -1; 1062 } 1063 1064 return 0; 1065 } 1066 1067 static int do_run(int argc, char **argv) 1068 { 1069 char *data_fname_in = NULL, *data_fname_out = NULL; 1070 char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1071 struct bpf_prog_test_run_attr test_attr = {0}; 1072 const unsigned int default_size = SZ_32K; 1073 void *data_in = NULL, *data_out = NULL; 1074 void *ctx_in = NULL, *ctx_out = NULL; 1075 unsigned int repeat = 1; 1076 int fd, err; 1077 1078 if (!REQ_ARGS(4)) 1079 return -1; 1080 1081 fd = prog_parse_fd(&argc, &argv); 1082 if (fd < 0) 1083 return -1; 1084 1085 while (argc) { 1086 if (detect_common_prefix(*argv, "data_in", "data_out", 1087 "data_size_out", NULL)) 1088 return -1; 1089 if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1090 "ctx_size_out", NULL)) 1091 return -1; 1092 1093 if (is_prefix(*argv, "data_in")) { 1094 NEXT_ARG(); 1095 if (!REQ_ARGS(1)) 1096 return -1; 1097 1098 data_fname_in = GET_ARG(); 1099 if (check_single_stdin(data_fname_in, ctx_fname_in)) 1100 return -1; 1101 } else if (is_prefix(*argv, "data_out")) { 1102 NEXT_ARG(); 1103 if (!REQ_ARGS(1)) 1104 return -1; 1105 1106 data_fname_out = GET_ARG(); 1107 } else if (is_prefix(*argv, "data_size_out")) { 1108 char *endptr; 1109 1110 NEXT_ARG(); 1111 if (!REQ_ARGS(1)) 1112 return -1; 1113 1114 test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1115 if (*endptr) { 1116 p_err("can't parse %s as output data size", 1117 *argv); 1118 return -1; 1119 } 1120 NEXT_ARG(); 1121 } else if (is_prefix(*argv, "ctx_in")) { 1122 NEXT_ARG(); 1123 if (!REQ_ARGS(1)) 1124 return -1; 1125 1126 ctx_fname_in = GET_ARG(); 1127 if (check_single_stdin(data_fname_in, ctx_fname_in)) 1128 return -1; 1129 } else if (is_prefix(*argv, "ctx_out")) { 1130 NEXT_ARG(); 1131 if (!REQ_ARGS(1)) 1132 return -1; 1133 1134 ctx_fname_out = GET_ARG(); 1135 } else if (is_prefix(*argv, "ctx_size_out")) { 1136 char *endptr; 1137 1138 NEXT_ARG(); 1139 if (!REQ_ARGS(1)) 1140 return -1; 1141 1142 test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1143 if (*endptr) { 1144 p_err("can't parse %s as output context size", 1145 *argv); 1146 return -1; 1147 } 1148 NEXT_ARG(); 1149 } else if (is_prefix(*argv, "repeat")) { 1150 char *endptr; 1151 1152 NEXT_ARG(); 1153 if (!REQ_ARGS(1)) 1154 return -1; 1155 1156 repeat = strtoul(*argv, &endptr, 0); 1157 if (*endptr) { 1158 p_err("can't parse %s as repeat number", 1159 *argv); 1160 return -1; 1161 } 1162 NEXT_ARG(); 1163 } else { 1164 p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1165 *argv); 1166 return -1; 1167 } 1168 } 1169 1170 err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1171 if (err) 1172 return -1; 1173 1174 if (data_in) { 1175 if (!test_attr.data_size_out) 1176 test_attr.data_size_out = default_size; 1177 err = alloc_run_data(&data_out, test_attr.data_size_out); 1178 if (err) 1179 goto free_data_in; 1180 } 1181 1182 err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1183 if (err) 1184 goto free_data_out; 1185 1186 if (ctx_in) { 1187 if (!test_attr.ctx_size_out) 1188 test_attr.ctx_size_out = default_size; 1189 err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1190 if (err) 1191 goto free_ctx_in; 1192 } 1193 1194 test_attr.prog_fd = fd; 1195 test_attr.repeat = repeat; 1196 test_attr.data_in = data_in; 1197 test_attr.data_out = data_out; 1198 test_attr.ctx_in = ctx_in; 1199 test_attr.ctx_out = ctx_out; 1200 1201 err = bpf_prog_test_run_xattr(&test_attr); 1202 if (err) { 1203 p_err("failed to run program: %s", strerror(errno)); 1204 goto free_ctx_out; 1205 } 1206 1207 err = 0; 1208 1209 if (json_output) 1210 jsonw_start_object(json_wtr); /* root */ 1211 1212 /* Do not exit on errors occurring when printing output data/context, 1213 * we still want to print return value and duration for program run. 1214 */ 1215 if (test_attr.data_size_out) 1216 err += print_run_output(test_attr.data_out, 1217 test_attr.data_size_out, 1218 data_fname_out, "data_out"); 1219 if (test_attr.ctx_size_out) 1220 err += print_run_output(test_attr.ctx_out, 1221 test_attr.ctx_size_out, 1222 ctx_fname_out, "ctx_out"); 1223 1224 if (json_output) { 1225 jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1226 jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1227 jsonw_end_object(json_wtr); /* root */ 1228 } else { 1229 fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1230 test_attr.retval, 1231 repeat > 1 ? " (average)" : "", test_attr.duration); 1232 } 1233 1234 free_ctx_out: 1235 free(ctx_out); 1236 free_ctx_in: 1237 free(ctx_in); 1238 free_data_out: 1239 free(data_out); 1240 free_data_in: 1241 free(data_in); 1242 1243 return err; 1244 } 1245 1246 static int load_with_options(int argc, char **argv, bool first_prog_only) 1247 { 1248 enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1249 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1250 .relaxed_maps = relaxed_maps, 1251 ); 1252 struct bpf_object_load_attr load_attr = { 0 }; 1253 enum bpf_attach_type expected_attach_type; 1254 struct map_replace *map_replace = NULL; 1255 struct bpf_program *prog = NULL, *pos; 1256 unsigned int old_map_fds = 0; 1257 const char *pinmaps = NULL; 1258 struct bpf_object *obj; 1259 struct bpf_map *map; 1260 const char *pinfile; 1261 unsigned int i, j; 1262 __u32 ifindex = 0; 1263 const char *file; 1264 int idx, err; 1265 1266 1267 if (!REQ_ARGS(2)) 1268 return -1; 1269 file = GET_ARG(); 1270 pinfile = GET_ARG(); 1271 1272 while (argc) { 1273 if (is_prefix(*argv, "type")) { 1274 char *type; 1275 1276 NEXT_ARG(); 1277 1278 if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 1279 p_err("program type already specified"); 1280 goto err_free_reuse_maps; 1281 } 1282 if (!REQ_ARGS(1)) 1283 goto err_free_reuse_maps; 1284 1285 /* Put a '/' at the end of type to appease libbpf */ 1286 type = malloc(strlen(*argv) + 2); 1287 if (!type) { 1288 p_err("mem alloc failed"); 1289 goto err_free_reuse_maps; 1290 } 1291 *type = 0; 1292 strcat(type, *argv); 1293 strcat(type, "/"); 1294 1295 err = libbpf_prog_type_by_name(type, &common_prog_type, 1296 &expected_attach_type); 1297 free(type); 1298 if (err < 0) 1299 goto err_free_reuse_maps; 1300 1301 NEXT_ARG(); 1302 } else if (is_prefix(*argv, "map")) { 1303 void *new_map_replace; 1304 char *endptr, *name; 1305 int fd; 1306 1307 NEXT_ARG(); 1308 1309 if (!REQ_ARGS(4)) 1310 goto err_free_reuse_maps; 1311 1312 if (is_prefix(*argv, "idx")) { 1313 NEXT_ARG(); 1314 1315 idx = strtoul(*argv, &endptr, 0); 1316 if (*endptr) { 1317 p_err("can't parse %s as IDX", *argv); 1318 goto err_free_reuse_maps; 1319 } 1320 name = NULL; 1321 } else if (is_prefix(*argv, "name")) { 1322 NEXT_ARG(); 1323 1324 name = *argv; 1325 idx = -1; 1326 } else { 1327 p_err("expected 'idx' or 'name', got: '%s'?", 1328 *argv); 1329 goto err_free_reuse_maps; 1330 } 1331 NEXT_ARG(); 1332 1333 fd = map_parse_fd(&argc, &argv); 1334 if (fd < 0) 1335 goto err_free_reuse_maps; 1336 1337 new_map_replace = reallocarray(map_replace, 1338 old_map_fds + 1, 1339 sizeof(*map_replace)); 1340 if (!new_map_replace) { 1341 p_err("mem alloc failed"); 1342 goto err_free_reuse_maps; 1343 } 1344 map_replace = new_map_replace; 1345 1346 map_replace[old_map_fds].idx = idx; 1347 map_replace[old_map_fds].name = name; 1348 map_replace[old_map_fds].fd = fd; 1349 old_map_fds++; 1350 } else if (is_prefix(*argv, "dev")) { 1351 NEXT_ARG(); 1352 1353 if (ifindex) { 1354 p_err("offload device already specified"); 1355 goto err_free_reuse_maps; 1356 } 1357 if (!REQ_ARGS(1)) 1358 goto err_free_reuse_maps; 1359 1360 ifindex = if_nametoindex(*argv); 1361 if (!ifindex) { 1362 p_err("unrecognized netdevice '%s': %s", 1363 *argv, strerror(errno)); 1364 goto err_free_reuse_maps; 1365 } 1366 NEXT_ARG(); 1367 } else if (is_prefix(*argv, "pinmaps")) { 1368 NEXT_ARG(); 1369 1370 if (!REQ_ARGS(1)) 1371 goto err_free_reuse_maps; 1372 1373 pinmaps = GET_ARG(); 1374 } else { 1375 p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1376 *argv); 1377 goto err_free_reuse_maps; 1378 } 1379 } 1380 1381 set_max_rlimit(); 1382 1383 obj = bpf_object__open_file(file, &open_opts); 1384 if (IS_ERR_OR_NULL(obj)) { 1385 p_err("failed to open object file"); 1386 goto err_free_reuse_maps; 1387 } 1388 1389 bpf_object__for_each_program(pos, obj) { 1390 enum bpf_prog_type prog_type = common_prog_type; 1391 1392 if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1393 const char *sec_name = bpf_program__title(pos, false); 1394 1395 err = libbpf_prog_type_by_name(sec_name, &prog_type, 1396 &expected_attach_type); 1397 if (err < 0) 1398 goto err_close_obj; 1399 } 1400 1401 bpf_program__set_ifindex(pos, ifindex); 1402 bpf_program__set_type(pos, prog_type); 1403 bpf_program__set_expected_attach_type(pos, expected_attach_type); 1404 } 1405 1406 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1407 map_replace_compar); 1408 1409 /* After the sort maps by name will be first on the list, because they 1410 * have idx == -1. Resolve them. 1411 */ 1412 j = 0; 1413 while (j < old_map_fds && map_replace[j].name) { 1414 i = 0; 1415 bpf_object__for_each_map(map, obj) { 1416 if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 1417 map_replace[j].idx = i; 1418 break; 1419 } 1420 i++; 1421 } 1422 if (map_replace[j].idx == -1) { 1423 p_err("unable to find map '%s'", map_replace[j].name); 1424 goto err_close_obj; 1425 } 1426 j++; 1427 } 1428 /* Resort if any names were resolved */ 1429 if (j) 1430 qsort(map_replace, old_map_fds, sizeof(*map_replace), 1431 map_replace_compar); 1432 1433 /* Set ifindex and name reuse */ 1434 j = 0; 1435 idx = 0; 1436 bpf_object__for_each_map(map, obj) { 1437 if (!bpf_map__is_offload_neutral(map)) 1438 bpf_map__set_ifindex(map, ifindex); 1439 1440 if (j < old_map_fds && idx == map_replace[j].idx) { 1441 err = bpf_map__reuse_fd(map, map_replace[j++].fd); 1442 if (err) { 1443 p_err("unable to set up map reuse: %d", err); 1444 goto err_close_obj; 1445 } 1446 1447 /* Next reuse wants to apply to the same map */ 1448 if (j < old_map_fds && map_replace[j].idx == idx) { 1449 p_err("replacement for map idx %d specified more than once", 1450 idx); 1451 goto err_close_obj; 1452 } 1453 } 1454 1455 idx++; 1456 } 1457 if (j < old_map_fds) { 1458 p_err("map idx '%d' not used", map_replace[j].idx); 1459 goto err_close_obj; 1460 } 1461 1462 load_attr.obj = obj; 1463 if (verifier_logs) 1464 /* log_level1 + log_level2 + stats, but not stable UAPI */ 1465 load_attr.log_level = 1 + 2 + 4; 1466 1467 err = bpf_object__load_xattr(&load_attr); 1468 if (err) { 1469 p_err("failed to load object file"); 1470 goto err_close_obj; 1471 } 1472 1473 err = mount_bpffs_for_pin(pinfile); 1474 if (err) 1475 goto err_close_obj; 1476 1477 if (first_prog_only) { 1478 prog = bpf_program__next(NULL, obj); 1479 if (!prog) { 1480 p_err("object file doesn't contain any bpf program"); 1481 goto err_close_obj; 1482 } 1483 1484 err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 1485 if (err) { 1486 p_err("failed to pin program %s", 1487 bpf_program__title(prog, false)); 1488 goto err_close_obj; 1489 } 1490 } else { 1491 err = bpf_object__pin_programs(obj, pinfile); 1492 if (err) { 1493 p_err("failed to pin all programs"); 1494 goto err_close_obj; 1495 } 1496 } 1497 1498 if (pinmaps) { 1499 err = bpf_object__pin_maps(obj, pinmaps); 1500 if (err) { 1501 p_err("failed to pin all maps"); 1502 goto err_unpin; 1503 } 1504 } 1505 1506 if (json_output) 1507 jsonw_null(json_wtr); 1508 1509 bpf_object__close(obj); 1510 for (i = 0; i < old_map_fds; i++) 1511 close(map_replace[i].fd); 1512 free(map_replace); 1513 1514 return 0; 1515 1516 err_unpin: 1517 if (first_prog_only) 1518 unlink(pinfile); 1519 else 1520 bpf_object__unpin_programs(obj, pinfile); 1521 err_close_obj: 1522 bpf_object__close(obj); 1523 err_free_reuse_maps: 1524 for (i = 0; i < old_map_fds; i++) 1525 close(map_replace[i].fd); 1526 free(map_replace); 1527 return -1; 1528 } 1529 1530 static int do_load(int argc, char **argv) 1531 { 1532 return load_with_options(argc, argv, true); 1533 } 1534 1535 static int do_loadall(int argc, char **argv) 1536 { 1537 return load_with_options(argc, argv, false); 1538 } 1539 1540 static int do_help(int argc, char **argv) 1541 { 1542 if (json_output) { 1543 jsonw_null(json_wtr); 1544 return 0; 1545 } 1546 1547 fprintf(stderr, 1548 "Usage: %s %s { show | list } [PROG]\n" 1549 " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1550 " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1551 " %s %s pin PROG FILE\n" 1552 " %s %s { load | loadall } OBJ PATH \\\n" 1553 " [type TYPE] [dev NAME] \\\n" 1554 " [map { idx IDX | name NAME } MAP]\\\n" 1555 " [pinmaps MAP_DIR]\n" 1556 " %s %s attach PROG ATTACH_TYPE [MAP]\n" 1557 " %s %s detach PROG ATTACH_TYPE [MAP]\n" 1558 " %s %s run PROG \\\n" 1559 " data_in FILE \\\n" 1560 " [data_out FILE [data_size_out L]] \\\n" 1561 " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 1562 " [repeat N]\n" 1563 " %s %s tracelog\n" 1564 " %s %s help\n" 1565 "\n" 1566 " " HELP_SPEC_MAP "\n" 1567 " " HELP_SPEC_PROGRAM "\n" 1568 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 1569 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 1570 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 1571 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 1572 " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 1573 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 1574 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 1575 " cgroup/sendmsg4 | cgroup/sendmsg6 | cgroup/recvmsg4 |\n" 1576 " cgroup/recvmsg6 | cgroup/getsockopt |\n" 1577 " cgroup/setsockopt }\n" 1578 " ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |\n" 1579 " flow_dissector }\n" 1580 " " HELP_SPEC_OPTIONS "\n" 1581 "", 1582 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1583 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1584 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 1585 bin_name, argv[-2]); 1586 1587 return 0; 1588 } 1589 1590 static const struct cmd cmds[] = { 1591 { "show", do_show }, 1592 { "list", do_show }, 1593 { "help", do_help }, 1594 { "dump", do_dump }, 1595 { "pin", do_pin }, 1596 { "load", do_load }, 1597 { "loadall", do_loadall }, 1598 { "attach", do_attach }, 1599 { "detach", do_detach }, 1600 { "tracelog", do_tracelog }, 1601 { "run", do_run }, 1602 { 0 } 1603 }; 1604 1605 int do_prog(int argc, char **argv) 1606 { 1607 return cmd_select(cmds, argc, argv, do_help); 1608 } 1609