1 /* 2 * Copyright (C) 2017 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 /* Author: Jakub Kicinski <kubakici@wp.pl> */ 35 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <stdarg.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 47 #include <bpf.h> 48 #include <libbpf.h> 49 50 #include "main.h" 51 #include "disasm.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 }; 71 72 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 73 { 74 struct timespec real_time_ts, boot_time_ts; 75 time_t wallclock_secs; 76 struct tm load_tm; 77 78 buf[--size] = '\0'; 79 80 if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 81 clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 82 perror("Can't read clocks"); 83 snprintf(buf, size, "%llu", nsecs / 1000000000); 84 return; 85 } 86 87 wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 88 nsecs / 1000000000; 89 90 if (!localtime_r(&wallclock_secs, &load_tm)) { 91 snprintf(buf, size, "%llu", nsecs / 1000000000); 92 return; 93 } 94 95 strftime(buf, size, "%b %d/%H:%M", &load_tm); 96 } 97 98 static int prog_fd_by_tag(unsigned char *tag) 99 { 100 struct bpf_prog_info info = {}; 101 __u32 len = sizeof(info); 102 unsigned int id = 0; 103 int err; 104 int fd; 105 106 while (true) { 107 err = bpf_prog_get_next_id(id, &id); 108 if (err) { 109 p_err("%s", strerror(errno)); 110 return -1; 111 } 112 113 fd = bpf_prog_get_fd_by_id(id); 114 if (fd < 0) { 115 p_err("can't get prog by id (%u): %s", 116 id, strerror(errno)); 117 return -1; 118 } 119 120 err = bpf_obj_get_info_by_fd(fd, &info, &len); 121 if (err) { 122 p_err("can't get prog info (%u): %s", 123 id, strerror(errno)); 124 close(fd); 125 return -1; 126 } 127 128 if (!memcmp(tag, info.tag, BPF_TAG_SIZE)) 129 return fd; 130 131 close(fd); 132 } 133 } 134 135 int prog_parse_fd(int *argc, char ***argv) 136 { 137 int fd; 138 139 if (is_prefix(**argv, "id")) { 140 unsigned int id; 141 char *endptr; 142 143 NEXT_ARGP(); 144 145 id = strtoul(**argv, &endptr, 0); 146 if (*endptr) { 147 p_err("can't parse %s as ID", **argv); 148 return -1; 149 } 150 NEXT_ARGP(); 151 152 fd = bpf_prog_get_fd_by_id(id); 153 if (fd < 0) 154 p_err("get by id (%u): %s", id, strerror(errno)); 155 return fd; 156 } else if (is_prefix(**argv, "tag")) { 157 unsigned char tag[BPF_TAG_SIZE]; 158 159 NEXT_ARGP(); 160 161 if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, 162 tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) 163 != BPF_TAG_SIZE) { 164 p_err("can't parse tag"); 165 return -1; 166 } 167 NEXT_ARGP(); 168 169 return prog_fd_by_tag(tag); 170 } else if (is_prefix(**argv, "pinned")) { 171 char *path; 172 173 NEXT_ARGP(); 174 175 path = **argv; 176 NEXT_ARGP(); 177 178 return open_obj_pinned_any(path, BPF_OBJ_PROG); 179 } 180 181 p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); 182 return -1; 183 } 184 185 static void show_prog_maps(int fd, u32 num_maps) 186 { 187 struct bpf_prog_info info = {}; 188 __u32 len = sizeof(info); 189 __u32 map_ids[num_maps]; 190 unsigned int i; 191 int err; 192 193 info.nr_map_ids = num_maps; 194 info.map_ids = ptr_to_u64(map_ids); 195 196 err = bpf_obj_get_info_by_fd(fd, &info, &len); 197 if (err || !info.nr_map_ids) 198 return; 199 200 if (json_output) { 201 jsonw_name(json_wtr, "map_ids"); 202 jsonw_start_array(json_wtr); 203 for (i = 0; i < info.nr_map_ids; i++) 204 jsonw_uint(json_wtr, map_ids[i]); 205 jsonw_end_array(json_wtr); 206 } else { 207 printf(" map_ids "); 208 for (i = 0; i < info.nr_map_ids; i++) 209 printf("%u%s", map_ids[i], 210 i == info.nr_map_ids - 1 ? "" : ","); 211 } 212 } 213 214 static void print_prog_json(struct bpf_prog_info *info, int fd) 215 { 216 char *memlock; 217 218 jsonw_start_object(json_wtr); 219 jsonw_uint_field(json_wtr, "id", info->id); 220 if (info->type < ARRAY_SIZE(prog_type_name)) 221 jsonw_string_field(json_wtr, "type", 222 prog_type_name[info->type]); 223 else 224 jsonw_uint_field(json_wtr, "type", info->type); 225 226 if (*info->name) 227 jsonw_string_field(json_wtr, "name", info->name); 228 229 jsonw_name(json_wtr, "tag"); 230 jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 231 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 232 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 233 234 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 235 236 if (info->load_time) { 237 char buf[32]; 238 239 print_boot_time(info->load_time, buf, sizeof(buf)); 240 241 /* Piggy back on load_time, since 0 uid is a valid one */ 242 jsonw_string_field(json_wtr, "loaded_at", buf); 243 jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 244 } 245 246 jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 247 248 if (info->jited_prog_len) { 249 jsonw_bool_field(json_wtr, "jited", true); 250 jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 251 } else { 252 jsonw_bool_field(json_wtr, "jited", false); 253 } 254 255 memlock = get_fdinfo(fd, "memlock"); 256 if (memlock) 257 jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 258 free(memlock); 259 260 if (info->nr_map_ids) 261 show_prog_maps(fd, info->nr_map_ids); 262 263 if (!hash_empty(prog_table.table)) { 264 struct pinned_obj *obj; 265 266 jsonw_name(json_wtr, "pinned"); 267 jsonw_start_array(json_wtr); 268 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 269 if (obj->id == info->id) 270 jsonw_string(json_wtr, obj->path); 271 } 272 jsonw_end_array(json_wtr); 273 } 274 275 jsonw_end_object(json_wtr); 276 } 277 278 static void print_prog_plain(struct bpf_prog_info *info, int fd) 279 { 280 char *memlock; 281 282 printf("%u: ", info->id); 283 if (info->type < ARRAY_SIZE(prog_type_name)) 284 printf("%s ", prog_type_name[info->type]); 285 else 286 printf("type %u ", info->type); 287 288 if (*info->name) 289 printf("name %s ", info->name); 290 291 printf("tag "); 292 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 293 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 294 printf("\n"); 295 296 if (info->load_time) { 297 char buf[32]; 298 299 print_boot_time(info->load_time, buf, sizeof(buf)); 300 301 /* Piggy back on load_time, since 0 uid is a valid one */ 302 printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 303 } 304 305 printf("\txlated %uB", info->xlated_prog_len); 306 307 if (info->jited_prog_len) 308 printf(" jited %uB", info->jited_prog_len); 309 else 310 printf(" not jited"); 311 312 memlock = get_fdinfo(fd, "memlock"); 313 if (memlock) 314 printf(" memlock %sB", memlock); 315 free(memlock); 316 317 if (info->nr_map_ids) 318 show_prog_maps(fd, info->nr_map_ids); 319 320 if (!hash_empty(prog_table.table)) { 321 struct pinned_obj *obj; 322 323 printf("\n"); 324 hash_for_each_possible(prog_table.table, obj, hash, info->id) { 325 if (obj->id == info->id) 326 printf("\tpinned %s\n", obj->path); 327 } 328 } 329 330 printf("\n"); 331 } 332 333 static int show_prog(int fd) 334 { 335 struct bpf_prog_info info = {}; 336 __u32 len = sizeof(info); 337 int err; 338 339 err = bpf_obj_get_info_by_fd(fd, &info, &len); 340 if (err) { 341 p_err("can't get prog info: %s", strerror(errno)); 342 return -1; 343 } 344 345 if (json_output) 346 print_prog_json(&info, fd); 347 else 348 print_prog_plain(&info, fd); 349 350 return 0; 351 } 352 353 static int do_show(int argc, char **argv) 354 { 355 __u32 id = 0; 356 int err; 357 int fd; 358 359 if (show_pinned) 360 build_pinned_obj_table(&prog_table, BPF_OBJ_PROG); 361 362 if (argc == 2) { 363 fd = prog_parse_fd(&argc, &argv); 364 if (fd < 0) 365 return -1; 366 367 return show_prog(fd); 368 } 369 370 if (argc) 371 return BAD_ARG(); 372 373 if (json_output) 374 jsonw_start_array(json_wtr); 375 while (true) { 376 err = bpf_prog_get_next_id(id, &id); 377 if (err) { 378 if (errno == ENOENT) { 379 err = 0; 380 break; 381 } 382 p_err("can't get next program: %s%s", strerror(errno), 383 errno == EINVAL ? " -- kernel too old?" : ""); 384 err = -1; 385 break; 386 } 387 388 fd = bpf_prog_get_fd_by_id(id); 389 if (fd < 0) { 390 if (errno == ENOENT) 391 continue; 392 p_err("can't get prog by id (%u): %s", 393 id, strerror(errno)); 394 err = -1; 395 break; 396 } 397 398 err = show_prog(fd); 399 close(fd); 400 if (err) 401 break; 402 } 403 404 if (json_output) 405 jsonw_end_array(json_wtr); 406 407 return err; 408 } 409 410 #define SYM_MAX_NAME 256 411 412 struct kernel_sym { 413 unsigned long address; 414 char name[SYM_MAX_NAME]; 415 }; 416 417 struct dump_data { 418 unsigned long address_call_base; 419 struct kernel_sym *sym_mapping; 420 __u32 sym_count; 421 char scratch_buff[SYM_MAX_NAME]; 422 }; 423 424 static int kernel_syms_cmp(const void *sym_a, const void *sym_b) 425 { 426 return ((struct kernel_sym *)sym_a)->address - 427 ((struct kernel_sym *)sym_b)->address; 428 } 429 430 static void kernel_syms_load(struct dump_data *dd) 431 { 432 struct kernel_sym *sym; 433 char buff[256]; 434 void *tmp, *address; 435 FILE *fp; 436 437 fp = fopen("/proc/kallsyms", "r"); 438 if (!fp) 439 return; 440 441 while (!feof(fp)) { 442 if (!fgets(buff, sizeof(buff), fp)) 443 break; 444 tmp = realloc(dd->sym_mapping, 445 (dd->sym_count + 1) * 446 sizeof(*dd->sym_mapping)); 447 if (!tmp) { 448 out: 449 free(dd->sym_mapping); 450 dd->sym_mapping = NULL; 451 fclose(fp); 452 return; 453 } 454 dd->sym_mapping = tmp; 455 sym = &dd->sym_mapping[dd->sym_count]; 456 if (sscanf(buff, "%p %*c %s", &address, sym->name) != 2) 457 continue; 458 sym->address = (unsigned long)address; 459 if (!strcmp(sym->name, "__bpf_call_base")) { 460 dd->address_call_base = sym->address; 461 /* sysctl kernel.kptr_restrict was set */ 462 if (!sym->address) 463 goto out; 464 } 465 if (sym->address) 466 dd->sym_count++; 467 } 468 469 fclose(fp); 470 471 qsort(dd->sym_mapping, dd->sym_count, 472 sizeof(*dd->sym_mapping), kernel_syms_cmp); 473 } 474 475 static void kernel_syms_destroy(struct dump_data *dd) 476 { 477 free(dd->sym_mapping); 478 } 479 480 static struct kernel_sym *kernel_syms_search(struct dump_data *dd, 481 unsigned long key) 482 { 483 struct kernel_sym sym = { 484 .address = key, 485 }; 486 487 return dd->sym_mapping ? 488 bsearch(&sym, dd->sym_mapping, dd->sym_count, 489 sizeof(*dd->sym_mapping), kernel_syms_cmp) : NULL; 490 } 491 492 static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) 493 { 494 va_list args; 495 496 va_start(args, fmt); 497 vprintf(fmt, args); 498 va_end(args); 499 } 500 501 static const char *print_call_pcrel(struct dump_data *dd, 502 struct kernel_sym *sym, 503 unsigned long address, 504 const struct bpf_insn *insn) 505 { 506 if (sym) 507 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 508 "%+d#%s", insn->off, sym->name); 509 else 510 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 511 "%+d#0x%lx", insn->off, address); 512 return dd->scratch_buff; 513 } 514 515 static const char *print_call_helper(struct dump_data *dd, 516 struct kernel_sym *sym, 517 unsigned long address) 518 { 519 if (sym) 520 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 521 "%s", sym->name); 522 else 523 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 524 "0x%lx", address); 525 return dd->scratch_buff; 526 } 527 528 static const char *print_call(void *private_data, 529 const struct bpf_insn *insn) 530 { 531 struct dump_data *dd = private_data; 532 unsigned long address = dd->address_call_base + insn->imm; 533 struct kernel_sym *sym; 534 535 sym = kernel_syms_search(dd, address); 536 if (insn->src_reg == BPF_PSEUDO_CALL) 537 return print_call_pcrel(dd, sym, address, insn); 538 else 539 return print_call_helper(dd, sym, address); 540 } 541 542 static const char *print_imm(void *private_data, 543 const struct bpf_insn *insn, 544 __u64 full_imm) 545 { 546 struct dump_data *dd = private_data; 547 548 if (insn->src_reg == BPF_PSEUDO_MAP_FD) 549 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 550 "map[id:%u]", insn->imm); 551 else 552 snprintf(dd->scratch_buff, sizeof(dd->scratch_buff), 553 "0x%llx", (unsigned long long)full_imm); 554 return dd->scratch_buff; 555 } 556 557 static void dump_xlated_plain(struct dump_data *dd, void *buf, 558 unsigned int len, bool opcodes) 559 { 560 const struct bpf_insn_cbs cbs = { 561 .cb_print = print_insn, 562 .cb_call = print_call, 563 .cb_imm = print_imm, 564 .private_data = dd, 565 }; 566 struct bpf_insn *insn = buf; 567 bool double_insn = false; 568 unsigned int i; 569 570 for (i = 0; i < len / sizeof(*insn); i++) { 571 if (double_insn) { 572 double_insn = false; 573 continue; 574 } 575 576 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 577 578 printf("% 4d: ", i); 579 print_bpf_insn(&cbs, NULL, insn + i, true); 580 581 if (opcodes) { 582 printf(" "); 583 fprint_hex(stdout, insn + i, 8, " "); 584 if (double_insn && i < len - 1) { 585 printf(" "); 586 fprint_hex(stdout, insn + i + 1, 8, " "); 587 } 588 printf("\n"); 589 } 590 } 591 } 592 593 static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) 594 { 595 unsigned int l = strlen(fmt); 596 char chomped_fmt[l]; 597 va_list args; 598 599 va_start(args, fmt); 600 if (l > 0) { 601 strncpy(chomped_fmt, fmt, l - 1); 602 chomped_fmt[l - 1] = '\0'; 603 } 604 jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); 605 va_end(args); 606 } 607 608 static void dump_xlated_json(struct dump_data *dd, void *buf, 609 unsigned int len, bool opcodes) 610 { 611 const struct bpf_insn_cbs cbs = { 612 .cb_print = print_insn_json, 613 .cb_call = print_call, 614 .cb_imm = print_imm, 615 .private_data = dd, 616 }; 617 struct bpf_insn *insn = buf; 618 bool double_insn = false; 619 unsigned int i; 620 621 jsonw_start_array(json_wtr); 622 for (i = 0; i < len / sizeof(*insn); i++) { 623 if (double_insn) { 624 double_insn = false; 625 continue; 626 } 627 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); 628 629 jsonw_start_object(json_wtr); 630 jsonw_name(json_wtr, "disasm"); 631 print_bpf_insn(&cbs, NULL, insn + i, true); 632 633 if (opcodes) { 634 jsonw_name(json_wtr, "opcodes"); 635 jsonw_start_object(json_wtr); 636 637 jsonw_name(json_wtr, "code"); 638 jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); 639 640 jsonw_name(json_wtr, "src_reg"); 641 jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); 642 643 jsonw_name(json_wtr, "dst_reg"); 644 jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); 645 646 jsonw_name(json_wtr, "off"); 647 print_hex_data_json((uint8_t *)(&insn[i].off), 2); 648 649 jsonw_name(json_wtr, "imm"); 650 if (double_insn && i < len - 1) 651 print_hex_data_json((uint8_t *)(&insn[i].imm), 652 12); 653 else 654 print_hex_data_json((uint8_t *)(&insn[i].imm), 655 4); 656 jsonw_end_object(json_wtr); 657 } 658 jsonw_end_object(json_wtr); 659 } 660 jsonw_end_array(json_wtr); 661 } 662 663 static int do_dump(int argc, char **argv) 664 { 665 struct bpf_prog_info info = {}; 666 struct dump_data dd = {}; 667 __u32 len = sizeof(info); 668 unsigned int buf_size; 669 char *filepath = NULL; 670 bool opcodes = false; 671 unsigned char *buf; 672 __u32 *member_len; 673 __u64 *member_ptr; 674 ssize_t n; 675 int err; 676 int fd; 677 678 if (is_prefix(*argv, "jited")) { 679 member_len = &info.jited_prog_len; 680 member_ptr = &info.jited_prog_insns; 681 } else if (is_prefix(*argv, "xlated")) { 682 member_len = &info.xlated_prog_len; 683 member_ptr = &info.xlated_prog_insns; 684 } else { 685 p_err("expected 'xlated' or 'jited', got: %s", *argv); 686 return -1; 687 } 688 NEXT_ARG(); 689 690 if (argc < 2) 691 usage(); 692 693 fd = prog_parse_fd(&argc, &argv); 694 if (fd < 0) 695 return -1; 696 697 if (is_prefix(*argv, "file")) { 698 NEXT_ARG(); 699 if (!argc) { 700 p_err("expected file path"); 701 return -1; 702 } 703 704 filepath = *argv; 705 NEXT_ARG(); 706 } else if (is_prefix(*argv, "opcodes")) { 707 opcodes = true; 708 NEXT_ARG(); 709 } 710 711 if (argc) { 712 usage(); 713 return -1; 714 } 715 716 err = bpf_obj_get_info_by_fd(fd, &info, &len); 717 if (err) { 718 p_err("can't get prog info: %s", strerror(errno)); 719 return -1; 720 } 721 722 if (!*member_len) { 723 p_info("no instructions returned"); 724 close(fd); 725 return 0; 726 } 727 728 buf_size = *member_len; 729 730 buf = malloc(buf_size); 731 if (!buf) { 732 p_err("mem alloc failed"); 733 close(fd); 734 return -1; 735 } 736 737 memset(&info, 0, sizeof(info)); 738 739 *member_ptr = ptr_to_u64(buf); 740 *member_len = buf_size; 741 742 err = bpf_obj_get_info_by_fd(fd, &info, &len); 743 close(fd); 744 if (err) { 745 p_err("can't get prog info: %s", strerror(errno)); 746 goto err_free; 747 } 748 749 if (*member_len > buf_size) { 750 p_err("too many instructions returned"); 751 goto err_free; 752 } 753 754 if ((member_len == &info.jited_prog_len && 755 info.jited_prog_insns == 0) || 756 (member_len == &info.xlated_prog_len && 757 info.xlated_prog_insns == 0)) { 758 p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 759 goto err_free; 760 } 761 762 if (filepath) { 763 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 764 if (fd < 0) { 765 p_err("can't open file %s: %s", filepath, 766 strerror(errno)); 767 goto err_free; 768 } 769 770 n = write(fd, buf, *member_len); 771 close(fd); 772 if (n != *member_len) { 773 p_err("error writing output file: %s", 774 n < 0 ? strerror(errno) : "short write"); 775 goto err_free; 776 } 777 778 if (json_output) 779 jsonw_null(json_wtr); 780 } else { 781 if (member_len == &info.jited_prog_len) { 782 const char *name = NULL; 783 784 if (info.ifindex) { 785 name = ifindex_to_bfd_name_ns(info.ifindex, 786 info.netns_dev, 787 info.netns_ino); 788 if (!name) 789 goto err_free; 790 } 791 792 disasm_print_insn(buf, *member_len, opcodes, name); 793 } else { 794 kernel_syms_load(&dd); 795 if (json_output) 796 dump_xlated_json(&dd, buf, *member_len, opcodes); 797 else 798 dump_xlated_plain(&dd, buf, *member_len, opcodes); 799 kernel_syms_destroy(&dd); 800 } 801 } 802 803 free(buf); 804 return 0; 805 806 err_free: 807 free(buf); 808 return -1; 809 } 810 811 static int do_pin(int argc, char **argv) 812 { 813 int err; 814 815 err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); 816 if (!err && json_output) 817 jsonw_null(json_wtr); 818 return err; 819 } 820 821 static int do_load(int argc, char **argv) 822 { 823 struct bpf_object *obj; 824 int prog_fd; 825 826 if (argc != 2) 827 usage(); 828 829 if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) { 830 p_err("failed to load program"); 831 return -1; 832 } 833 834 if (do_pin_fd(prog_fd, argv[1])) { 835 p_err("failed to pin program"); 836 return -1; 837 } 838 839 if (json_output) 840 jsonw_null(json_wtr); 841 842 return 0; 843 } 844 845 static int do_help(int argc, char **argv) 846 { 847 if (json_output) { 848 jsonw_null(json_wtr); 849 return 0; 850 } 851 852 fprintf(stderr, 853 "Usage: %s %s { show | list } [PROG]\n" 854 " %s %s dump xlated PROG [{ file FILE | opcodes }]\n" 855 " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 856 " %s %s pin PROG FILE\n" 857 " %s %s load OBJ FILE\n" 858 " %s %s help\n" 859 "\n" 860 " " HELP_SPEC_PROGRAM "\n" 861 " " HELP_SPEC_OPTIONS "\n" 862 "", 863 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], 864 bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]); 865 866 return 0; 867 } 868 869 static const struct cmd cmds[] = { 870 { "show", do_show }, 871 { "list", do_show }, 872 { "help", do_help }, 873 { "dump", do_dump }, 874 { "pin", do_pin }, 875 { "load", do_load }, 876 { 0 } 877 }; 878 879 int do_prog(int argc, char **argv) 880 { 881 return cmd_select(cmds, argc, argv, do_help); 882 } 883