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