linux/tools/bpf/bpftool/prog.c
<<
>>
Prefs
   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
  28static 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
  36static 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
  49static 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
  80static 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
 118int 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
 168static 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
 197static 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
 271static 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
 332static 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
 352static 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
 411static 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) {
 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) {
 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
 649err_free:
 650        free(info_linear);
 651        return -1;
 652}
 653
 654static 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
 664struct map_replace {
 665        int idx;
 666        int fd;
 667        char *name;
 668};
 669
 670static 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
 677static 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
 710static 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
 732static 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
 754static 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
 765static 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
 826err_free:
 827        free(*data_ptr);
 828        *data_ptr = NULL;
 829err_fclose:
 830        if (f != stdin)
 831                fclose(f);
 832        return -1;
 833}
 834
 835static 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
 864static int
 865print_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
 901static 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
 913static 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
1080free_ctx_out:
1081        free(ctx_out);
1082free_ctx_in:
1083        free(ctx_in);
1084free_data_out:
1085        free(data_out);
1086free_data_in:
1087        free(data_in);
1088
1089        return err;
1090}
1091
1092static 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
1360err_unpin:
1361        if (first_prog_only)
1362                unlink(pinfile);
1363        else
1364                bpf_object__unpin_programs(obj, pinfile);
1365err_close_obj:
1366        bpf_object__close(obj);
1367err_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
1374static int do_load(int argc, char **argv)
1375{
1376        return load_with_options(argc, argv, true);
1377}
1378
1379static int do_loadall(int argc, char **argv)
1380{
1381        return load_with_options(argc, argv, false);
1382}
1383
1384static 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
1434static 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
1449int do_prog(int argc, char **argv)
1450{
1451        return cmd_select(cmds, argc, argv, do_help);
1452}
1453