1 /* 2 * Copyright (C) 2017-2018 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <time.h> 41 #include <unistd.h> 42 #include <net/if.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 46 #include <bpf.h> 47 #include <libbpf.h> 48 49 #include "cfg.h" 50 #include "main.h" 51 #include "xlated_dumper.h" 52 53 static const char * const prog_type_name[] = { 54 [BPF_PROG_TYPE_UNSPEC] = "unspec", 55 [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 56 [BPF_PROG_TYPE_KPROBE] = "kprobe", 57 [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 58 [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 59 [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 60 [BPF_PROG_TYPE_XDP] = "xdp", 61 [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 62 [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 63 [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 64 [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 65 [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 66 [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 67 [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 68 [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 69 [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 70 [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 71 [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 72 [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 73 [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 74 }; 75 76 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 77 { 78 struct timespec real_time_ts, boot_time_ts; 79 time_t wallclock_secs; 80 struct tm load_tm; 81 82 buf[--size] = '\0'; 83 84 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 85 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 86 perror("Can't read clocks"); 87 snprintf(buf, size, "%llu", nsecs / 1000000000); 88 return; 89 } 90 91 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 92 (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 93 1000000000; 94 95 96 if (!localtime_r(&wallclock_secs, &load_tm)) { 97 snprintf(buf, size, "%llu", nsecs / 1000000000); 98 return; 99 } 100 101 if (json_output) 102 strftime(buf, size, "%s", &load_tm); 103 else 104 strftime(buf, size, "%FT%T%z", &load_tm); 105 } 106 107 static int prog_fd_by_tag(unsigned char *tag) 108 { 109 struct bpf_prog_info info = {}; 110 __u32 len = sizeof(info); 111 unsigned int id = 0; 112 int err; 113 int fd; 114 115 while (true) { 116 err = bpf_prog_get_next_id(id, &id); 117 if (err) { 118 p_err("%s", strerror(errno)); 119 return -1; 120 } 121 122 fd = bpf_prog_get_fd_by_id(id); 123 if (fd < 0) { 124 p_err("can't get prog by id (%u): %s", 125 id, strerror(errno)); 126 return -1; 127 } 128 129 err = bpf_obj_get_info_by_fd(fd, &info, &len); 130 if (err) { 131 p_err("can't get prog info (%u): %s", 132 id, strerror(errno)); 133 close(fd); 134 return -1; 135 } 136 137 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 138 return fd; 139 140 close(fd); 141 } 142 } 143 144 int prog_parse_fd(int *argc, char ***argv) 145 { 146 int fd; 147 148 if (is_prefix(**argv, "id")) { 149 unsigned int id; 150 char *endptr; 151 152 NEXT_ARGP(); 153 154 id = strtoul(**argv, &endptr, 0); 155 if (*endptr) { 156 p_err("can't parse %s as ID", **argv); 157 return -1; 158 } 159 NEXT_ARGP(); 160 161 fd = bpf_prog_get_fd_by_id(id); 162 if (fd < 0) 163 p_err("get by id (%u): %s", id, strerror(errno)); 164 return fd; 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_tag(tag); 179 } else if (is_prefix(**argv, "pinned")) { 180 char *path; 181 182 NEXT_ARGP(); 183 184 path = **argv; 185 NEXT_ARGP(); 186 187 return open_obj_pinned_any(path, BPF_OBJ_PROG); 188 } 189 190 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 191 return -1; 192 } 193 194 static void show_prog_maps(int fd, u32 num_maps) 195 { 196 struct bpf_prog_info info = {}; 197 __u32 len = sizeof(info); 198 __u32 map_ids[num_maps]; 199 unsigned int i; 200 int err; 201 202 info.nr_map_ids = num_maps; 203 info.map_ids = ptr_to_u64(map_ids); 204 205 err = bpf_obj_get_info_by_fd(fd, &info, &len); 206 if (err || !info.nr_map_ids) 207 return; 208 209 if (json_output) { 210 jsonw_name(json_wtr, "map_ids"); 211 jsonw_start_array(json_wtr); 212 for (i = 0; i < info.nr_map_ids; i++) 213 jsonw_uint(json_wtr, map_ids[i]); 214 jsonw_end_array(json_wtr); 215 } else { 216 printf(" map_ids "); 217 for (i = 0; i < info.nr_map_ids; i++) 218 printf("%u%s", map_ids[i], 219 i == info.nr_map_ids - 1 ? "" : ","); 220 } 221 } 222 223 static void print_prog_json(struct bpf_prog_info *info, int fd) 224 { 225 char *memlock; 226 227 jsonw_start_object(json_wtr); 228 jsonw_uint_field(json_wtr, "id", info->id); 229 if (info->type < ARRAY_SIZE(prog_type_name)) 230 jsonw_string_field(json_wtr, "type", 231 prog_type_name[info->type]); 232 else 233 jsonw_uint_field(json_wtr, "type", info->type); 234 235 if (*info->name) 236 jsonw_string_field(json_wtr, "name", info->name); 237 238 jsonw_name(json_wtr, "tag"); 239 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 240 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 241 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 242 243 jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 244 245 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 246 247 if (info->load_time) { 248 char buf[32]; 249 250 print_boot_time(info->load_time, buf, sizeof(buf)); 251 252 /* Piggy back on load_time, since 0 uid is a valid one */ 253 jsonw_name(json_wtr, "loaded_at"); 254 jsonw_printf(json_wtr, "%s", buf); 255 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 256 } 257 258 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 259 260 if (info->jited_prog_len) { 261 jsonw_bool_field(json_wtr, "jited", true); 262 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 263 } else { 264 jsonw_bool_field(json_wtr, "jited", false); 265 } 266 267 memlock = get_fdinfo(fd, "memlock"); 268 if (memlock) 269 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 270 free(memlock); 271 272 if (info->nr_map_ids) 273 show_prog_maps(fd, info->nr_map_ids); 274 275 if (!hash_empty(prog_table.table)) { 276 struct pinned_obj *obj; 277 278 jsonw_name(json_wtr, "pinned"); 279 jsonw_start_array(json_wtr); 280 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 281 if (obj->id == info->id) 282 jsonw_string(json_wtr, obj->path); 283 } 284 jsonw_end_array(json_wtr); 285 } 286 287 jsonw_end_object(json_wtr); 288 } 289 290 static void print_prog_plain(struct bpf_prog_info *info, int fd) 291 { 292 char *memlock; 293 294 printf("%u: ", info->id); 295 if (info->type < ARRAY_SIZE(prog_type_name)) 296 printf("%s ", prog_type_name[info->type]); 297 else 298 printf("type %u ", info->type); 299 300 if (*info->name) 301 printf("name %s ", info->name); 302 303 printf("tag "); 304 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 305 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 306 printf("%s", info->gpl_compatible ? " gpl" : ""); 307 printf("\n"); 308 309 if (info->load_time) { 310 char buf[32]; 311 312 print_boot_time(info->load_time, buf, sizeof(buf)); 313 314 /* Piggy back on load_time, since 0 uid is a valid one */ 315 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 316 } 317 318 printf("\txlated %uB", info->xlated_prog_len); 319 320 if (info->jited_prog_len) 321 printf(" jited %uB", info->jited_prog_len); 322 else 323 printf(" not jited"); 324 325 memlock = get_fdinfo(fd, "memlock"); 326 if (memlock) 327 printf(" memlock %sB", memlock); 328 free(memlock); 329 330 if (info->nr_map_ids) 331 show_prog_maps(fd, info->nr_map_ids); 332 333 if (!hash_empty(prog_table.table)) { 334 struct pinned_obj *obj; 335 336 printf("\n"); 337 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 338 if (obj->id == info->id) 339 printf("\tpinned %s\n", obj->path); 340 } 341 } 342 343 printf("\n"); 344 } 345 346 static int show_prog(int fd) 347 { 348 struct bpf_prog_info info = {}; 349 __u32 len = sizeof(info); 350 int err; 351 352 err = bpf_obj_get_info_by_fd(fd, &info, &len); 353 if (err) { 354 p_err("can't get prog info: %s", strerror(errno)); 355 return -1; 356 } 357 358 if (json_output) 359 print_prog_json(&info, fd); 360 else 361 print_prog_plain(&info, fd); 362 363 return 0; 364 } 365 366 static int do_show(int argc, char **argv) 367 { 368 __u32 id = 0; 369 int err; 370 int fd; 371 372 if (show_pinned) 373 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 374 375 if (argc == 2) { 376 fd = prog_parse_fd(&argc, &argv); 377 if (fd < 0) 378 return -1; 379 380 return show_prog(fd); 381 } 382 383 if (argc) 384 return BAD_ARG(); 385 386 if (json_output) 387 jsonw_start_array(json_wtr); 388 while (true) { 389 err = bpf_prog_get_next_id(id, &id); 390 if (err) { 391 if (errno == ENOENT) { 392 err = 0; 393 break; 394 } 395 p_err("can't get next program: %s%s", strerror(errno), 396 errno == EINVAL ? " -- kernel too old?" : ""); 397 err = -1; 398 break; 399 } 400 401 fd = bpf_prog_get_fd_by_id(id); 402 if (fd < 0) { 403 if (errno == ENOENT) 404 continue; 405 p_err("can't get prog by id (%u): %s", 406 id, strerror(errno)); 407 err = -1; 408 break; 409 } 410 411 err = show_prog(fd); 412 close(fd); 413 if (err) 414 break; 415 } 416 417 if (json_output) 418 jsonw_end_array(json_wtr); 419 420 return err; 421 } 422 423 static int do_dump(int argc, char **argv) 424 { 425 unsigned long *func_ksyms = NULL; 426 struct bpf_prog_info info = {}; 427 unsigned int *func_lens = NULL; 428 unsigned int nr_func_ksyms; 429 unsigned int nr_func_lens; 430 struct dump_data dd = {}; 431 __u32 len = sizeof(info); 432 unsigned int buf_size; 433 char *filepath = NULL; 434 bool opcodes = false; 435 bool visual = false; 436 unsigned char *buf; 437 __u32 *member_len; 438 __u64 *member_ptr; 439 ssize_t n; 440 int err; 441 int fd; 442 443 if (is_prefix(*argv, "jited")) { 444 member_len = &info.jited_prog_len; 445 member_ptr = &info.jited_prog_insns; 446 } else if (is_prefix(*argv, "xlated")) { 447 member_len = &info.xlated_prog_len; 448 member_ptr = &info.xlated_prog_insns; 449 } else { 450 p_err("expected 'xlated' or 'jited', got: %s", *argv); 451 return -1; 452 } 453 NEXT_ARG(); 454 455 if (argc < 2) 456 usage(); 457 458 fd = prog_parse_fd(&argc, &argv); 459 if (fd < 0) 460 return -1; 461 462 if (is_prefix(*argv, "file")) { 463 NEXT_ARG(); 464 if (!argc) { 465 p_err("expected file path"); 466 return -1; 467 } 468 469 filepath = *argv; 470 NEXT_ARG(); 471 } else if (is_prefix(*argv, "opcodes")) { 472 opcodes = true; 473 NEXT_ARG(); 474 } else if (is_prefix(*argv, "visual")) { 475 visual = true; 476 NEXT_ARG(); 477 } 478 479 if (argc) { 480 usage(); 481 return -1; 482 } 483 484 err = bpf_obj_get_info_by_fd(fd, &info, &len); 485 if (err) { 486 p_err("can't get prog info: %s", strerror(errno)); 487 return -1; 488 } 489 490 if (!*member_len) { 491 p_info("no instructions returned"); 492 close(fd); 493 return 0; 494 } 495 496 buf_size = *member_len; 497 498 buf = malloc(buf_size); 499 if (!buf) { 500 p_err("mem alloc failed"); 501 close(fd); 502 return -1; 503 } 504 505 nr_func_ksyms = info.nr_jited_ksyms; 506 if (nr_func_ksyms) { 507 func_ksyms = malloc(nr_func_ksyms * sizeof(__u64)); 508 if (!func_ksyms) { 509 p_err("mem alloc failed"); 510 close(fd); 511 goto err_free; 512 } 513 } 514 515 nr_func_lens = info.nr_jited_func_lens; 516 if (nr_func_lens) { 517 func_lens = malloc(nr_func_lens * sizeof(__u32)); 518 if (!func_lens) { 519 p_err("mem alloc failed"); 520 close(fd); 521 goto err_free; 522 } 523 } 524 525 memset(&info, 0, sizeof(info)); 526 527 *member_ptr = ptr_to_u64(buf); 528 *member_len = buf_size; 529 info.jited_ksyms = ptr_to_u64(func_ksyms); 530 info.nr_jited_ksyms = nr_func_ksyms; 531 info.jited_func_lens = ptr_to_u64(func_lens); 532 info.nr_jited_func_lens = nr_func_lens; 533 534 err = bpf_obj_get_info_by_fd(fd, &info, &len); 535 close(fd); 536 if (err) { 537 p_err("can't get prog info: %s", strerror(errno)); 538 goto err_free; 539 } 540 541 if (*member_len > buf_size) { 542 p_err("too many instructions returned"); 543 goto err_free; 544 } 545 546 if (info.nr_jited_ksyms > nr_func_ksyms) { 547 p_err("too many addresses returned"); 548 goto err_free; 549 } 550 551 if (info.nr_jited_func_lens > nr_func_lens) { 552 p_err("too many values returned"); 553 goto err_free; 554 } 555 556 if ((member_len == &info.jited_prog_len && 557 info.jited_prog_insns == 0) || 558 (member_len == &info.xlated_prog_len && 559 info.xlated_prog_insns == 0)) { 560 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 561 goto err_free; 562 } 563 564 if (filepath) { 565 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 566 if (fd < 0) { 567 p_err("can't open file %s: %s", filepath, 568 strerror(errno)); 569 goto err_free; 570 } 571 572 n = write(fd, buf, *member_len); 573 close(fd); 574 if (n != *member_len) { 575 p_err("error writing output file: %s", 576 n < 0 ? strerror(errno) : "short write"); 577 goto err_free; 578 } 579 580 if (json_output) 581 jsonw_null(json_wtr); 582 } else if (member_len == &info.jited_prog_len) { 583 const char *name = NULL; 584 585 if (info.ifindex) { 586 name = ifindex_to_bfd_name_ns(info.ifindex, 587 info.netns_dev, 588 info.netns_ino); 589 if (!name) 590 goto err_free; 591 } 592 593 if (info.nr_jited_func_lens && info.jited_func_lens) { 594 struct kernel_sym *sym = NULL; 595 char sym_name[SYM_MAX_NAME]; 596 unsigned char *img = buf; 597 __u64 *ksyms = NULL; 598 __u32 *lens; 599 __u32 i; 600 601 if (info.nr_jited_ksyms) { 602 kernel_syms_load(&dd); 603 ksyms = (__u64 *) info.jited_ksyms; 604 } 605 606 if (json_output) 607 jsonw_start_array(json_wtr); 608 609 lens = (__u32 *) info.jited_func_lens; 610 for (i = 0; i < info.nr_jited_func_lens; i++) { 611 if (ksyms) { 612 sym = kernel_syms_search(&dd, ksyms[i]); 613 if (sym) 614 sprintf(sym_name, "%s", sym->name); 615 else 616 sprintf(sym_name, "0x%016llx", ksyms[i]); 617 } else { 618 strcpy(sym_name, "unknown"); 619 } 620 621 if (json_output) { 622 jsonw_start_object(json_wtr); 623 jsonw_name(json_wtr, "name"); 624 jsonw_string(json_wtr, sym_name); 625 jsonw_name(json_wtr, "insns"); 626 } else { 627 printf("%s:\n", sym_name); 628 } 629 630 disasm_print_insn(img, lens[i], opcodes, name); 631 img += lens[i]; 632 633 if (json_output) 634 jsonw_end_object(json_wtr); 635 else 636 printf("\n"); 637 } 638 639 if (json_output) 640 jsonw_end_array(json_wtr); 641 } else { 642 disasm_print_insn(buf, *member_len, opcodes, name); 643 } 644 } else if (visual) { 645 if (json_output) 646 jsonw_null(json_wtr); 647 else 648 dump_xlated_cfg(buf, *member_len); 649 } else { 650 kernel_syms_load(&dd); 651 dd.nr_jited_ksyms = info.nr_jited_ksyms; 652 dd.jited_ksyms = (__u64 *) info.jited_ksyms; 653 654 if (json_output) 655 dump_xlated_json(&dd, buf, *member_len, opcodes); 656 else 657 dump_xlated_plain(&dd, buf, *member_len, opcodes); 658 kernel_syms_destroy(&dd); 659 } 660 661 free(buf); 662 free(func_ksyms); 663 free(func_lens); 664 return 0; 665 666 err_free: 667 free(buf); 668 free(func_ksyms); 669 free(func_lens); 670 return -1; 671 } 672 673 static int do_pin(int argc, char **argv) 674 { 675 int err; 676 677 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 678 if (!err && json_output) 679 jsonw_null(json_wtr); 680 return err; 681 } 682 683 static int do_load(int argc, char **argv) 684 { 685 struct bpf_prog_load_attr attr = { 686 .prog_type = BPF_PROG_TYPE_UNSPEC, 687 }; 688 const char *objfile, *pinfile; 689 struct bpf_object *obj; 690 int prog_fd; 691 int err; 692 693 if (!REQ_ARGS(2)) 694 return -1; 695 objfile = GET_ARG(); 696 pinfile = GET_ARG(); 697 698 while (argc) { 699 if (is_prefix(*argv, "type")) { 700 char *type; 701 702 NEXT_ARG(); 703 704 if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) { 705 p_err("program type already specified"); 706 return -1; 707 } 708 if (!REQ_ARGS(1)) 709 return -1; 710 711 /* Put a '/' at the end of type to appease libbpf */ 712 type = malloc(strlen(*argv) + 2); 713 if (!type) { 714 p_err("mem alloc failed"); 715 return -1; 716 } 717 *type = 0; 718 strcat(type, *argv); 719 strcat(type, "/"); 720 721 err = libbpf_prog_type_by_name(type, &attr.prog_type, 722 &attr.expected_attach_type); 723 free(type); 724 if (err < 0) { 725 p_err("unknown program type '%s'", *argv); 726 return err; 727 } 728 NEXT_ARG(); 729 } else if (is_prefix(*argv, "dev")) { 730 NEXT_ARG(); 731 732 if (attr.ifindex) { 733 p_err("offload device already specified"); 734 return -1; 735 } 736 if (!REQ_ARGS(1)) 737 return -1; 738 739 attr.ifindex = if_nametoindex(*argv); 740 if (!attr.ifindex) { 741 p_err("unrecognized netdevice '%s': %s", 742 *argv, strerror(errno)); 743 return -1; 744 } 745 NEXT_ARG(); 746 } else { 747 p_err("expected no more arguments, 'type' or 'dev', got: '%s'?", 748 *argv); 749 return -1; 750 } 751 } 752 753 attr.file = objfile; 754 755 if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) { 756 p_err("failed to load program"); 757 return -1; 758 } 759 760 if (do_pin_fd(prog_fd, pinfile)) 761 goto err_close_obj; 762 763 if (json_output) 764 jsonw_null(json_wtr); 765 766 bpf_object__close(obj); 767 768 return 0; 769 770 err_close_obj: 771 bpf_object__close(obj); 772 return -1; 773 } 774 775 static int do_help(int argc, char **argv) 776 { 777 if (json_output) { 778 jsonw_null(json_wtr); 779 return 0; 780 } 781 782 fprintf(stderr, 783 "Usage: %s %s { show | list } [PROG]\n" 784 " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 785 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 786 " %s %s pin PROG FILE\n" 787 " %s %s load OBJ FILE [type TYPE] [dev NAME]\n" 788 " %s %s help\n" 789 "\n" 790 " " HELP_SPEC_PROGRAM "\n" 791 " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 792 " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 793 " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 794 " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 795 " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 796 " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 797 " cgroup/sendmsg4 | cgroup/sendmsg6 }\n" 798 " " HELP_SPEC_OPTIONS "\n" 799 "", 800 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 801 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 802 803 return 0; 804 } 805 806 static const struct cmd cmds[] = { 807 { "show", do_show }, 808 { "list", do_show }, 809 { "help", do_help }, 810 { "dump", do_dump }, 811 { "pin", do_pin }, 812 { "load", do_load }, 813 { 0 } 814 }; 815 816 int do_prog(int argc, char **argv) 817 { 818 return cmd_select(cmds, argc, argv, do_help); 819 } 820