Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
0003 
0004 #define _GNU_SOURCE
0005 #include <errno.h>
0006 #include <fcntl.h>
0007 #include <signal.h>
0008 #include <stdarg.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <time.h>
0013 #include <unistd.h>
0014 #include <net/if.h>
0015 #include <sys/ioctl.h>
0016 #include <sys/types.h>
0017 #include <sys/stat.h>
0018 #include <sys/syscall.h>
0019 #include <dirent.h>
0020 
0021 #include <linux/err.h>
0022 #include <linux/perf_event.h>
0023 #include <linux/sizes.h>
0024 
0025 #include <bpf/bpf.h>
0026 #include <bpf/btf.h>
0027 #include <bpf/hashmap.h>
0028 #include <bpf/libbpf.h>
0029 #include <bpf/libbpf_internal.h>
0030 #include <bpf/skel_internal.h>
0031 
0032 #include "cfg.h"
0033 #include "main.h"
0034 #include "xlated_dumper.h"
0035 
0036 #define BPF_METADATA_PREFIX "bpf_metadata_"
0037 #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1)
0038 
0039 enum dump_mode {
0040     DUMP_JITED,
0041     DUMP_XLATED,
0042 };
0043 
0044 static const bool attach_types[] = {
0045     [BPF_SK_SKB_STREAM_PARSER] = true,
0046     [BPF_SK_SKB_STREAM_VERDICT] = true,
0047     [BPF_SK_SKB_VERDICT] = true,
0048     [BPF_SK_MSG_VERDICT] = true,
0049     [BPF_FLOW_DISSECTOR] = true,
0050     [__MAX_BPF_ATTACH_TYPE] = false,
0051 };
0052 
0053 /* Textual representations traditionally used by the program and kept around
0054  * for the sake of backwards compatibility.
0055  */
0056 static const char * const attach_type_strings[] = {
0057     [BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
0058     [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
0059     [BPF_SK_SKB_VERDICT] = "skb_verdict",
0060     [BPF_SK_MSG_VERDICT] = "msg_verdict",
0061     [__MAX_BPF_ATTACH_TYPE] = NULL,
0062 };
0063 
0064 static struct hashmap *prog_table;
0065 
0066 static enum bpf_attach_type parse_attach_type(const char *str)
0067 {
0068     enum bpf_attach_type type;
0069 
0070     for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
0071         if (attach_types[type]) {
0072             const char *attach_type_str;
0073 
0074             attach_type_str = libbpf_bpf_attach_type_str(type);
0075             if (!strcmp(str, attach_type_str))
0076                 return type;
0077         }
0078 
0079         if (attach_type_strings[type] &&
0080             is_prefix(str, attach_type_strings[type]))
0081             return type;
0082     }
0083 
0084     return __MAX_BPF_ATTACH_TYPE;
0085 }
0086 
0087 static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode,
0088               void **info_data, size_t *const info_data_sz)
0089 {
0090     struct bpf_prog_info holder = {};
0091     size_t needed = 0;
0092     void *ptr;
0093 
0094     if (mode == DUMP_JITED) {
0095         holder.jited_prog_len = info->jited_prog_len;
0096         needed += info->jited_prog_len;
0097     } else {
0098         holder.xlated_prog_len = info->xlated_prog_len;
0099         needed += info->xlated_prog_len;
0100     }
0101 
0102     holder.nr_jited_ksyms = info->nr_jited_ksyms;
0103     needed += info->nr_jited_ksyms * sizeof(__u64);
0104 
0105     holder.nr_jited_func_lens = info->nr_jited_func_lens;
0106     needed += info->nr_jited_func_lens * sizeof(__u32);
0107 
0108     holder.nr_func_info = info->nr_func_info;
0109     holder.func_info_rec_size = info->func_info_rec_size;
0110     needed += info->nr_func_info * info->func_info_rec_size;
0111 
0112     holder.nr_line_info = info->nr_line_info;
0113     holder.line_info_rec_size = info->line_info_rec_size;
0114     needed += info->nr_line_info * info->line_info_rec_size;
0115 
0116     holder.nr_jited_line_info = info->nr_jited_line_info;
0117     holder.jited_line_info_rec_size = info->jited_line_info_rec_size;
0118     needed += info->nr_jited_line_info * info->jited_line_info_rec_size;
0119 
0120     if (needed > *info_data_sz) {
0121         ptr = realloc(*info_data, needed);
0122         if (!ptr)
0123             return -1;
0124 
0125         *info_data = ptr;
0126         *info_data_sz = needed;
0127     }
0128     ptr = *info_data;
0129 
0130     if (mode == DUMP_JITED) {
0131         holder.jited_prog_insns = ptr_to_u64(ptr);
0132         ptr += holder.jited_prog_len;
0133     } else {
0134         holder.xlated_prog_insns = ptr_to_u64(ptr);
0135         ptr += holder.xlated_prog_len;
0136     }
0137 
0138     holder.jited_ksyms = ptr_to_u64(ptr);
0139     ptr += holder.nr_jited_ksyms * sizeof(__u64);
0140 
0141     holder.jited_func_lens = ptr_to_u64(ptr);
0142     ptr += holder.nr_jited_func_lens * sizeof(__u32);
0143 
0144     holder.func_info = ptr_to_u64(ptr);
0145     ptr += holder.nr_func_info * holder.func_info_rec_size;
0146 
0147     holder.line_info = ptr_to_u64(ptr);
0148     ptr += holder.nr_line_info * holder.line_info_rec_size;
0149 
0150     holder.jited_line_info = ptr_to_u64(ptr);
0151     ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size;
0152 
0153     *info = holder;
0154     return 0;
0155 }
0156 
0157 static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
0158 {
0159     struct timespec real_time_ts, boot_time_ts;
0160     time_t wallclock_secs;
0161     struct tm load_tm;
0162 
0163     buf[--size] = '\0';
0164 
0165     if (clock_gettime(CLOCK_REALTIME, &real_time_ts) ||
0166         clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) {
0167         perror("Can't read clocks");
0168         snprintf(buf, size, "%llu", nsecs / 1000000000);
0169         return;
0170     }
0171 
0172     wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) +
0173         (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) /
0174         1000000000;
0175 
0176 
0177     if (!localtime_r(&wallclock_secs, &load_tm)) {
0178         snprintf(buf, size, "%llu", nsecs / 1000000000);
0179         return;
0180     }
0181 
0182     if (json_output)
0183         strftime(buf, size, "%s", &load_tm);
0184     else
0185         strftime(buf, size, "%FT%T%z", &load_tm);
0186 }
0187 
0188 static void show_prog_maps(int fd, __u32 num_maps)
0189 {
0190     struct bpf_prog_info info = {};
0191     __u32 len = sizeof(info);
0192     __u32 map_ids[num_maps];
0193     unsigned int i;
0194     int err;
0195 
0196     info.nr_map_ids = num_maps;
0197     info.map_ids = ptr_to_u64(map_ids);
0198 
0199     err = bpf_obj_get_info_by_fd(fd, &info, &len);
0200     if (err || !info.nr_map_ids)
0201         return;
0202 
0203     if (json_output) {
0204         jsonw_name(json_wtr, "map_ids");
0205         jsonw_start_array(json_wtr);
0206         for (i = 0; i < info.nr_map_ids; i++)
0207             jsonw_uint(json_wtr, map_ids[i]);
0208         jsonw_end_array(json_wtr);
0209     } else {
0210         printf("  map_ids ");
0211         for (i = 0; i < info.nr_map_ids; i++)
0212             printf("%u%s", map_ids[i],
0213                    i == info.nr_map_ids - 1 ? "" : ",");
0214     }
0215 }
0216 
0217 static void *find_metadata(int prog_fd, struct bpf_map_info *map_info)
0218 {
0219     struct bpf_prog_info prog_info;
0220     __u32 prog_info_len;
0221     __u32 map_info_len;
0222     void *value = NULL;
0223     __u32 *map_ids;
0224     int nr_maps;
0225     int key = 0;
0226     int map_fd;
0227     int ret;
0228     __u32 i;
0229 
0230     memset(&prog_info, 0, sizeof(prog_info));
0231     prog_info_len = sizeof(prog_info);
0232     ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
0233     if (ret)
0234         return NULL;
0235 
0236     if (!prog_info.nr_map_ids)
0237         return NULL;
0238 
0239     map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32));
0240     if (!map_ids)
0241         return NULL;
0242 
0243     nr_maps = prog_info.nr_map_ids;
0244     memset(&prog_info, 0, sizeof(prog_info));
0245     prog_info.nr_map_ids = nr_maps;
0246     prog_info.map_ids = ptr_to_u64(map_ids);
0247     prog_info_len = sizeof(prog_info);
0248 
0249     ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
0250     if (ret)
0251         goto free_map_ids;
0252 
0253     for (i = 0; i < prog_info.nr_map_ids; i++) {
0254         map_fd = bpf_map_get_fd_by_id(map_ids[i]);
0255         if (map_fd < 0)
0256             goto free_map_ids;
0257 
0258         memset(map_info, 0, sizeof(*map_info));
0259         map_info_len = sizeof(*map_info);
0260         ret = bpf_obj_get_info_by_fd(map_fd, map_info, &map_info_len);
0261         if (ret < 0) {
0262             close(map_fd);
0263             goto free_map_ids;
0264         }
0265 
0266         if (map_info->type != BPF_MAP_TYPE_ARRAY ||
0267             map_info->key_size != sizeof(int) ||
0268             map_info->max_entries != 1 ||
0269             !map_info->btf_value_type_id ||
0270             !strstr(map_info->name, ".rodata")) {
0271             close(map_fd);
0272             continue;
0273         }
0274 
0275         value = malloc(map_info->value_size);
0276         if (!value) {
0277             close(map_fd);
0278             goto free_map_ids;
0279         }
0280 
0281         if (bpf_map_lookup_elem(map_fd, &key, value)) {
0282             close(map_fd);
0283             free(value);
0284             value = NULL;
0285             goto free_map_ids;
0286         }
0287 
0288         close(map_fd);
0289         break;
0290     }
0291 
0292 free_map_ids:
0293     free(map_ids);
0294     return value;
0295 }
0296 
0297 static bool has_metadata_prefix(const char *s)
0298 {
0299     return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0;
0300 }
0301 
0302 static void show_prog_metadata(int fd, __u32 num_maps)
0303 {
0304     const struct btf_type *t_datasec, *t_var;
0305     struct bpf_map_info map_info;
0306     struct btf_var_secinfo *vsi;
0307     bool printed_header = false;
0308     unsigned int i, vlen;
0309     void *value = NULL;
0310     const char *name;
0311     struct btf *btf;
0312     int err;
0313 
0314     if (!num_maps)
0315         return;
0316 
0317     memset(&map_info, 0, sizeof(map_info));
0318     value = find_metadata(fd, &map_info);
0319     if (!value)
0320         return;
0321 
0322     btf = btf__load_from_kernel_by_id(map_info.btf_id);
0323     if (libbpf_get_error(btf))
0324         goto out_free;
0325 
0326     t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id);
0327     if (!btf_is_datasec(t_datasec))
0328         goto out_free;
0329 
0330     vlen = btf_vlen(t_datasec);
0331     vsi = btf_var_secinfos(t_datasec);
0332 
0333     /* We don't proceed to check the kinds of the elements of the DATASEC.
0334      * The verifier enforces them to be BTF_KIND_VAR.
0335      */
0336 
0337     if (json_output) {
0338         struct btf_dumper d = {
0339             .btf = btf,
0340             .jw = json_wtr,
0341             .is_plain_text = false,
0342         };
0343 
0344         for (i = 0; i < vlen; i++, vsi++) {
0345             t_var = btf__type_by_id(btf, vsi->type);
0346             name = btf__name_by_offset(btf, t_var->name_off);
0347 
0348             if (!has_metadata_prefix(name))
0349                 continue;
0350 
0351             if (!printed_header) {
0352                 jsonw_name(json_wtr, "metadata");
0353                 jsonw_start_object(json_wtr);
0354                 printed_header = true;
0355             }
0356 
0357             jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN);
0358             err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
0359             if (err) {
0360                 p_err("btf dump failed: %d", err);
0361                 break;
0362             }
0363         }
0364         if (printed_header)
0365             jsonw_end_object(json_wtr);
0366     } else {
0367         json_writer_t *btf_wtr;
0368         struct btf_dumper d = {
0369             .btf = btf,
0370             .is_plain_text = true,
0371         };
0372 
0373         for (i = 0; i < vlen; i++, vsi++) {
0374             t_var = btf__type_by_id(btf, vsi->type);
0375             name = btf__name_by_offset(btf, t_var->name_off);
0376 
0377             if (!has_metadata_prefix(name))
0378                 continue;
0379 
0380             if (!printed_header) {
0381                 printf("\tmetadata:");
0382 
0383                 btf_wtr = jsonw_new(stdout);
0384                 if (!btf_wtr) {
0385                     p_err("jsonw alloc failed");
0386                     goto out_free;
0387                 }
0388                 d.jw = btf_wtr,
0389 
0390                 printed_header = true;
0391             }
0392 
0393             printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN);
0394 
0395             jsonw_reset(btf_wtr);
0396             err = btf_dumper_type(&d, t_var->type, value + vsi->offset);
0397             if (err) {
0398                 p_err("btf dump failed: %d", err);
0399                 break;
0400             }
0401         }
0402         if (printed_header)
0403             jsonw_destroy(&btf_wtr);
0404     }
0405 
0406 out_free:
0407     btf__free(btf);
0408     free(value);
0409 }
0410 
0411 static void print_prog_header_json(struct bpf_prog_info *info, int fd)
0412 {
0413     const char *prog_type_str;
0414     char prog_name[MAX_PROG_FULL_NAME];
0415 
0416     jsonw_uint_field(json_wtr, "id", info->id);
0417     prog_type_str = libbpf_bpf_prog_type_str(info->type);
0418 
0419     if (prog_type_str)
0420         jsonw_string_field(json_wtr, "type", prog_type_str);
0421     else
0422         jsonw_uint_field(json_wtr, "type", info->type);
0423 
0424     if (*info->name) {
0425         get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
0426         jsonw_string_field(json_wtr, "name", prog_name);
0427     }
0428 
0429     jsonw_name(json_wtr, "tag");
0430     jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
0431              info->tag[0], info->tag[1], info->tag[2], info->tag[3],
0432              info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
0433 
0434     jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible);
0435     if (info->run_time_ns) {
0436         jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns);
0437         jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt);
0438     }
0439     if (info->recursion_misses)
0440         jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses);
0441 }
0442 
0443 static void print_prog_json(struct bpf_prog_info *info, int fd)
0444 {
0445     char *memlock;
0446 
0447     jsonw_start_object(json_wtr);
0448     print_prog_header_json(info, fd);
0449     print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
0450 
0451     if (info->load_time) {
0452         char buf[32];
0453 
0454         print_boot_time(info->load_time, buf, sizeof(buf));
0455 
0456         /* Piggy back on load_time, since 0 uid is a valid one */
0457         jsonw_name(json_wtr, "loaded_at");
0458         jsonw_printf(json_wtr, "%s", buf);
0459         jsonw_uint_field(json_wtr, "uid", info->created_by_uid);
0460     }
0461 
0462     jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len);
0463 
0464     if (info->jited_prog_len) {
0465         jsonw_bool_field(json_wtr, "jited", true);
0466         jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len);
0467     } else {
0468         jsonw_bool_field(json_wtr, "jited", false);
0469     }
0470 
0471     memlock = get_fdinfo(fd, "memlock");
0472     if (memlock)
0473         jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock));
0474     free(memlock);
0475 
0476     if (info->nr_map_ids)
0477         show_prog_maps(fd, info->nr_map_ids);
0478 
0479     if (info->btf_id)
0480         jsonw_int_field(json_wtr, "btf_id", info->btf_id);
0481 
0482     if (!hashmap__empty(prog_table)) {
0483         struct hashmap_entry *entry;
0484 
0485         jsonw_name(json_wtr, "pinned");
0486         jsonw_start_array(json_wtr);
0487         hashmap__for_each_key_entry(prog_table, entry,
0488                         u32_as_hash_field(info->id))
0489             jsonw_string(json_wtr, entry->value);
0490         jsonw_end_array(json_wtr);
0491     }
0492 
0493     emit_obj_refs_json(refs_table, info->id, json_wtr);
0494 
0495     show_prog_metadata(fd, info->nr_map_ids);
0496 
0497     jsonw_end_object(json_wtr);
0498 }
0499 
0500 static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
0501 {
0502     const char *prog_type_str;
0503     char prog_name[MAX_PROG_FULL_NAME];
0504 
0505     printf("%u: ", info->id);
0506     prog_type_str = libbpf_bpf_prog_type_str(info->type);
0507     if (prog_type_str)
0508         printf("%s  ", prog_type_str);
0509     else
0510         printf("type %u  ", info->type);
0511 
0512     if (*info->name) {
0513         get_prog_full_name(info, fd, prog_name, sizeof(prog_name));
0514         printf("name %s  ", prog_name);
0515     }
0516 
0517     printf("tag ");
0518     fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
0519     print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
0520     printf("%s", info->gpl_compatible ? "  gpl" : "");
0521     if (info->run_time_ns)
0522         printf(" run_time_ns %lld run_cnt %lld",
0523                info->run_time_ns, info->run_cnt);
0524     if (info->recursion_misses)
0525         printf(" recursion_misses %lld", info->recursion_misses);
0526     printf("\n");
0527 }
0528 
0529 static void print_prog_plain(struct bpf_prog_info *info, int fd)
0530 {
0531     char *memlock;
0532 
0533     print_prog_header_plain(info, fd);
0534 
0535     if (info->load_time) {
0536         char buf[32];
0537 
0538         print_boot_time(info->load_time, buf, sizeof(buf));
0539 
0540         /* Piggy back on load_time, since 0 uid is a valid one */
0541         printf("\tloaded_at %s  uid %u\n", buf, info->created_by_uid);
0542     }
0543 
0544     printf("\txlated %uB", info->xlated_prog_len);
0545 
0546     if (info->jited_prog_len)
0547         printf("  jited %uB", info->jited_prog_len);
0548     else
0549         printf("  not jited");
0550 
0551     memlock = get_fdinfo(fd, "memlock");
0552     if (memlock)
0553         printf("  memlock %sB", memlock);
0554     free(memlock);
0555 
0556     if (info->nr_map_ids)
0557         show_prog_maps(fd, info->nr_map_ids);
0558 
0559     if (!hashmap__empty(prog_table)) {
0560         struct hashmap_entry *entry;
0561 
0562         hashmap__for_each_key_entry(prog_table, entry,
0563                         u32_as_hash_field(info->id))
0564             printf("\n\tpinned %s", (char *)entry->value);
0565     }
0566 
0567     if (info->btf_id)
0568         printf("\n\tbtf_id %d", info->btf_id);
0569 
0570     emit_obj_refs_plain(refs_table, info->id, "\n\tpids ");
0571 
0572     printf("\n");
0573 
0574     show_prog_metadata(fd, info->nr_map_ids);
0575 }
0576 
0577 static int show_prog(int fd)
0578 {
0579     struct bpf_prog_info info = {};
0580     __u32 len = sizeof(info);
0581     int err;
0582 
0583     err = bpf_obj_get_info_by_fd(fd, &info, &len);
0584     if (err) {
0585         p_err("can't get prog info: %s", strerror(errno));
0586         return -1;
0587     }
0588 
0589     if (json_output)
0590         print_prog_json(&info, fd);
0591     else
0592         print_prog_plain(&info, fd);
0593 
0594     return 0;
0595 }
0596 
0597 static int do_show_subset(int argc, char **argv)
0598 {
0599     int *fds = NULL;
0600     int nb_fds, i;
0601     int err = -1;
0602 
0603     fds = malloc(sizeof(int));
0604     if (!fds) {
0605         p_err("mem alloc failed");
0606         return -1;
0607     }
0608     nb_fds = prog_parse_fds(&argc, &argv, &fds);
0609     if (nb_fds < 1)
0610         goto exit_free;
0611 
0612     if (json_output && nb_fds > 1)
0613         jsonw_start_array(json_wtr);    /* root array */
0614     for (i = 0; i < nb_fds; i++) {
0615         err = show_prog(fds[i]);
0616         if (err) {
0617             for (; i < nb_fds; i++)
0618                 close(fds[i]);
0619             break;
0620         }
0621         close(fds[i]);
0622     }
0623     if (json_output && nb_fds > 1)
0624         jsonw_end_array(json_wtr);  /* root array */
0625 
0626 exit_free:
0627     free(fds);
0628     return err;
0629 }
0630 
0631 static int do_show(int argc, char **argv)
0632 {
0633     __u32 id = 0;
0634     int err;
0635     int fd;
0636 
0637     if (show_pinned) {
0638         prog_table = hashmap__new(hash_fn_for_key_as_id,
0639                       equal_fn_for_key_as_id, NULL);
0640         if (IS_ERR(prog_table)) {
0641             p_err("failed to create hashmap for pinned paths");
0642             return -1;
0643         }
0644         build_pinned_obj_table(prog_table, BPF_OBJ_PROG);
0645     }
0646     build_obj_refs_table(&refs_table, BPF_OBJ_PROG);
0647 
0648     if (argc == 2)
0649         return do_show_subset(argc, argv);
0650 
0651     if (argc)
0652         return BAD_ARG();
0653 
0654     if (json_output)
0655         jsonw_start_array(json_wtr);
0656     while (true) {
0657         err = bpf_prog_get_next_id(id, &id);
0658         if (err) {
0659             if (errno == ENOENT) {
0660                 err = 0;
0661                 break;
0662             }
0663             p_err("can't get next program: %s%s", strerror(errno),
0664                   errno == EINVAL ? " -- kernel too old?" : "");
0665             err = -1;
0666             break;
0667         }
0668 
0669         fd = bpf_prog_get_fd_by_id(id);
0670         if (fd < 0) {
0671             if (errno == ENOENT)
0672                 continue;
0673             p_err("can't get prog by id (%u): %s",
0674                   id, strerror(errno));
0675             err = -1;
0676             break;
0677         }
0678 
0679         err = show_prog(fd);
0680         close(fd);
0681         if (err)
0682             break;
0683     }
0684 
0685     if (json_output)
0686         jsonw_end_array(json_wtr);
0687 
0688     delete_obj_refs_table(refs_table);
0689 
0690     if (show_pinned)
0691         delete_pinned_obj_table(prog_table);
0692 
0693     return err;
0694 }
0695 
0696 static int
0697 prog_dump(struct bpf_prog_info *info, enum dump_mode mode,
0698       char *filepath, bool opcodes, bool visual, bool linum)
0699 {
0700     struct bpf_prog_linfo *prog_linfo = NULL;
0701     const char *disasm_opt = NULL;
0702     struct dump_data dd = {};
0703     void *func_info = NULL;
0704     struct btf *btf = NULL;
0705     char func_sig[1024];
0706     unsigned char *buf;
0707     __u32 member_len;
0708     int fd, err = -1;
0709     ssize_t n;
0710 
0711     if (mode == DUMP_JITED) {
0712         if (info->jited_prog_len == 0 || !info->jited_prog_insns) {
0713             p_info("no instructions returned");
0714             return -1;
0715         }
0716         buf = u64_to_ptr(info->jited_prog_insns);
0717         member_len = info->jited_prog_len;
0718     } else {    /* DUMP_XLATED */
0719         if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) {
0720             p_err("error retrieving insn dump: kernel.kptr_restrict set?");
0721             return -1;
0722         }
0723         buf = u64_to_ptr(info->xlated_prog_insns);
0724         member_len = info->xlated_prog_len;
0725     }
0726 
0727     if (info->btf_id) {
0728         btf = btf__load_from_kernel_by_id(info->btf_id);
0729         if (libbpf_get_error(btf)) {
0730             p_err("failed to get btf");
0731             return -1;
0732         }
0733     }
0734 
0735     func_info = u64_to_ptr(info->func_info);
0736 
0737     if (info->nr_line_info) {
0738         prog_linfo = bpf_prog_linfo__new(info);
0739         if (!prog_linfo)
0740             p_info("error in processing bpf_line_info.  continue without it.");
0741     }
0742 
0743     if (filepath) {
0744         fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
0745         if (fd < 0) {
0746             p_err("can't open file %s: %s", filepath,
0747                   strerror(errno));
0748             goto exit_free;
0749         }
0750 
0751         n = write(fd, buf, member_len);
0752         close(fd);
0753         if (n != (ssize_t)member_len) {
0754             p_err("error writing output file: %s",
0755                   n < 0 ? strerror(errno) : "short write");
0756             goto exit_free;
0757         }
0758 
0759         if (json_output)
0760             jsonw_null(json_wtr);
0761     } else if (mode == DUMP_JITED) {
0762         const char *name = NULL;
0763 
0764         if (info->ifindex) {
0765             name = ifindex_to_bfd_params(info->ifindex,
0766                              info->netns_dev,
0767                              info->netns_ino,
0768                              &disasm_opt);
0769             if (!name)
0770                 goto exit_free;
0771         }
0772 
0773         if (info->nr_jited_func_lens && info->jited_func_lens) {
0774             struct kernel_sym *sym = NULL;
0775             struct bpf_func_info *record;
0776             char sym_name[SYM_MAX_NAME];
0777             unsigned char *img = buf;
0778             __u64 *ksyms = NULL;
0779             __u32 *lens;
0780             __u32 i;
0781             if (info->nr_jited_ksyms) {
0782                 kernel_syms_load(&dd);
0783                 ksyms = u64_to_ptr(info->jited_ksyms);
0784             }
0785 
0786             if (json_output)
0787                 jsonw_start_array(json_wtr);
0788 
0789             lens = u64_to_ptr(info->jited_func_lens);
0790             for (i = 0; i < info->nr_jited_func_lens; i++) {
0791                 if (ksyms) {
0792                     sym = kernel_syms_search(&dd, ksyms[i]);
0793                     if (sym)
0794                         sprintf(sym_name, "%s", sym->name);
0795                     else
0796                         sprintf(sym_name, "0x%016llx", ksyms[i]);
0797                 } else {
0798                     strcpy(sym_name, "unknown");
0799                 }
0800 
0801                 if (func_info) {
0802                     record = func_info + i * info->func_info_rec_size;
0803                     btf_dumper_type_only(btf, record->type_id,
0804                                  func_sig,
0805                                  sizeof(func_sig));
0806                 }
0807 
0808                 if (json_output) {
0809                     jsonw_start_object(json_wtr);
0810                     if (func_info && func_sig[0] != '\0') {
0811                         jsonw_name(json_wtr, "proto");
0812                         jsonw_string(json_wtr, func_sig);
0813                     }
0814                     jsonw_name(json_wtr, "name");
0815                     jsonw_string(json_wtr, sym_name);
0816                     jsonw_name(json_wtr, "insns");
0817                 } else {
0818                     if (func_info && func_sig[0] != '\0')
0819                         printf("%s:\n", func_sig);
0820                     printf("%s:\n", sym_name);
0821                 }
0822 
0823                 disasm_print_insn(img, lens[i], opcodes,
0824                           name, disasm_opt, btf,
0825                           prog_linfo, ksyms[i], i,
0826                           linum);
0827 
0828                 img += lens[i];
0829 
0830                 if (json_output)
0831                     jsonw_end_object(json_wtr);
0832                 else
0833                     printf("\n");
0834             }
0835 
0836             if (json_output)
0837                 jsonw_end_array(json_wtr);
0838         } else {
0839             disasm_print_insn(buf, member_len, opcodes, name,
0840                       disasm_opt, btf, NULL, 0, 0, false);
0841         }
0842     } else if (visual) {
0843         if (json_output)
0844             jsonw_null(json_wtr);
0845         else
0846             dump_xlated_cfg(buf, member_len);
0847     } else {
0848         kernel_syms_load(&dd);
0849         dd.nr_jited_ksyms = info->nr_jited_ksyms;
0850         dd.jited_ksyms = u64_to_ptr(info->jited_ksyms);
0851         dd.btf = btf;
0852         dd.func_info = func_info;
0853         dd.finfo_rec_size = info->func_info_rec_size;
0854         dd.prog_linfo = prog_linfo;
0855 
0856         if (json_output)
0857             dump_xlated_json(&dd, buf, member_len, opcodes,
0858                      linum);
0859         else
0860             dump_xlated_plain(&dd, buf, member_len, opcodes,
0861                       linum);
0862         kernel_syms_destroy(&dd);
0863     }
0864 
0865     err = 0;
0866 
0867 exit_free:
0868     btf__free(btf);
0869     bpf_prog_linfo__free(prog_linfo);
0870     return err;
0871 }
0872 
0873 static int do_dump(int argc, char **argv)
0874 {
0875     struct bpf_prog_info info;
0876     __u32 info_len = sizeof(info);
0877     size_t info_data_sz = 0;
0878     void *info_data = NULL;
0879     char *filepath = NULL;
0880     bool opcodes = false;
0881     bool visual = false;
0882     enum dump_mode mode;
0883     bool linum = false;
0884     int nb_fds, i = 0;
0885     int *fds = NULL;
0886     int err = -1;
0887 
0888     if (is_prefix(*argv, "jited")) {
0889         if (disasm_init())
0890             return -1;
0891         mode = DUMP_JITED;
0892     } else if (is_prefix(*argv, "xlated")) {
0893         mode = DUMP_XLATED;
0894     } else {
0895         p_err("expected 'xlated' or 'jited', got: %s", *argv);
0896         return -1;
0897     }
0898     NEXT_ARG();
0899 
0900     if (argc < 2)
0901         usage();
0902 
0903     fds = malloc(sizeof(int));
0904     if (!fds) {
0905         p_err("mem alloc failed");
0906         return -1;
0907     }
0908     nb_fds = prog_parse_fds(&argc, &argv, &fds);
0909     if (nb_fds < 1)
0910         goto exit_free;
0911 
0912     if (is_prefix(*argv, "file")) {
0913         NEXT_ARG();
0914         if (!argc) {
0915             p_err("expected file path");
0916             goto exit_close;
0917         }
0918         if (nb_fds > 1) {
0919             p_err("several programs matched");
0920             goto exit_close;
0921         }
0922 
0923         filepath = *argv;
0924         NEXT_ARG();
0925     } else if (is_prefix(*argv, "opcodes")) {
0926         opcodes = true;
0927         NEXT_ARG();
0928     } else if (is_prefix(*argv, "visual")) {
0929         if (nb_fds > 1) {
0930             p_err("several programs matched");
0931             goto exit_close;
0932         }
0933 
0934         visual = true;
0935         NEXT_ARG();
0936     } else if (is_prefix(*argv, "linum")) {
0937         linum = true;
0938         NEXT_ARG();
0939     }
0940 
0941     if (argc) {
0942         usage();
0943         goto exit_close;
0944     }
0945 
0946     if (json_output && nb_fds > 1)
0947         jsonw_start_array(json_wtr);    /* root array */
0948     for (i = 0; i < nb_fds; i++) {
0949         memset(&info, 0, sizeof(info));
0950 
0951         err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len);
0952         if (err) {
0953             p_err("can't get prog info: %s", strerror(errno));
0954             break;
0955         }
0956 
0957         err = prep_prog_info(&info, mode, &info_data, &info_data_sz);
0958         if (err) {
0959             p_err("can't grow prog info_data");
0960             break;
0961         }
0962 
0963         err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len);
0964         if (err) {
0965             p_err("can't get prog info: %s", strerror(errno));
0966             break;
0967         }
0968 
0969         if (json_output && nb_fds > 1) {
0970             jsonw_start_object(json_wtr);   /* prog object */
0971             print_prog_header_json(&info, fds[i]);
0972             jsonw_name(json_wtr, "insns");
0973         } else if (nb_fds > 1) {
0974             print_prog_header_plain(&info, fds[i]);
0975         }
0976 
0977         err = prog_dump(&info, mode, filepath, opcodes, visual, linum);
0978 
0979         if (json_output && nb_fds > 1)
0980             jsonw_end_object(json_wtr); /* prog object */
0981         else if (i != nb_fds - 1 && nb_fds > 1)
0982             printf("\n");
0983 
0984         if (err)
0985             break;
0986         close(fds[i]);
0987     }
0988     if (json_output && nb_fds > 1)
0989         jsonw_end_array(json_wtr);  /* root array */
0990 
0991 exit_close:
0992     for (; i < nb_fds; i++)
0993         close(fds[i]);
0994 exit_free:
0995     free(info_data);
0996     free(fds);
0997     return err;
0998 }
0999 
1000 static int do_pin(int argc, char **argv)
1001 {
1002     int err;
1003 
1004     err = do_pin_any(argc, argv, prog_parse_fd);
1005     if (!err && json_output)
1006         jsonw_null(json_wtr);
1007     return err;
1008 }
1009 
1010 struct map_replace {
1011     int idx;
1012     int fd;
1013     char *name;
1014 };
1015 
1016 static int map_replace_compar(const void *p1, const void *p2)
1017 {
1018     const struct map_replace *a = p1, *b = p2;
1019 
1020     return a->idx - b->idx;
1021 }
1022 
1023 static int parse_attach_detach_args(int argc, char **argv, int *progfd,
1024                     enum bpf_attach_type *attach_type,
1025                     int *mapfd)
1026 {
1027     if (!REQ_ARGS(3))
1028         return -EINVAL;
1029 
1030     *progfd = prog_parse_fd(&argc, &argv);
1031     if (*progfd < 0)
1032         return *progfd;
1033 
1034     *attach_type = parse_attach_type(*argv);
1035     if (*attach_type == __MAX_BPF_ATTACH_TYPE) {
1036         p_err("invalid attach/detach type");
1037         return -EINVAL;
1038     }
1039 
1040     if (*attach_type == BPF_FLOW_DISSECTOR) {
1041         *mapfd = 0;
1042         return 0;
1043     }
1044 
1045     NEXT_ARG();
1046     if (!REQ_ARGS(2))
1047         return -EINVAL;
1048 
1049     *mapfd = map_parse_fd(&argc, &argv);
1050     if (*mapfd < 0)
1051         return *mapfd;
1052 
1053     return 0;
1054 }
1055 
1056 static int do_attach(int argc, char **argv)
1057 {
1058     enum bpf_attach_type attach_type;
1059     int err, progfd;
1060     int mapfd;
1061 
1062     err = parse_attach_detach_args(argc, argv,
1063                        &progfd, &attach_type, &mapfd);
1064     if (err)
1065         return err;
1066 
1067     err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
1068     if (err) {
1069         p_err("failed prog attach to map");
1070         return -EINVAL;
1071     }
1072 
1073     if (json_output)
1074         jsonw_null(json_wtr);
1075     return 0;
1076 }
1077 
1078 static int do_detach(int argc, char **argv)
1079 {
1080     enum bpf_attach_type attach_type;
1081     int err, progfd;
1082     int mapfd;
1083 
1084     err = parse_attach_detach_args(argc, argv,
1085                        &progfd, &attach_type, &mapfd);
1086     if (err)
1087         return err;
1088 
1089     err = bpf_prog_detach2(progfd, mapfd, attach_type);
1090     if (err) {
1091         p_err("failed prog detach from map");
1092         return -EINVAL;
1093     }
1094 
1095     if (json_output)
1096         jsonw_null(json_wtr);
1097     return 0;
1098 }
1099 
1100 static int check_single_stdin(char *file_data_in, char *file_ctx_in)
1101 {
1102     if (file_data_in && file_ctx_in &&
1103         !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) {
1104         p_err("cannot use standard input for both data_in and ctx_in");
1105         return -1;
1106     }
1107 
1108     return 0;
1109 }
1110 
1111 static int get_run_data(const char *fname, void **data_ptr, unsigned int *size)
1112 {
1113     size_t block_size = 256;
1114     size_t buf_size = block_size;
1115     size_t nb_read = 0;
1116     void *tmp;
1117     FILE *f;
1118 
1119     if (!fname) {
1120         *data_ptr = NULL;
1121         *size = 0;
1122         return 0;
1123     }
1124 
1125     if (!strcmp(fname, "-"))
1126         f = stdin;
1127     else
1128         f = fopen(fname, "r");
1129     if (!f) {
1130         p_err("failed to open %s: %s", fname, strerror(errno));
1131         return -1;
1132     }
1133 
1134     *data_ptr = malloc(block_size);
1135     if (!*data_ptr) {
1136         p_err("failed to allocate memory for data_in/ctx_in: %s",
1137               strerror(errno));
1138         goto err_fclose;
1139     }
1140 
1141     while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) {
1142         if (feof(f))
1143             break;
1144         if (ferror(f)) {
1145             p_err("failed to read data_in/ctx_in from %s: %s",
1146                   fname, strerror(errno));
1147             goto err_free;
1148         }
1149         if (nb_read > buf_size - block_size) {
1150             if (buf_size == UINT32_MAX) {
1151                 p_err("data_in/ctx_in is too long (max: %d)",
1152                       UINT32_MAX);
1153                 goto err_free;
1154             }
1155             /* No space for fread()-ing next chunk; realloc() */
1156             buf_size *= 2;
1157             tmp = realloc(*data_ptr, buf_size);
1158             if (!tmp) {
1159                 p_err("failed to reallocate data_in/ctx_in: %s",
1160                       strerror(errno));
1161                 goto err_free;
1162             }
1163             *data_ptr = tmp;
1164         }
1165     }
1166     if (f != stdin)
1167         fclose(f);
1168 
1169     *size = nb_read;
1170     return 0;
1171 
1172 err_free:
1173     free(*data_ptr);
1174     *data_ptr = NULL;
1175 err_fclose:
1176     if (f != stdin)
1177         fclose(f);
1178     return -1;
1179 }
1180 
1181 static void hex_print(void *data, unsigned int size, FILE *f)
1182 {
1183     size_t i, j;
1184     char c;
1185 
1186     for (i = 0; i < size; i += 16) {
1187         /* Row offset */
1188         fprintf(f, "%07zx\t", i);
1189 
1190         /* Hexadecimal values */
1191         for (j = i; j < i + 16 && j < size; j++)
1192             fprintf(f, "%02x%s", *(uint8_t *)(data + j),
1193                 j % 2 ? " " : "");
1194         for (; j < i + 16; j++)
1195             fprintf(f, "  %s", j % 2 ? " " : "");
1196 
1197         /* ASCII values (if relevant), '.' otherwise */
1198         fprintf(f, "| ");
1199         for (j = i; j < i + 16 && j < size; j++) {
1200             c = *(char *)(data + j);
1201             if (c < ' ' || c > '~')
1202                 c = '.';
1203             fprintf(f, "%c%s", c, j == i + 7 ? " " : "");
1204         }
1205 
1206         fprintf(f, "\n");
1207     }
1208 }
1209 
1210 static int
1211 print_run_output(void *data, unsigned int size, const char *fname,
1212          const char *json_key)
1213 {
1214     size_t nb_written;
1215     FILE *f;
1216 
1217     if (!fname)
1218         return 0;
1219 
1220     if (!strcmp(fname, "-")) {
1221         f = stdout;
1222         if (json_output) {
1223             jsonw_name(json_wtr, json_key);
1224             print_data_json(data, size);
1225         } else {
1226             hex_print(data, size, f);
1227         }
1228         return 0;
1229     }
1230 
1231     f = fopen(fname, "w");
1232     if (!f) {
1233         p_err("failed to open %s: %s", fname, strerror(errno));
1234         return -1;
1235     }
1236 
1237     nb_written = fwrite(data, 1, size, f);
1238     fclose(f);
1239     if (nb_written != size) {
1240         p_err("failed to write output data/ctx: %s", strerror(errno));
1241         return -1;
1242     }
1243 
1244     return 0;
1245 }
1246 
1247 static int alloc_run_data(void **data_ptr, unsigned int size_out)
1248 {
1249     *data_ptr = calloc(size_out, 1);
1250     if (!*data_ptr) {
1251         p_err("failed to allocate memory for output data/ctx: %s",
1252               strerror(errno));
1253         return -1;
1254     }
1255 
1256     return 0;
1257 }
1258 
1259 static int do_run(int argc, char **argv)
1260 {
1261     char *data_fname_in = NULL, *data_fname_out = NULL;
1262     char *ctx_fname_in = NULL, *ctx_fname_out = NULL;
1263     const unsigned int default_size = SZ_32K;
1264     void *data_in = NULL, *data_out = NULL;
1265     void *ctx_in = NULL, *ctx_out = NULL;
1266     unsigned int repeat = 1;
1267     int fd, err;
1268     LIBBPF_OPTS(bpf_test_run_opts, test_attr);
1269 
1270     if (!REQ_ARGS(4))
1271         return -1;
1272 
1273     fd = prog_parse_fd(&argc, &argv);
1274     if (fd < 0)
1275         return -1;
1276 
1277     while (argc) {
1278         if (detect_common_prefix(*argv, "data_in", "data_out",
1279                      "data_size_out", NULL))
1280             return -1;
1281         if (detect_common_prefix(*argv, "ctx_in", "ctx_out",
1282                      "ctx_size_out", NULL))
1283             return -1;
1284 
1285         if (is_prefix(*argv, "data_in")) {
1286             NEXT_ARG();
1287             if (!REQ_ARGS(1))
1288                 return -1;
1289 
1290             data_fname_in = GET_ARG();
1291             if (check_single_stdin(data_fname_in, ctx_fname_in))
1292                 return -1;
1293         } else if (is_prefix(*argv, "data_out")) {
1294             NEXT_ARG();
1295             if (!REQ_ARGS(1))
1296                 return -1;
1297 
1298             data_fname_out = GET_ARG();
1299         } else if (is_prefix(*argv, "data_size_out")) {
1300             char *endptr;
1301 
1302             NEXT_ARG();
1303             if (!REQ_ARGS(1))
1304                 return -1;
1305 
1306             test_attr.data_size_out = strtoul(*argv, &endptr, 0);
1307             if (*endptr) {
1308                 p_err("can't parse %s as output data size",
1309                       *argv);
1310                 return -1;
1311             }
1312             NEXT_ARG();
1313         } else if (is_prefix(*argv, "ctx_in")) {
1314             NEXT_ARG();
1315             if (!REQ_ARGS(1))
1316                 return -1;
1317 
1318             ctx_fname_in = GET_ARG();
1319             if (check_single_stdin(data_fname_in, ctx_fname_in))
1320                 return -1;
1321         } else if (is_prefix(*argv, "ctx_out")) {
1322             NEXT_ARG();
1323             if (!REQ_ARGS(1))
1324                 return -1;
1325 
1326             ctx_fname_out = GET_ARG();
1327         } else if (is_prefix(*argv, "ctx_size_out")) {
1328             char *endptr;
1329 
1330             NEXT_ARG();
1331             if (!REQ_ARGS(1))
1332                 return -1;
1333 
1334             test_attr.ctx_size_out = strtoul(*argv, &endptr, 0);
1335             if (*endptr) {
1336                 p_err("can't parse %s as output context size",
1337                       *argv);
1338                 return -1;
1339             }
1340             NEXT_ARG();
1341         } else if (is_prefix(*argv, "repeat")) {
1342             char *endptr;
1343 
1344             NEXT_ARG();
1345             if (!REQ_ARGS(1))
1346                 return -1;
1347 
1348             repeat = strtoul(*argv, &endptr, 0);
1349             if (*endptr) {
1350                 p_err("can't parse %s as repeat number",
1351                       *argv);
1352                 return -1;
1353             }
1354             NEXT_ARG();
1355         } else {
1356             p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?",
1357                   *argv);
1358             return -1;
1359         }
1360     }
1361 
1362     err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in);
1363     if (err)
1364         return -1;
1365 
1366     if (data_in) {
1367         if (!test_attr.data_size_out)
1368             test_attr.data_size_out = default_size;
1369         err = alloc_run_data(&data_out, test_attr.data_size_out);
1370         if (err)
1371             goto free_data_in;
1372     }
1373 
1374     err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in);
1375     if (err)
1376         goto free_data_out;
1377 
1378     if (ctx_in) {
1379         if (!test_attr.ctx_size_out)
1380             test_attr.ctx_size_out = default_size;
1381         err = alloc_run_data(&ctx_out, test_attr.ctx_size_out);
1382         if (err)
1383             goto free_ctx_in;
1384     }
1385 
1386     test_attr.repeat    = repeat;
1387     test_attr.data_in   = data_in;
1388     test_attr.data_out  = data_out;
1389     test_attr.ctx_in    = ctx_in;
1390     test_attr.ctx_out   = ctx_out;
1391 
1392     err = bpf_prog_test_run_opts(fd, &test_attr);
1393     if (err) {
1394         p_err("failed to run program: %s", strerror(errno));
1395         goto free_ctx_out;
1396     }
1397 
1398     err = 0;
1399 
1400     if (json_output)
1401         jsonw_start_object(json_wtr);   /* root */
1402 
1403     /* Do not exit on errors occurring when printing output data/context,
1404      * we still want to print return value and duration for program run.
1405      */
1406     if (test_attr.data_size_out)
1407         err += print_run_output(test_attr.data_out,
1408                     test_attr.data_size_out,
1409                     data_fname_out, "data_out");
1410     if (test_attr.ctx_size_out)
1411         err += print_run_output(test_attr.ctx_out,
1412                     test_attr.ctx_size_out,
1413                     ctx_fname_out, "ctx_out");
1414 
1415     if (json_output) {
1416         jsonw_uint_field(json_wtr, "retval", test_attr.retval);
1417         jsonw_uint_field(json_wtr, "duration", test_attr.duration);
1418         jsonw_end_object(json_wtr); /* root */
1419     } else {
1420         fprintf(stdout, "Return value: %u, duration%s: %uns\n",
1421             test_attr.retval,
1422             repeat > 1 ? " (average)" : "", test_attr.duration);
1423     }
1424 
1425 free_ctx_out:
1426     free(ctx_out);
1427 free_ctx_in:
1428     free(ctx_in);
1429 free_data_out:
1430     free(data_out);
1431 free_data_in:
1432     free(data_in);
1433 
1434     return err;
1435 }
1436 
1437 static int
1438 get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type,
1439               enum bpf_attach_type *expected_attach_type)
1440 {
1441     libbpf_print_fn_t print_backup;
1442     int ret;
1443 
1444     ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type);
1445     if (!ret)
1446         return ret;
1447 
1448     /* libbpf_prog_type_by_name() failed, let's re-run with debug level */
1449     print_backup = libbpf_set_print(print_all_levels);
1450     ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type);
1451     libbpf_set_print(print_backup);
1452 
1453     return ret;
1454 }
1455 
1456 static int load_with_options(int argc, char **argv, bool first_prog_only)
1457 {
1458     enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC;
1459     DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts,
1460         .relaxed_maps = relaxed_maps,
1461     );
1462     enum bpf_attach_type expected_attach_type;
1463     struct map_replace *map_replace = NULL;
1464     struct bpf_program *prog = NULL, *pos;
1465     unsigned int old_map_fds = 0;
1466     const char *pinmaps = NULL;
1467     struct bpf_object *obj;
1468     struct bpf_map *map;
1469     const char *pinfile;
1470     unsigned int i, j;
1471     __u32 ifindex = 0;
1472     const char *file;
1473     int idx, err;
1474 
1475 
1476     if (!REQ_ARGS(2))
1477         return -1;
1478     file = GET_ARG();
1479     pinfile = GET_ARG();
1480 
1481     while (argc) {
1482         if (is_prefix(*argv, "type")) {
1483             NEXT_ARG();
1484 
1485             if (common_prog_type != BPF_PROG_TYPE_UNSPEC) {
1486                 p_err("program type already specified");
1487                 goto err_free_reuse_maps;
1488             }
1489             if (!REQ_ARGS(1))
1490                 goto err_free_reuse_maps;
1491 
1492             err = libbpf_prog_type_by_name(*argv, &common_prog_type,
1493                                &expected_attach_type);
1494             if (err < 0) {
1495                 /* Put a '/' at the end of type to appease libbpf */
1496                 char *type = malloc(strlen(*argv) + 2);
1497 
1498                 if (!type) {
1499                     p_err("mem alloc failed");
1500                     goto err_free_reuse_maps;
1501                 }
1502                 *type = 0;
1503                 strcat(type, *argv);
1504                 strcat(type, "/");
1505 
1506                 err = get_prog_type_by_name(type, &common_prog_type,
1507                                 &expected_attach_type);
1508                 free(type);
1509                 if (err < 0)
1510                     goto err_free_reuse_maps;
1511             }
1512 
1513             NEXT_ARG();
1514         } else if (is_prefix(*argv, "map")) {
1515             void *new_map_replace;
1516             char *endptr, *name;
1517             int fd;
1518 
1519             NEXT_ARG();
1520 
1521             if (!REQ_ARGS(4))
1522                 goto err_free_reuse_maps;
1523 
1524             if (is_prefix(*argv, "idx")) {
1525                 NEXT_ARG();
1526 
1527                 idx = strtoul(*argv, &endptr, 0);
1528                 if (*endptr) {
1529                     p_err("can't parse %s as IDX", *argv);
1530                     goto err_free_reuse_maps;
1531                 }
1532                 name = NULL;
1533             } else if (is_prefix(*argv, "name")) {
1534                 NEXT_ARG();
1535 
1536                 name = *argv;
1537                 idx = -1;
1538             } else {
1539                 p_err("expected 'idx' or 'name', got: '%s'?",
1540                       *argv);
1541                 goto err_free_reuse_maps;
1542             }
1543             NEXT_ARG();
1544 
1545             fd = map_parse_fd(&argc, &argv);
1546             if (fd < 0)
1547                 goto err_free_reuse_maps;
1548 
1549             new_map_replace = libbpf_reallocarray(map_replace,
1550                                   old_map_fds + 1,
1551                                   sizeof(*map_replace));
1552             if (!new_map_replace) {
1553                 p_err("mem alloc failed");
1554                 goto err_free_reuse_maps;
1555             }
1556             map_replace = new_map_replace;
1557 
1558             map_replace[old_map_fds].idx = idx;
1559             map_replace[old_map_fds].name = name;
1560             map_replace[old_map_fds].fd = fd;
1561             old_map_fds++;
1562         } else if (is_prefix(*argv, "dev")) {
1563             NEXT_ARG();
1564 
1565             if (ifindex) {
1566                 p_err("offload device already specified");
1567                 goto err_free_reuse_maps;
1568             }
1569             if (!REQ_ARGS(1))
1570                 goto err_free_reuse_maps;
1571 
1572             ifindex = if_nametoindex(*argv);
1573             if (!ifindex) {
1574                 p_err("unrecognized netdevice '%s': %s",
1575                       *argv, strerror(errno));
1576                 goto err_free_reuse_maps;
1577             }
1578             NEXT_ARG();
1579         } else if (is_prefix(*argv, "pinmaps")) {
1580             NEXT_ARG();
1581 
1582             if (!REQ_ARGS(1))
1583                 goto err_free_reuse_maps;
1584 
1585             pinmaps = GET_ARG();
1586         } else {
1587             p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
1588                   *argv);
1589             goto err_free_reuse_maps;
1590         }
1591     }
1592 
1593     set_max_rlimit();
1594 
1595     if (verifier_logs)
1596         /* log_level1 + log_level2 + stats, but not stable UAPI */
1597         open_opts.kernel_log_level = 1 + 2 + 4;
1598 
1599     obj = bpf_object__open_file(file, &open_opts);
1600     if (libbpf_get_error(obj)) {
1601         p_err("failed to open object file");
1602         goto err_free_reuse_maps;
1603     }
1604 
1605     bpf_object__for_each_program(pos, obj) {
1606         enum bpf_prog_type prog_type = common_prog_type;
1607 
1608         if (prog_type == BPF_PROG_TYPE_UNSPEC) {
1609             const char *sec_name = bpf_program__section_name(pos);
1610 
1611             err = get_prog_type_by_name(sec_name, &prog_type,
1612                             &expected_attach_type);
1613             if (err < 0)
1614                 goto err_close_obj;
1615         }
1616 
1617         bpf_program__set_ifindex(pos, ifindex);
1618         bpf_program__set_type(pos, prog_type);
1619         bpf_program__set_expected_attach_type(pos, expected_attach_type);
1620     }
1621 
1622     qsort(map_replace, old_map_fds, sizeof(*map_replace),
1623           map_replace_compar);
1624 
1625     /* After the sort maps by name will be first on the list, because they
1626      * have idx == -1.  Resolve them.
1627      */
1628     j = 0;
1629     while (j < old_map_fds && map_replace[j].name) {
1630         i = 0;
1631         bpf_object__for_each_map(map, obj) {
1632             if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
1633                 map_replace[j].idx = i;
1634                 break;
1635             }
1636             i++;
1637         }
1638         if (map_replace[j].idx == -1) {
1639             p_err("unable to find map '%s'", map_replace[j].name);
1640             goto err_close_obj;
1641         }
1642         j++;
1643     }
1644     /* Resort if any names were resolved */
1645     if (j)
1646         qsort(map_replace, old_map_fds, sizeof(*map_replace),
1647               map_replace_compar);
1648 
1649     /* Set ifindex and name reuse */
1650     j = 0;
1651     idx = 0;
1652     bpf_object__for_each_map(map, obj) {
1653         if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
1654             bpf_map__set_ifindex(map, ifindex);
1655 
1656         if (j < old_map_fds && idx == map_replace[j].idx) {
1657             err = bpf_map__reuse_fd(map, map_replace[j++].fd);
1658             if (err) {
1659                 p_err("unable to set up map reuse: %d", err);
1660                 goto err_close_obj;
1661             }
1662 
1663             /* Next reuse wants to apply to the same map */
1664             if (j < old_map_fds && map_replace[j].idx == idx) {
1665                 p_err("replacement for map idx %d specified more than once",
1666                       idx);
1667                 goto err_close_obj;
1668             }
1669         }
1670 
1671         idx++;
1672     }
1673     if (j < old_map_fds) {
1674         p_err("map idx '%d' not used", map_replace[j].idx);
1675         goto err_close_obj;
1676     }
1677 
1678     err = bpf_object__load(obj);
1679     if (err) {
1680         p_err("failed to load object file");
1681         goto err_close_obj;
1682     }
1683 
1684     err = mount_bpffs_for_pin(pinfile);
1685     if (err)
1686         goto err_close_obj;
1687 
1688     if (first_prog_only) {
1689         prog = bpf_object__next_program(obj, NULL);
1690         if (!prog) {
1691             p_err("object file doesn't contain any bpf program");
1692             goto err_close_obj;
1693         }
1694 
1695         err = bpf_obj_pin(bpf_program__fd(prog), pinfile);
1696         if (err) {
1697             p_err("failed to pin program %s",
1698                   bpf_program__section_name(prog));
1699             goto err_close_obj;
1700         }
1701     } else {
1702         err = bpf_object__pin_programs(obj, pinfile);
1703         if (err) {
1704             p_err("failed to pin all programs");
1705             goto err_close_obj;
1706         }
1707     }
1708 
1709     if (pinmaps) {
1710         err = bpf_object__pin_maps(obj, pinmaps);
1711         if (err) {
1712             p_err("failed to pin all maps");
1713             goto err_unpin;
1714         }
1715     }
1716 
1717     if (json_output)
1718         jsonw_null(json_wtr);
1719 
1720     bpf_object__close(obj);
1721     for (i = 0; i < old_map_fds; i++)
1722         close(map_replace[i].fd);
1723     free(map_replace);
1724 
1725     return 0;
1726 
1727 err_unpin:
1728     if (first_prog_only)
1729         unlink(pinfile);
1730     else
1731         bpf_object__unpin_programs(obj, pinfile);
1732 err_close_obj:
1733     if (!legacy_libbpf) {
1734         p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n"
1735                "If it used to work for this object file but now doesn't, see --legacy option for more details.\n");
1736     }
1737 
1738     bpf_object__close(obj);
1739 err_free_reuse_maps:
1740     for (i = 0; i < old_map_fds; i++)
1741         close(map_replace[i].fd);
1742     free(map_replace);
1743     return -1;
1744 }
1745 
1746 static int count_open_fds(void)
1747 {
1748     DIR *dp = opendir("/proc/self/fd");
1749     struct dirent *de;
1750     int cnt = -3;
1751 
1752     if (!dp)
1753         return -1;
1754 
1755     while ((de = readdir(dp)))
1756         cnt++;
1757 
1758     closedir(dp);
1759     return cnt;
1760 }
1761 
1762 static int try_loader(struct gen_loader_opts *gen)
1763 {
1764     struct bpf_load_and_run_opts opts = {};
1765     struct bpf_loader_ctx *ctx;
1766     int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc),
1767                          sizeof(struct bpf_prog_desc));
1768     int log_buf_sz = (1u << 24) - 1;
1769     int err, fds_before, fd_delta;
1770     char *log_buf = NULL;
1771 
1772     ctx = alloca(ctx_sz);
1773     memset(ctx, 0, ctx_sz);
1774     ctx->sz = ctx_sz;
1775     if (verifier_logs) {
1776         ctx->log_level = 1 + 2 + 4;
1777         ctx->log_size = log_buf_sz;
1778         log_buf = malloc(log_buf_sz);
1779         if (!log_buf)
1780             return -ENOMEM;
1781         ctx->log_buf = (long) log_buf;
1782     }
1783     opts.ctx = ctx;
1784     opts.data = gen->data;
1785     opts.data_sz = gen->data_sz;
1786     opts.insns = gen->insns;
1787     opts.insns_sz = gen->insns_sz;
1788     fds_before = count_open_fds();
1789     err = bpf_load_and_run(&opts);
1790     fd_delta = count_open_fds() - fds_before;
1791     if (err < 0 || verifier_logs) {
1792         fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf);
1793         if (fd_delta && err < 0)
1794             fprintf(stderr, "loader prog leaked %d FDs\n",
1795                 fd_delta);
1796     }
1797     free(log_buf);
1798     return err;
1799 }
1800 
1801 static int do_loader(int argc, char **argv)
1802 {
1803     DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts);
1804     DECLARE_LIBBPF_OPTS(gen_loader_opts, gen);
1805     struct bpf_object *obj;
1806     const char *file;
1807     int err = 0;
1808 
1809     if (!REQ_ARGS(1))
1810         return -1;
1811     file = GET_ARG();
1812 
1813     if (verifier_logs)
1814         /* log_level1 + log_level2 + stats, but not stable UAPI */
1815         open_opts.kernel_log_level = 1 + 2 + 4;
1816 
1817     obj = bpf_object__open_file(file, &open_opts);
1818     if (libbpf_get_error(obj)) {
1819         p_err("failed to open object file");
1820         goto err_close_obj;
1821     }
1822 
1823     err = bpf_object__gen_loader(obj, &gen);
1824     if (err)
1825         goto err_close_obj;
1826 
1827     err = bpf_object__load(obj);
1828     if (err) {
1829         p_err("failed to load object file");
1830         goto err_close_obj;
1831     }
1832 
1833     if (verifier_logs) {
1834         struct dump_data dd = {};
1835 
1836         kernel_syms_load(&dd);
1837         dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false);
1838         kernel_syms_destroy(&dd);
1839     }
1840     err = try_loader(&gen);
1841 err_close_obj:
1842     bpf_object__close(obj);
1843     return err;
1844 }
1845 
1846 static int do_load(int argc, char **argv)
1847 {
1848     if (use_loader)
1849         return do_loader(argc, argv);
1850     return load_with_options(argc, argv, true);
1851 }
1852 
1853 static int do_loadall(int argc, char **argv)
1854 {
1855     return load_with_options(argc, argv, false);
1856 }
1857 
1858 #ifdef BPFTOOL_WITHOUT_SKELETONS
1859 
1860 static int do_profile(int argc, char **argv)
1861 {
1862     p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0");
1863     return 0;
1864 }
1865 
1866 #else /* BPFTOOL_WITHOUT_SKELETONS */
1867 
1868 #include "profiler.skel.h"
1869 
1870 struct profile_metric {
1871     const char *name;
1872     struct bpf_perf_event_value val;
1873     struct perf_event_attr attr;
1874     bool selected;
1875 
1876     /* calculate ratios like instructions per cycle */
1877     const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */
1878     const char *ratio_desc;
1879     const float ratio_mul;
1880 } metrics[] = {
1881     {
1882         .name = "cycles",
1883         .attr = {
1884             .type = PERF_TYPE_HARDWARE,
1885             .config = PERF_COUNT_HW_CPU_CYCLES,
1886             .exclude_user = 1,
1887         },
1888     },
1889     {
1890         .name = "instructions",
1891         .attr = {
1892             .type = PERF_TYPE_HARDWARE,
1893             .config = PERF_COUNT_HW_INSTRUCTIONS,
1894             .exclude_user = 1,
1895         },
1896         .ratio_metric = 1,
1897         .ratio_desc = "insns per cycle",
1898         .ratio_mul = 1.0,
1899     },
1900     {
1901         .name = "l1d_loads",
1902         .attr = {
1903             .type = PERF_TYPE_HW_CACHE,
1904             .config =
1905                 PERF_COUNT_HW_CACHE_L1D |
1906                 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1907                 (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
1908             .exclude_user = 1,
1909         },
1910     },
1911     {
1912         .name = "llc_misses",
1913         .attr = {
1914             .type = PERF_TYPE_HW_CACHE,
1915             .config =
1916                 PERF_COUNT_HW_CACHE_LL |
1917                 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1918                 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
1919             .exclude_user = 1
1920         },
1921         .ratio_metric = 2,
1922         .ratio_desc = "LLC misses per million insns",
1923         .ratio_mul = 1e6,
1924     },
1925     {
1926         .name = "itlb_misses",
1927         .attr = {
1928             .type = PERF_TYPE_HW_CACHE,
1929             .config =
1930                 PERF_COUNT_HW_CACHE_ITLB |
1931                 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1932                 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
1933             .exclude_user = 1
1934         },
1935         .ratio_metric = 2,
1936         .ratio_desc = "itlb misses per million insns",
1937         .ratio_mul = 1e6,
1938     },
1939     {
1940         .name = "dtlb_misses",
1941         .attr = {
1942             .type = PERF_TYPE_HW_CACHE,
1943             .config =
1944                 PERF_COUNT_HW_CACHE_DTLB |
1945                 (PERF_COUNT_HW_CACHE_OP_READ << 8) |
1946                 (PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
1947             .exclude_user = 1
1948         },
1949         .ratio_metric = 2,
1950         .ratio_desc = "dtlb misses per million insns",
1951         .ratio_mul = 1e6,
1952     },
1953 };
1954 
1955 static __u64 profile_total_count;
1956 
1957 #define MAX_NUM_PROFILE_METRICS 4
1958 
1959 static int profile_parse_metrics(int argc, char **argv)
1960 {
1961     unsigned int metric_cnt;
1962     int selected_cnt = 0;
1963     unsigned int i;
1964 
1965     metric_cnt = ARRAY_SIZE(metrics);
1966 
1967     while (argc > 0) {
1968         for (i = 0; i < metric_cnt; i++) {
1969             if (is_prefix(argv[0], metrics[i].name)) {
1970                 if (!metrics[i].selected)
1971                     selected_cnt++;
1972                 metrics[i].selected = true;
1973                 break;
1974             }
1975         }
1976         if (i == metric_cnt) {
1977             p_err("unknown metric %s", argv[0]);
1978             return -1;
1979         }
1980         NEXT_ARG();
1981     }
1982     if (selected_cnt > MAX_NUM_PROFILE_METRICS) {
1983         p_err("too many (%d) metrics, please specify no more than %d metrics at at time",
1984               selected_cnt, MAX_NUM_PROFILE_METRICS);
1985         return -1;
1986     }
1987     return selected_cnt;
1988 }
1989 
1990 static void profile_read_values(struct profiler_bpf *obj)
1991 {
1992     __u32 m, cpu, num_cpu = obj->rodata->num_cpu;
1993     int reading_map_fd, count_map_fd;
1994     __u64 counts[num_cpu];
1995     __u32 key = 0;
1996     int err;
1997 
1998     reading_map_fd = bpf_map__fd(obj->maps.accum_readings);
1999     count_map_fd = bpf_map__fd(obj->maps.counts);
2000     if (reading_map_fd < 0 || count_map_fd < 0) {
2001         p_err("failed to get fd for map");
2002         return;
2003     }
2004 
2005     err = bpf_map_lookup_elem(count_map_fd, &key, counts);
2006     if (err) {
2007         p_err("failed to read count_map: %s", strerror(errno));
2008         return;
2009     }
2010 
2011     profile_total_count = 0;
2012     for (cpu = 0; cpu < num_cpu; cpu++)
2013         profile_total_count += counts[cpu];
2014 
2015     for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2016         struct bpf_perf_event_value values[num_cpu];
2017 
2018         if (!metrics[m].selected)
2019             continue;
2020 
2021         err = bpf_map_lookup_elem(reading_map_fd, &key, values);
2022         if (err) {
2023             p_err("failed to read reading_map: %s",
2024                   strerror(errno));
2025             return;
2026         }
2027         for (cpu = 0; cpu < num_cpu; cpu++) {
2028             metrics[m].val.counter += values[cpu].counter;
2029             metrics[m].val.enabled += values[cpu].enabled;
2030             metrics[m].val.running += values[cpu].running;
2031         }
2032         key++;
2033     }
2034 }
2035 
2036 static void profile_print_readings_json(void)
2037 {
2038     __u32 m;
2039 
2040     jsonw_start_array(json_wtr);
2041     for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2042         if (!metrics[m].selected)
2043             continue;
2044         jsonw_start_object(json_wtr);
2045         jsonw_string_field(json_wtr, "metric", metrics[m].name);
2046         jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count);
2047         jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter);
2048         jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled);
2049         jsonw_lluint_field(json_wtr, "running", metrics[m].val.running);
2050 
2051         jsonw_end_object(json_wtr);
2052     }
2053     jsonw_end_array(json_wtr);
2054 }
2055 
2056 static void profile_print_readings_plain(void)
2057 {
2058     __u32 m;
2059 
2060     printf("\n%18llu %-20s\n", profile_total_count, "run_cnt");
2061     for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2062         struct bpf_perf_event_value *val = &metrics[m].val;
2063         int r;
2064 
2065         if (!metrics[m].selected)
2066             continue;
2067         printf("%18llu %-20s", val->counter, metrics[m].name);
2068 
2069         r = metrics[m].ratio_metric - 1;
2070         if (r >= 0 && metrics[r].selected &&
2071             metrics[r].val.counter > 0) {
2072             printf("# %8.2f %-30s",
2073                    val->counter * metrics[m].ratio_mul /
2074                    metrics[r].val.counter,
2075                    metrics[m].ratio_desc);
2076         } else {
2077             printf("%-41s", "");
2078         }
2079 
2080         if (val->enabled > val->running)
2081             printf("(%4.2f%%)",
2082                    val->running * 100.0 / val->enabled);
2083         printf("\n");
2084     }
2085 }
2086 
2087 static void profile_print_readings(void)
2088 {
2089     if (json_output)
2090         profile_print_readings_json();
2091     else
2092         profile_print_readings_plain();
2093 }
2094 
2095 static char *profile_target_name(int tgt_fd)
2096 {
2097     struct bpf_func_info func_info;
2098     struct bpf_prog_info info = {};
2099     __u32 info_len = sizeof(info);
2100     const struct btf_type *t;
2101     __u32 func_info_rec_size;
2102     struct btf *btf = NULL;
2103     char *name = NULL;
2104     int err;
2105 
2106     err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len);
2107     if (err) {
2108         p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd);
2109         goto out;
2110     }
2111 
2112     if (info.btf_id == 0) {
2113         p_err("prog FD %d doesn't have valid btf", tgt_fd);
2114         goto out;
2115     }
2116 
2117     func_info_rec_size = info.func_info_rec_size;
2118     if (info.nr_func_info == 0) {
2119         p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd);
2120         goto out;
2121     }
2122 
2123     memset(&info, 0, sizeof(info));
2124     info.nr_func_info = 1;
2125     info.func_info_rec_size = func_info_rec_size;
2126     info.func_info = ptr_to_u64(&func_info);
2127 
2128     err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len);
2129     if (err) {
2130         p_err("failed to get func_info for prog FD %d", tgt_fd);
2131         goto out;
2132     }
2133 
2134     btf = btf__load_from_kernel_by_id(info.btf_id);
2135     if (libbpf_get_error(btf)) {
2136         p_err("failed to load btf for prog FD %d", tgt_fd);
2137         goto out;
2138     }
2139 
2140     t = btf__type_by_id(btf, func_info.type_id);
2141     if (!t) {
2142         p_err("btf %d doesn't have type %d",
2143               info.btf_id, func_info.type_id);
2144         goto out;
2145     }
2146     name = strdup(btf__name_by_offset(btf, t->name_off));
2147 out:
2148     btf__free(btf);
2149     return name;
2150 }
2151 
2152 static struct profiler_bpf *profile_obj;
2153 static int profile_tgt_fd = -1;
2154 static char *profile_tgt_name;
2155 static int *profile_perf_events;
2156 static int profile_perf_event_cnt;
2157 
2158 static void profile_close_perf_events(struct profiler_bpf *obj)
2159 {
2160     int i;
2161 
2162     for (i = profile_perf_event_cnt - 1; i >= 0; i--)
2163         close(profile_perf_events[i]);
2164 
2165     free(profile_perf_events);
2166     profile_perf_event_cnt = 0;
2167 }
2168 
2169 static int profile_open_perf_events(struct profiler_bpf *obj)
2170 {
2171     unsigned int cpu, m;
2172     int map_fd, pmu_fd;
2173 
2174     profile_perf_events = calloc(
2175         sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric);
2176     if (!profile_perf_events) {
2177         p_err("failed to allocate memory for perf_event array: %s",
2178               strerror(errno));
2179         return -1;
2180     }
2181     map_fd = bpf_map__fd(obj->maps.events);
2182     if (map_fd < 0) {
2183         p_err("failed to get fd for events map");
2184         return -1;
2185     }
2186 
2187     for (m = 0; m < ARRAY_SIZE(metrics); m++) {
2188         if (!metrics[m].selected)
2189             continue;
2190         for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) {
2191             pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr,
2192                      -1/*pid*/, cpu, -1/*group_fd*/, 0);
2193             if (pmu_fd < 0 ||
2194                 bpf_map_update_elem(map_fd, &profile_perf_event_cnt,
2195                         &pmu_fd, BPF_ANY) ||
2196                 ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) {
2197                 p_err("failed to create event %s on cpu %d",
2198                       metrics[m].name, cpu);
2199                 return -1;
2200             }
2201             profile_perf_events[profile_perf_event_cnt++] = pmu_fd;
2202         }
2203     }
2204     return 0;
2205 }
2206 
2207 static void profile_print_and_cleanup(void)
2208 {
2209     profile_close_perf_events(profile_obj);
2210     profile_read_values(profile_obj);
2211     profile_print_readings();
2212     profiler_bpf__destroy(profile_obj);
2213 
2214     close(profile_tgt_fd);
2215     free(profile_tgt_name);
2216 }
2217 
2218 static void int_exit(int signo)
2219 {
2220     profile_print_and_cleanup();
2221     exit(0);
2222 }
2223 
2224 static int do_profile(int argc, char **argv)
2225 {
2226     int num_metric, num_cpu, err = -1;
2227     struct bpf_program *prog;
2228     unsigned long duration;
2229     char *endptr;
2230 
2231     /* we at least need two args for the prog and one metric */
2232     if (!REQ_ARGS(3))
2233         return -EINVAL;
2234 
2235     /* parse target fd */
2236     profile_tgt_fd = prog_parse_fd(&argc, &argv);
2237     if (profile_tgt_fd < 0) {
2238         p_err("failed to parse fd");
2239         return -1;
2240     }
2241 
2242     /* parse profiling optional duration */
2243     if (argc > 2 && is_prefix(argv[0], "duration")) {
2244         NEXT_ARG();
2245         duration = strtoul(*argv, &endptr, 0);
2246         if (*endptr)
2247             usage();
2248         NEXT_ARG();
2249     } else {
2250         duration = UINT_MAX;
2251     }
2252 
2253     num_metric = profile_parse_metrics(argc, argv);
2254     if (num_metric <= 0)
2255         goto out;
2256 
2257     num_cpu = libbpf_num_possible_cpus();
2258     if (num_cpu <= 0) {
2259         p_err("failed to identify number of CPUs");
2260         goto out;
2261     }
2262 
2263     profile_obj = profiler_bpf__open();
2264     if (!profile_obj) {
2265         p_err("failed to open and/or load BPF object");
2266         goto out;
2267     }
2268 
2269     profile_obj->rodata->num_cpu = num_cpu;
2270     profile_obj->rodata->num_metric = num_metric;
2271 
2272     /* adjust map sizes */
2273     bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu);
2274     bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric);
2275     bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric);
2276     bpf_map__set_max_entries(profile_obj->maps.counts, 1);
2277 
2278     /* change target name */
2279     profile_tgt_name = profile_target_name(profile_tgt_fd);
2280     if (!profile_tgt_name)
2281         goto out;
2282 
2283     bpf_object__for_each_program(prog, profile_obj->obj) {
2284         err = bpf_program__set_attach_target(prog, profile_tgt_fd,
2285                              profile_tgt_name);
2286         if (err) {
2287             p_err("failed to set attach target\n");
2288             goto out;
2289         }
2290     }
2291 
2292     set_max_rlimit();
2293     err = profiler_bpf__load(profile_obj);
2294     if (err) {
2295         p_err("failed to load profile_obj");
2296         goto out;
2297     }
2298 
2299     err = profile_open_perf_events(profile_obj);
2300     if (err)
2301         goto out;
2302 
2303     err = profiler_bpf__attach(profile_obj);
2304     if (err) {
2305         p_err("failed to attach profile_obj");
2306         goto out;
2307     }
2308     signal(SIGINT, int_exit);
2309 
2310     sleep(duration);
2311     profile_print_and_cleanup();
2312     return 0;
2313 
2314 out:
2315     profile_close_perf_events(profile_obj);
2316     if (profile_obj)
2317         profiler_bpf__destroy(profile_obj);
2318     close(profile_tgt_fd);
2319     free(profile_tgt_name);
2320     return err;
2321 }
2322 
2323 #endif /* BPFTOOL_WITHOUT_SKELETONS */
2324 
2325 static int do_help(int argc, char **argv)
2326 {
2327     if (json_output) {
2328         jsonw_null(json_wtr);
2329         return 0;
2330     }
2331 
2332     fprintf(stderr,
2333         "Usage: %1$s %2$s { show | list } [PROG]\n"
2334         "       %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
2335         "       %1$s %2$s dump jited  PROG [{ file FILE | opcodes | linum }]\n"
2336         "       %1$s %2$s pin   PROG FILE\n"
2337         "       %1$s %2$s { load | loadall } OBJ  PATH \\\n"
2338         "                         [type TYPE] [dev NAME] \\\n"
2339         "                         [map { idx IDX | name NAME } MAP]\\\n"
2340         "                         [pinmaps MAP_DIR]\n"
2341         "       %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n"
2342         "       %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n"
2343         "       %1$s %2$s run PROG \\\n"
2344         "                         data_in FILE \\\n"
2345         "                         [data_out FILE [data_size_out L]] \\\n"
2346         "                         [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n"
2347         "                         [repeat N]\n"
2348         "       %1$s %2$s profile PROG [duration DURATION] METRICs\n"
2349         "       %1$s %2$s tracelog\n"
2350         "       %1$s %2$s help\n"
2351         "\n"
2352         "       " HELP_SPEC_MAP "\n"
2353         "       " HELP_SPEC_PROGRAM "\n"
2354         "       TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
2355         "                 tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
2356         "                 cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
2357         "                 lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
2358         "                 sk_reuseport | flow_dissector | cgroup/sysctl |\n"
2359         "                 cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
2360         "                 cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
2361         "                 cgroup/getpeername4 | cgroup/getpeername6 |\n"
2362         "                 cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n"
2363         "                 cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n"
2364         "                 cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n"
2365         "                 struct_ops | fentry | fexit | freplace | sk_lookup }\n"
2366         "       ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n"
2367         "                        sk_skb_stream_parser | flow_dissector }\n"
2368         "       METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n"
2369         "       " HELP_SPEC_OPTIONS " |\n"
2370         "                    {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n"
2371         "                    {-L|--use-loader} }\n"
2372         "",
2373         bin_name, argv[-2]);
2374 
2375     return 0;
2376 }
2377 
2378 static const struct cmd cmds[] = {
2379     { "show",   do_show },
2380     { "list",   do_show },
2381     { "help",   do_help },
2382     { "dump",   do_dump },
2383     { "pin",    do_pin },
2384     { "load",   do_load },
2385     { "loadall",    do_loadall },
2386     { "attach", do_attach },
2387     { "detach", do_detach },
2388     { "tracelog",   do_tracelog },
2389     { "run",    do_run },
2390     { "profile",    do_profile },
2391     { 0 }
2392 };
2393 
2394 int do_prog(int argc, char **argv)
2395 {
2396     return cmd_select(cmds, argc, argv, do_help);
2397 }