root/tools/bpf/bpftool/prog.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. parse_attach_type
  2. print_boot_time
  3. prog_fd_by_tag
  4. prog_parse_fd
  5. show_prog_maps
  6. print_prog_json
  7. print_prog_plain
  8. show_prog
  9. do_show
  10. do_dump
  11. do_pin
  12. map_replace_compar
  13. parse_attach_detach_args
  14. do_attach
  15. do_detach
  16. check_single_stdin
  17. get_run_data
  18. hex_print
  19. print_run_output
  20. alloc_run_data
  21. do_run
  22. load_with_options
  23. do_load
  24. do_loadall
  25. do_help
  26. do_prog

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

/* [<][>][^][v][top][bottom][index][help] */