102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 371bb428fSJakub Kicinski 43ff5a4dcSJakub Kicinski #define _GNU_SOURCE 571bb428fSJakub Kicinski #include <errno.h> 671bb428fSJakub Kicinski #include <fcntl.h> 747c09d6aSSong Liu #include <signal.h> 8c9c35995SJakub Kicinski #include <stdarg.h> 971bb428fSJakub Kicinski #include <stdio.h> 1071bb428fSJakub Kicinski #include <stdlib.h> 1171bb428fSJakub Kicinski #include <string.h> 1271bb428fSJakub Kicinski #include <time.h> 1371bb428fSJakub Kicinski #include <unistd.h> 14ba6dd679SJakub Kicinski #include <net/if.h> 1547c09d6aSSong Liu #include <sys/ioctl.h> 1671bb428fSJakub Kicinski #include <sys/types.h> 1771bb428fSJakub Kicinski #include <sys/stat.h> 1847c09d6aSSong Liu #include <sys/syscall.h> 19d510296dSAlexei Starovoitov #include <dirent.h> 2071bb428fSJakub Kicinski 21c8406848SJakub Kicinski #include <linux/err.h> 2247c09d6aSSong Liu #include <linux/perf_event.h> 23ba95c745SQuentin Monnet #include <linux/sizes.h> 24c8406848SJakub Kicinski 25229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 26229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 278f184732SQuentin Monnet #include <bpf/hashmap.h> 28229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 29a19df713SMauricio Vásquez #include <bpf/libbpf_internal.h> 30d510296dSAlexei Starovoitov #include <bpf/skel_internal.h> 3171bb428fSJakub Kicinski 32b6c1cedbSJiong Wang #include "cfg.h" 3371bb428fSJakub Kicinski #include "main.h" 3473bb5b4fSJiong Wang #include "xlated_dumper.h" 3571bb428fSJakub Kicinski 36aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX "bpf_metadata_" 37aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 38aff52e68SYiFei Zhu 39ec202509SPaul Chaignon enum dump_mode { 40ec202509SPaul Chaignon DUMP_JITED, 41ec202509SPaul Chaignon DUMP_XLATED, 42ec202509SPaul Chaignon }; 43ec202509SPaul Chaignon 44*1ba5ad36SDaniel Müller static const bool attach_types[] = { 45*1ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_PARSER] = true, 46*1ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_VERDICT] = true, 47*1ba5ad36SDaniel Müller [BPF_SK_SKB_VERDICT] = true, 48*1ba5ad36SDaniel Müller [BPF_SK_MSG_VERDICT] = true, 49*1ba5ad36SDaniel Müller [BPF_FLOW_DISSECTOR] = true, 50*1ba5ad36SDaniel Müller [__MAX_BPF_ATTACH_TYPE] = false, 51*1ba5ad36SDaniel Müller }; 52*1ba5ad36SDaniel Müller 53*1ba5ad36SDaniel Müller /* Textual representations traditionally used by the program and kept around 54*1ba5ad36SDaniel Müller * for the sake of backwards compatibility. 55*1ba5ad36SDaniel Müller */ 56b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 57b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 58b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 59a7ba4558SCong Wang [BPF_SK_SKB_VERDICT] = "skb_verdict", 60b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 61b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 62b7d3826cSJohn Fastabend }; 63b7d3826cSJohn Fastabend 648f184732SQuentin Monnet static struct hashmap *prog_table; 6546241271SQuentin Monnet 66c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 67b7d3826cSJohn Fastabend { 68b7d3826cSJohn Fastabend enum bpf_attach_type type; 69b7d3826cSJohn Fastabend 70b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 71*1ba5ad36SDaniel Müller if (attach_types[type]) { 72*1ba5ad36SDaniel Müller const char *attach_type_str; 73*1ba5ad36SDaniel Müller 74*1ba5ad36SDaniel Müller attach_type_str = libbpf_bpf_attach_type_str(type); 75*1ba5ad36SDaniel Müller if (!strcmp(str, attach_type_str)) 76*1ba5ad36SDaniel Müller return type; 77*1ba5ad36SDaniel Müller } 78*1ba5ad36SDaniel Müller 79b7d3826cSJohn Fastabend if (attach_type_strings[type] && 80b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 81b7d3826cSJohn Fastabend return type; 82b7d3826cSJohn Fastabend } 83b7d3826cSJohn Fastabend 84b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 85b7d3826cSJohn Fastabend } 86b7d3826cSJohn Fastabend 87c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 88c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 89c59765cfSDave Marchevsky { 90c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 91c59765cfSDave Marchevsky size_t needed = 0; 92c59765cfSDave Marchevsky void *ptr; 93c59765cfSDave Marchevsky 94c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 95c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 96c59765cfSDave Marchevsky needed += info->jited_prog_len; 97c59765cfSDave Marchevsky } else { 98c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 99c59765cfSDave Marchevsky needed += info->xlated_prog_len; 100c59765cfSDave Marchevsky } 101c59765cfSDave Marchevsky 102c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 103c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 104c59765cfSDave Marchevsky 105c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 106c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 107c59765cfSDave Marchevsky 108c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 109c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 110c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 111c59765cfSDave Marchevsky 112c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 113c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 114c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 115c59765cfSDave Marchevsky 116c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 117c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 118c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 119c59765cfSDave Marchevsky 120c59765cfSDave Marchevsky if (needed > *info_data_sz) { 121c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 122c59765cfSDave Marchevsky if (!ptr) 123c59765cfSDave Marchevsky return -1; 124c59765cfSDave Marchevsky 125c59765cfSDave Marchevsky *info_data = ptr; 126c59765cfSDave Marchevsky *info_data_sz = needed; 127c59765cfSDave Marchevsky } 128c59765cfSDave Marchevsky ptr = *info_data; 129c59765cfSDave Marchevsky 130c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 131c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 132c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 133c59765cfSDave Marchevsky } else { 134c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 135c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 136c59765cfSDave Marchevsky } 137c59765cfSDave Marchevsky 138c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 139c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 140c59765cfSDave Marchevsky 141c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 142c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 143c59765cfSDave Marchevsky 144c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 145c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 146c59765cfSDave Marchevsky 147c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 148c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 149c59765cfSDave Marchevsky 150c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 151c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 152c59765cfSDave Marchevsky 153c59765cfSDave Marchevsky *info = holder; 154c59765cfSDave Marchevsky return 0; 155c59765cfSDave Marchevsky } 156c59765cfSDave Marchevsky 15771bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 15871bb428fSJakub Kicinski { 15971bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 16071bb428fSJakub Kicinski time_t wallclock_secs; 16171bb428fSJakub Kicinski struct tm load_tm; 16271bb428fSJakub Kicinski 16371bb428fSJakub Kicinski buf[--size] = '\0'; 16471bb428fSJakub Kicinski 16571bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 16671bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 16771bb428fSJakub Kicinski perror("Can't read clocks"); 16871bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 16971bb428fSJakub Kicinski return; 17071bb428fSJakub Kicinski } 17171bb428fSJakub Kicinski 17271bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 17307480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 17407480cbcSJakub Kicinski 1000000000; 17507480cbcSJakub Kicinski 17671bb428fSJakub Kicinski 17771bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 17871bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 17971bb428fSJakub Kicinski return; 18071bb428fSJakub Kicinski } 18171bb428fSJakub Kicinski 182a3fe1f6fSQuentin Monnet if (json_output) 183a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 184a3fe1f6fSQuentin Monnet else 185a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 18671bb428fSJakub Kicinski } 18771bb428fSJakub Kicinski 1886e7e034eSQuentin Monnet static void show_prog_maps(int fd, __u32 num_maps) 18971bb428fSJakub Kicinski { 19071bb428fSJakub Kicinski struct bpf_prog_info info = {}; 19171bb428fSJakub Kicinski __u32 len = sizeof(info); 19271bb428fSJakub Kicinski __u32 map_ids[num_maps]; 19371bb428fSJakub Kicinski unsigned int i; 19471bb428fSJakub Kicinski int err; 19571bb428fSJakub Kicinski 19671bb428fSJakub Kicinski info.nr_map_ids = num_maps; 19771bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 19871bb428fSJakub Kicinski 19971bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 20071bb428fSJakub Kicinski if (err || !info.nr_map_ids) 20171bb428fSJakub Kicinski return; 20271bb428fSJakub Kicinski 203743cc665SQuentin Monnet if (json_output) { 204743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 205743cc665SQuentin Monnet jsonw_start_array(json_wtr); 206743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 207743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 208743cc665SQuentin Monnet jsonw_end_array(json_wtr); 209743cc665SQuentin Monnet } else { 21071bb428fSJakub Kicinski printf(" map_ids "); 21171bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 21271bb428fSJakub Kicinski printf("%u%s", map_ids[i], 21371bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 21471bb428fSJakub Kicinski } 21571bb428fSJakub Kicinski } 21671bb428fSJakub Kicinski 217aff52e68SYiFei Zhu static void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 218aff52e68SYiFei Zhu { 219aff52e68SYiFei Zhu struct bpf_prog_info prog_info; 220aff52e68SYiFei Zhu __u32 prog_info_len; 221aff52e68SYiFei Zhu __u32 map_info_len; 222aff52e68SYiFei Zhu void *value = NULL; 223aff52e68SYiFei Zhu __u32 *map_ids; 224aff52e68SYiFei Zhu int nr_maps; 225aff52e68SYiFei Zhu int key = 0; 226aff52e68SYiFei Zhu int map_fd; 227aff52e68SYiFei Zhu int ret; 228aff52e68SYiFei Zhu __u32 i; 229aff52e68SYiFei Zhu 230aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 231aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 232aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 233aff52e68SYiFei Zhu if (ret) 234aff52e68SYiFei Zhu return NULL; 235aff52e68SYiFei Zhu 236aff52e68SYiFei Zhu if (!prog_info.nr_map_ids) 237aff52e68SYiFei Zhu return NULL; 238aff52e68SYiFei Zhu 239aff52e68SYiFei Zhu map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 240aff52e68SYiFei Zhu if (!map_ids) 241aff52e68SYiFei Zhu return NULL; 242aff52e68SYiFei Zhu 243aff52e68SYiFei Zhu nr_maps = prog_info.nr_map_ids; 244aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 245aff52e68SYiFei Zhu prog_info.nr_map_ids = nr_maps; 246aff52e68SYiFei Zhu prog_info.map_ids = ptr_to_u64(map_ids); 247aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 248aff52e68SYiFei Zhu 249aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 250aff52e68SYiFei Zhu if (ret) 251aff52e68SYiFei Zhu goto free_map_ids; 252aff52e68SYiFei Zhu 253aff52e68SYiFei Zhu for (i = 0; i < prog_info.nr_map_ids; i++) { 254aff52e68SYiFei Zhu map_fd = bpf_map_get_fd_by_id(map_ids[i]); 255aff52e68SYiFei Zhu if (map_fd < 0) 256aff52e68SYiFei Zhu goto free_map_ids; 257aff52e68SYiFei Zhu 258aff52e68SYiFei Zhu memset(map_info, 0, sizeof(*map_info)); 259aff52e68SYiFei Zhu map_info_len = sizeof(*map_info); 260aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(map_fd, map_info, &map_info_len); 261aff52e68SYiFei Zhu if (ret < 0) { 262aff52e68SYiFei Zhu close(map_fd); 263aff52e68SYiFei Zhu goto free_map_ids; 264aff52e68SYiFei Zhu } 265aff52e68SYiFei Zhu 266aff52e68SYiFei Zhu if (map_info->type != BPF_MAP_TYPE_ARRAY || 267aff52e68SYiFei Zhu map_info->key_size != sizeof(int) || 268aff52e68SYiFei Zhu map_info->max_entries != 1 || 269aff52e68SYiFei Zhu !map_info->btf_value_type_id || 270aff52e68SYiFei Zhu !strstr(map_info->name, ".rodata")) { 271aff52e68SYiFei Zhu close(map_fd); 272aff52e68SYiFei Zhu continue; 273aff52e68SYiFei Zhu } 274aff52e68SYiFei Zhu 275aff52e68SYiFei Zhu value = malloc(map_info->value_size); 276aff52e68SYiFei Zhu if (!value) { 277aff52e68SYiFei Zhu close(map_fd); 278aff52e68SYiFei Zhu goto free_map_ids; 279aff52e68SYiFei Zhu } 280aff52e68SYiFei Zhu 281aff52e68SYiFei Zhu if (bpf_map_lookup_elem(map_fd, &key, value)) { 282aff52e68SYiFei Zhu close(map_fd); 283aff52e68SYiFei Zhu free(value); 284aff52e68SYiFei Zhu value = NULL; 285aff52e68SYiFei Zhu goto free_map_ids; 286aff52e68SYiFei Zhu } 287aff52e68SYiFei Zhu 288aff52e68SYiFei Zhu close(map_fd); 289aff52e68SYiFei Zhu break; 290aff52e68SYiFei Zhu } 291aff52e68SYiFei Zhu 292aff52e68SYiFei Zhu free_map_ids: 293aff52e68SYiFei Zhu free(map_ids); 294aff52e68SYiFei Zhu return value; 295aff52e68SYiFei Zhu } 296aff52e68SYiFei Zhu 297aff52e68SYiFei Zhu static bool has_metadata_prefix(const char *s) 298aff52e68SYiFei Zhu { 299aff52e68SYiFei Zhu return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 300aff52e68SYiFei Zhu } 301aff52e68SYiFei Zhu 302aff52e68SYiFei Zhu static void show_prog_metadata(int fd, __u32 num_maps) 303aff52e68SYiFei Zhu { 304aff52e68SYiFei Zhu const struct btf_type *t_datasec, *t_var; 305aff52e68SYiFei Zhu struct bpf_map_info map_info; 306aff52e68SYiFei Zhu struct btf_var_secinfo *vsi; 307aff52e68SYiFei Zhu bool printed_header = false; 308aff52e68SYiFei Zhu unsigned int i, vlen; 309aff52e68SYiFei Zhu void *value = NULL; 310aff52e68SYiFei Zhu const char *name; 31186f4b7f2SQuentin Monnet struct btf *btf; 312aff52e68SYiFei Zhu int err; 313aff52e68SYiFei Zhu 314aff52e68SYiFei Zhu if (!num_maps) 315aff52e68SYiFei Zhu return; 316aff52e68SYiFei Zhu 317aff52e68SYiFei Zhu memset(&map_info, 0, sizeof(map_info)); 318aff52e68SYiFei Zhu value = find_metadata(fd, &map_info); 319aff52e68SYiFei Zhu if (!value) 320aff52e68SYiFei Zhu return; 321aff52e68SYiFei Zhu 32286f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(map_info.btf_id); 32386f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) 324aff52e68SYiFei Zhu goto out_free; 325aff52e68SYiFei Zhu 326aff52e68SYiFei Zhu t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 327aff52e68SYiFei Zhu if (!btf_is_datasec(t_datasec)) 328aff52e68SYiFei Zhu goto out_free; 329aff52e68SYiFei Zhu 330aff52e68SYiFei Zhu vlen = btf_vlen(t_datasec); 331aff52e68SYiFei Zhu vsi = btf_var_secinfos(t_datasec); 332aff52e68SYiFei Zhu 333aff52e68SYiFei Zhu /* We don't proceed to check the kinds of the elements of the DATASEC. 334aff52e68SYiFei Zhu * The verifier enforces them to be BTF_KIND_VAR. 335aff52e68SYiFei Zhu */ 336aff52e68SYiFei Zhu 337aff52e68SYiFei Zhu if (json_output) { 338aff52e68SYiFei Zhu struct btf_dumper d = { 339aff52e68SYiFei Zhu .btf = btf, 340aff52e68SYiFei Zhu .jw = json_wtr, 341aff52e68SYiFei Zhu .is_plain_text = false, 342aff52e68SYiFei Zhu }; 343aff52e68SYiFei Zhu 344aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 345aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 346aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 347aff52e68SYiFei Zhu 348aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 349aff52e68SYiFei Zhu continue; 350aff52e68SYiFei Zhu 351aff52e68SYiFei Zhu if (!printed_header) { 352aff52e68SYiFei Zhu jsonw_name(json_wtr, "metadata"); 353aff52e68SYiFei Zhu jsonw_start_object(json_wtr); 354aff52e68SYiFei Zhu printed_header = true; 355aff52e68SYiFei Zhu } 356aff52e68SYiFei Zhu 357aff52e68SYiFei Zhu jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 358aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 359aff52e68SYiFei Zhu if (err) { 360aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 361aff52e68SYiFei Zhu break; 362aff52e68SYiFei Zhu } 363aff52e68SYiFei Zhu } 364aff52e68SYiFei Zhu if (printed_header) 365aff52e68SYiFei Zhu jsonw_end_object(json_wtr); 366aff52e68SYiFei Zhu } else { 367e89ef634SQuentin Monnet json_writer_t *btf_wtr; 368aff52e68SYiFei Zhu struct btf_dumper d = { 369aff52e68SYiFei Zhu .btf = btf, 370aff52e68SYiFei Zhu .is_plain_text = true, 371aff52e68SYiFei Zhu }; 372aff52e68SYiFei Zhu 373aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 374aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 375aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 376aff52e68SYiFei Zhu 377aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 378aff52e68SYiFei Zhu continue; 379aff52e68SYiFei Zhu 380aff52e68SYiFei Zhu if (!printed_header) { 381aff52e68SYiFei Zhu printf("\tmetadata:"); 382e89ef634SQuentin Monnet 383e89ef634SQuentin Monnet btf_wtr = jsonw_new(stdout); 384e89ef634SQuentin Monnet if (!btf_wtr) { 385e89ef634SQuentin Monnet p_err("jsonw alloc failed"); 386e89ef634SQuentin Monnet goto out_free; 387e89ef634SQuentin Monnet } 388e89ef634SQuentin Monnet d.jw = btf_wtr, 389e89ef634SQuentin Monnet 390aff52e68SYiFei Zhu printed_header = true; 391aff52e68SYiFei Zhu } 392aff52e68SYiFei Zhu 393aff52e68SYiFei Zhu printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 394aff52e68SYiFei Zhu 395aff52e68SYiFei Zhu jsonw_reset(btf_wtr); 396aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 397aff52e68SYiFei Zhu if (err) { 398aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 399aff52e68SYiFei Zhu break; 400aff52e68SYiFei Zhu } 401aff52e68SYiFei Zhu } 402aff52e68SYiFei Zhu if (printed_header) 403aff52e68SYiFei Zhu jsonw_destroy(&btf_wtr); 404aff52e68SYiFei Zhu } 405aff52e68SYiFei Zhu 406aff52e68SYiFei Zhu out_free: 407aff52e68SYiFei Zhu btf__free(btf); 408aff52e68SYiFei Zhu free(value); 409aff52e68SYiFei Zhu } 410aff52e68SYiFei Zhu 411b662000aSRaman Shukhau static void print_prog_header_json(struct bpf_prog_info *info, int fd) 412743cc665SQuentin Monnet { 413b700eeb4SDaniel Müller const char *prog_type_str; 414b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 415b662000aSRaman Shukhau 416743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 417b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 418b700eeb4SDaniel Müller 419b700eeb4SDaniel Müller if (prog_type_str) 420b700eeb4SDaniel Müller jsonw_string_field(json_wtr, "type", prog_type_str); 42171bb428fSJakub Kicinski else 422743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 42371bb428fSJakub Kicinski 424b662000aSRaman Shukhau if (*info->name) { 425b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 426b662000aSRaman Shukhau jsonw_string_field(json_wtr, "name", prog_name); 427b662000aSRaman Shukhau } 42871bb428fSJakub Kicinski 429743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 430743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 431743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 432743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 43371bb428fSJakub Kicinski 4349b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 43588ad472bSAlexei Starovoitov if (info->run_time_ns) { 43688ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 43788ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 43888ad472bSAlexei Starovoitov } 4399ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4409ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 441ec202509SPaul Chaignon } 4429b984a20SJiri Olsa 443ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 444ec202509SPaul Chaignon { 445ec202509SPaul Chaignon char *memlock; 446ec202509SPaul Chaignon 447ec202509SPaul Chaignon jsonw_start_object(json_wtr); 448b662000aSRaman Shukhau print_prog_header_json(info, fd); 44952262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 45052262210SJakub Kicinski 451743cc665SQuentin Monnet if (info->load_time) { 45271bb428fSJakub Kicinski char buf[32]; 45371bb428fSJakub Kicinski 454743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 45571bb428fSJakub Kicinski 45671bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 457a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 458a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 459743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 46071bb428fSJakub Kicinski } 46171bb428fSJakub Kicinski 462743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 46371bb428fSJakub Kicinski 464743cc665SQuentin Monnet if (info->jited_prog_len) { 465743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 466743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 467743cc665SQuentin Monnet } else { 468743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 469743cc665SQuentin Monnet } 470743cc665SQuentin Monnet 471743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 472743cc665SQuentin Monnet if (memlock) 473357b3cc3SChris J Arges jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock)); 474743cc665SQuentin Monnet free(memlock); 475743cc665SQuentin Monnet 476743cc665SQuentin Monnet if (info->nr_map_ids) 477743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 478743cc665SQuentin Monnet 479569b0c77SPrashant Bhole if (info->btf_id) 480569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 481569b0c77SPrashant Bhole 4828f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4838f184732SQuentin Monnet struct hashmap_entry *entry; 4844990f1f4SPrashant Bhole 4854990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 4864990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 4878f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 4888f184732SQuentin Monnet u32_as_hash_field(info->id)) 4898f184732SQuentin Monnet jsonw_string(json_wtr, entry->value); 4904990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 4914990f1f4SPrashant Bhole } 4924990f1f4SPrashant Bhole 493d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 494d53dee3fSAndrii Nakryiko 495aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 496aff52e68SYiFei Zhu 497743cc665SQuentin Monnet jsonw_end_object(json_wtr); 498743cc665SQuentin Monnet } 499743cc665SQuentin Monnet 500b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 501743cc665SQuentin Monnet { 502b700eeb4SDaniel Müller const char *prog_type_str; 503b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 504b662000aSRaman Shukhau 505743cc665SQuentin Monnet printf("%u: ", info->id); 506b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 507b700eeb4SDaniel Müller if (prog_type_str) 508b700eeb4SDaniel Müller printf("%s ", prog_type_str); 509743cc665SQuentin Monnet else 510743cc665SQuentin Monnet printf("type %u ", info->type); 511743cc665SQuentin Monnet 512b662000aSRaman Shukhau if (*info->name) { 513b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 514b662000aSRaman Shukhau printf("name %s ", prog_name); 515b662000aSRaman Shukhau } 516743cc665SQuentin Monnet 517743cc665SQuentin Monnet printf("tag "); 518743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 51952262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5209b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 52188ad472bSAlexei Starovoitov if (info->run_time_ns) 52288ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 52388ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5249ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5259ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 526743cc665SQuentin Monnet printf("\n"); 527ec202509SPaul Chaignon } 528ec202509SPaul Chaignon 529ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 530ec202509SPaul Chaignon { 531ec202509SPaul Chaignon char *memlock; 532ec202509SPaul Chaignon 533b662000aSRaman Shukhau print_prog_header_plain(info, fd); 534743cc665SQuentin Monnet 535743cc665SQuentin Monnet if (info->load_time) { 536743cc665SQuentin Monnet char buf[32]; 537743cc665SQuentin Monnet 538743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 539743cc665SQuentin Monnet 540743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 541743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 542743cc665SQuentin Monnet } 543743cc665SQuentin Monnet 544743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 545743cc665SQuentin Monnet 546743cc665SQuentin Monnet if (info->jited_prog_len) 547743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 54871bb428fSJakub Kicinski else 54971bb428fSJakub Kicinski printf(" not jited"); 55071bb428fSJakub Kicinski 55171bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 55271bb428fSJakub Kicinski if (memlock) 55371bb428fSJakub Kicinski printf(" memlock %sB", memlock); 55471bb428fSJakub Kicinski free(memlock); 55571bb428fSJakub Kicinski 556743cc665SQuentin Monnet if (info->nr_map_ids) 557743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 55871bb428fSJakub Kicinski 5598f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5608f184732SQuentin Monnet struct hashmap_entry *entry; 5614990f1f4SPrashant Bhole 5628f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5638f184732SQuentin Monnet u32_as_hash_field(info->id)) 5648f184732SQuentin Monnet printf("\n\tpinned %s", (char *)entry->value); 5654990f1f4SPrashant Bhole } 5664990f1f4SPrashant Bhole 567569b0c77SPrashant Bhole if (info->btf_id) 568031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 569569b0c77SPrashant Bhole 570d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 571d53dee3fSAndrii Nakryiko 57271bb428fSJakub Kicinski printf("\n"); 573aff52e68SYiFei Zhu 574aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 575743cc665SQuentin Monnet } 576743cc665SQuentin Monnet 577743cc665SQuentin Monnet static int show_prog(int fd) 578743cc665SQuentin Monnet { 579743cc665SQuentin Monnet struct bpf_prog_info info = {}; 580743cc665SQuentin Monnet __u32 len = sizeof(info); 581743cc665SQuentin Monnet int err; 582743cc665SQuentin Monnet 583743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 584743cc665SQuentin Monnet if (err) { 5859a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 586743cc665SQuentin Monnet return -1; 587743cc665SQuentin Monnet } 588743cc665SQuentin Monnet 589743cc665SQuentin Monnet if (json_output) 590743cc665SQuentin Monnet print_prog_json(&info, fd); 591743cc665SQuentin Monnet else 592743cc665SQuentin Monnet print_prog_plain(&info, fd); 59371bb428fSJakub Kicinski 59471bb428fSJakub Kicinski return 0; 59571bb428fSJakub Kicinski } 59671bb428fSJakub Kicinski 597ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 598ec202509SPaul Chaignon { 599ec202509SPaul Chaignon int *fds = NULL; 600ec202509SPaul Chaignon int nb_fds, i; 601ec202509SPaul Chaignon int err = -1; 602ec202509SPaul Chaignon 603ec202509SPaul Chaignon fds = malloc(sizeof(int)); 604ec202509SPaul Chaignon if (!fds) { 605ec202509SPaul Chaignon p_err("mem alloc failed"); 606ec202509SPaul Chaignon return -1; 607ec202509SPaul Chaignon } 608ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 609ec202509SPaul Chaignon if (nb_fds < 1) 610ec202509SPaul Chaignon goto exit_free; 611ec202509SPaul Chaignon 612ec202509SPaul Chaignon if (json_output && nb_fds > 1) 613ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 614ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 615ec202509SPaul Chaignon err = show_prog(fds[i]); 616ec202509SPaul Chaignon if (err) { 617ec202509SPaul Chaignon for (; i < nb_fds; i++) 618ec202509SPaul Chaignon close(fds[i]); 619ec202509SPaul Chaignon break; 620ec202509SPaul Chaignon } 621ec202509SPaul Chaignon close(fds[i]); 622ec202509SPaul Chaignon } 623ec202509SPaul Chaignon if (json_output && nb_fds > 1) 624ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 625ec202509SPaul Chaignon 626ec202509SPaul Chaignon exit_free: 627ec202509SPaul Chaignon free(fds); 628ec202509SPaul Chaignon return err; 629ec202509SPaul Chaignon } 630ec202509SPaul Chaignon 63171bb428fSJakub Kicinski static int do_show(int argc, char **argv) 632743cc665SQuentin Monnet { 633743cc665SQuentin Monnet __u32 id = 0; 63471bb428fSJakub Kicinski int err; 63571bb428fSJakub Kicinski int fd; 63671bb428fSJakub Kicinski 63746241271SQuentin Monnet if (show_pinned) { 6388f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6398f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 640622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6418f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6428f184732SQuentin Monnet return -1; 6438f184732SQuentin Monnet } 6448f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64546241271SQuentin Monnet } 646d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6474990f1f4SPrashant Bhole 648ec202509SPaul Chaignon if (argc == 2) 649ec202509SPaul Chaignon return do_show_subset(argc, argv); 65071bb428fSJakub Kicinski 65171bb428fSJakub Kicinski if (argc) 65271bb428fSJakub Kicinski return BAD_ARG(); 65371bb428fSJakub Kicinski 654743cc665SQuentin Monnet if (json_output) 655743cc665SQuentin Monnet jsonw_start_array(json_wtr); 65671bb428fSJakub Kicinski while (true) { 65771bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 65871bb428fSJakub Kicinski if (err) { 6591739c26dSQuentin Monnet if (errno == ENOENT) { 6601739c26dSQuentin Monnet err = 0; 66171bb428fSJakub Kicinski break; 6621739c26dSQuentin Monnet } 6639a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6649a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 665743cc665SQuentin Monnet err = -1; 666743cc665SQuentin Monnet break; 66771bb428fSJakub Kicinski } 66871bb428fSJakub Kicinski 66971bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 67071bb428fSJakub Kicinski if (fd < 0) { 6718207c6ddSJakub Kicinski if (errno == ENOENT) 6728207c6ddSJakub Kicinski continue; 6739a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 67471bb428fSJakub Kicinski id, strerror(errno)); 675743cc665SQuentin Monnet err = -1; 676743cc665SQuentin Monnet break; 67771bb428fSJakub Kicinski } 67871bb428fSJakub Kicinski 67971bb428fSJakub Kicinski err = show_prog(fd); 68071bb428fSJakub Kicinski close(fd); 68171bb428fSJakub Kicinski if (err) 682743cc665SQuentin Monnet break; 68371bb428fSJakub Kicinski } 68471bb428fSJakub Kicinski 685743cc665SQuentin Monnet if (json_output) 686743cc665SQuentin Monnet jsonw_end_array(json_wtr); 687743cc665SQuentin Monnet 688d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 689d53dee3fSAndrii Nakryiko 69046241271SQuentin Monnet if (show_pinned) 6918f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 69246241271SQuentin Monnet 693743cc665SQuentin Monnet return err; 69471bb428fSJakub Kicinski } 69571bb428fSJakub Kicinski 696ec202509SPaul Chaignon static int 697ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 698ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 69971bb428fSJakub Kicinski { 700b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7013ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7027105e828SDaniel Borkmann struct dump_data dd = {}; 703cae73f23SSong Liu void *func_info = NULL; 704254471e5SYonghong Song struct btf *btf = NULL; 705254471e5SYonghong Song char func_sig[1024]; 70671bb428fSJakub Kicinski unsigned char *buf; 707cae73f23SSong Liu __u32 member_len; 708ebbd7f64SQuentin Monnet int fd, err = -1; 70971bb428fSJakub Kicinski ssize_t n; 71071bb428fSJakub Kicinski 711cae73f23SSong Liu if (mode == DUMP_JITED) { 7125b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7139a5ab8bfSQuentin Monnet p_info("no instructions returned"); 714ec202509SPaul Chaignon return -1; 715f84192eeSSandipan Das } 71609f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 717cae73f23SSong Liu member_len = info->jited_prog_len; 718cae73f23SSong Liu } else { /* DUMP_XLATED */ 719d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7207105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 721ec202509SPaul Chaignon return -1; 7227105e828SDaniel Borkmann } 72309f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 724cae73f23SSong Liu member_len = info->xlated_prog_len; 725cae73f23SSong Liu } 7267105e828SDaniel Borkmann 72786f4b7f2SQuentin Monnet if (info->btf_id) { 72886f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 72986f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 730254471e5SYonghong Song p_err("failed to get btf"); 731ec202509SPaul Chaignon return -1; 732254471e5SYonghong Song } 73386f4b7f2SQuentin Monnet } 734254471e5SYonghong Song 73509f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 736cae73f23SSong Liu 737cae73f23SSong Liu if (info->nr_line_info) { 738cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 739b053b439SMartin KaFai Lau if (!prog_linfo) 74010a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 741b053b439SMartin KaFai Lau } 742b053b439SMartin KaFai Lau 74371bb428fSJakub Kicinski if (filepath) { 74471bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74571bb428fSJakub Kicinski if (fd < 0) { 7469a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 74771bb428fSJakub Kicinski strerror(errno)); 748ebbd7f64SQuentin Monnet goto exit_free; 74971bb428fSJakub Kicinski } 75071bb428fSJakub Kicinski 751cae73f23SSong Liu n = write(fd, buf, member_len); 75271bb428fSJakub Kicinski close(fd); 75309f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7549a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 75571bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 756ebbd7f64SQuentin Monnet goto exit_free; 75771bb428fSJakub Kicinski } 75852c84d36SQuentin Monnet 75952c84d36SQuentin Monnet if (json_output) 76052c84d36SQuentin Monnet jsonw_null(json_wtr); 761cae73f23SSong Liu } else if (mode == DUMP_JITED) { 762e6593596SJiong Wang const char *name = NULL; 763e6593596SJiong Wang 764cae73f23SSong Liu if (info->ifindex) { 765cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 766cae73f23SSong Liu info->netns_dev, 767cae73f23SSong Liu info->netns_ino, 7683ddeac67SJakub Kicinski &disasm_opt); 769e6593596SJiong Wang if (!name) 770ebbd7f64SQuentin Monnet goto exit_free; 771e6593596SJiong Wang } 772e6593596SJiong Wang 773cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 774f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 775254471e5SYonghong Song struct bpf_func_info *record; 776f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 777f7f62c71SSandipan Das unsigned char *img = buf; 778f7f62c71SSandipan Das __u64 *ksyms = NULL; 779f7f62c71SSandipan Das __u32 *lens; 780f7f62c71SSandipan Das __u32 i; 781cae73f23SSong Liu if (info->nr_jited_ksyms) { 782f7f62c71SSandipan Das kernel_syms_load(&dd); 78309f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 784f7f62c71SSandipan Das } 785f7f62c71SSandipan Das 786f7f62c71SSandipan Das if (json_output) 787f7f62c71SSandipan Das jsonw_start_array(json_wtr); 788f7f62c71SSandipan Das 78909f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 790cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 791f7f62c71SSandipan Das if (ksyms) { 792f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 793f7f62c71SSandipan Das if (sym) 794f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 795f7f62c71SSandipan Das else 796f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 797f7f62c71SSandipan Das } else { 798f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 799f7f62c71SSandipan Das } 800f7f62c71SSandipan Das 801254471e5SYonghong Song if (func_info) { 802cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 803254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 804254471e5SYonghong Song func_sig, 805254471e5SYonghong Song sizeof(func_sig)); 806254471e5SYonghong Song } 807254471e5SYonghong Song 808f7f62c71SSandipan Das if (json_output) { 809f7f62c71SSandipan Das jsonw_start_object(json_wtr); 810254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 811254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 812254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 813254471e5SYonghong Song } 814f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 815f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 816f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 817f7f62c71SSandipan Das } else { 818254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 819254471e5SYonghong Song printf("%s:\n", func_sig); 820f7f62c71SSandipan Das printf("%s:\n", sym_name); 821f7f62c71SSandipan Das } 822f7f62c71SSandipan Das 823b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 824b053b439SMartin KaFai Lau name, disasm_opt, btf, 825b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 826b053b439SMartin KaFai Lau linum); 827b053b439SMartin KaFai Lau 828f7f62c71SSandipan Das img += lens[i]; 829f7f62c71SSandipan Das 830f7f62c71SSandipan Das if (json_output) 831f7f62c71SSandipan Das jsonw_end_object(json_wtr); 832f7f62c71SSandipan Das else 833f7f62c71SSandipan Das printf("\n"); 834f7f62c71SSandipan Das } 835f7f62c71SSandipan Das 836f7f62c71SSandipan Das if (json_output) 837f7f62c71SSandipan Das jsonw_end_array(json_wtr); 838f7f62c71SSandipan Das } else { 839cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 840b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 841f7f62c71SSandipan Das } 842b6c1cedbSJiong Wang } else if (visual) { 843b6c1cedbSJiong Wang if (json_output) 844b6c1cedbSJiong Wang jsonw_null(json_wtr); 845b6c1cedbSJiong Wang else 846cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8477105e828SDaniel Borkmann } else { 8487105e828SDaniel Borkmann kernel_syms_load(&dd); 849cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 85009f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 851254471e5SYonghong Song dd.btf = btf; 852254471e5SYonghong Song dd.func_info = func_info; 853cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 854b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 855f84192eeSSandipan Das 856f05e2c32SQuentin Monnet if (json_output) 857cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 858b053b439SMartin KaFai Lau linum); 859f05e2c32SQuentin Monnet else 860cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 861b053b439SMartin KaFai Lau linum); 8627105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8637105e828SDaniel Borkmann } 86471bb428fSJakub Kicinski 865ebbd7f64SQuentin Monnet err = 0; 866369e955bSQuentin Monnet 867ebbd7f64SQuentin Monnet exit_free: 868ebbd7f64SQuentin Monnet btf__free(btf); 869ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 870ebbd7f64SQuentin Monnet return err; 871ec202509SPaul Chaignon } 87271bb428fSJakub Kicinski 873ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 874ec202509SPaul Chaignon { 875c59765cfSDave Marchevsky struct bpf_prog_info info; 876c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 877c59765cfSDave Marchevsky size_t info_data_sz = 0; 878c59765cfSDave Marchevsky void *info_data = NULL; 879ec202509SPaul Chaignon char *filepath = NULL; 880ec202509SPaul Chaignon bool opcodes = false; 881ec202509SPaul Chaignon bool visual = false; 882ec202509SPaul Chaignon enum dump_mode mode; 883ec202509SPaul Chaignon bool linum = false; 884ec202509SPaul Chaignon int nb_fds, i = 0; 885c59765cfSDave Marchevsky int *fds = NULL; 886ec202509SPaul Chaignon int err = -1; 887ec202509SPaul Chaignon 888ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 889ec202509SPaul Chaignon if (disasm_init()) 89071bb428fSJakub Kicinski return -1; 891ec202509SPaul Chaignon mode = DUMP_JITED; 892ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 893ec202509SPaul Chaignon mode = DUMP_XLATED; 894ec202509SPaul Chaignon } else { 895ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 896ec202509SPaul Chaignon return -1; 897ec202509SPaul Chaignon } 898ec202509SPaul Chaignon NEXT_ARG(); 899ec202509SPaul Chaignon 900ec202509SPaul Chaignon if (argc < 2) 901ec202509SPaul Chaignon usage(); 902ec202509SPaul Chaignon 903ec202509SPaul Chaignon fds = malloc(sizeof(int)); 904ec202509SPaul Chaignon if (!fds) { 905ec202509SPaul Chaignon p_err("mem alloc failed"); 906ec202509SPaul Chaignon return -1; 907ec202509SPaul Chaignon } 908ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 909ec202509SPaul Chaignon if (nb_fds < 1) 910ec202509SPaul Chaignon goto exit_free; 911ec202509SPaul Chaignon 912ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 913ec202509SPaul Chaignon NEXT_ARG(); 914ec202509SPaul Chaignon if (!argc) { 915ec202509SPaul Chaignon p_err("expected file path"); 916ec202509SPaul Chaignon goto exit_close; 917ec202509SPaul Chaignon } 918ec202509SPaul Chaignon if (nb_fds > 1) { 919ec202509SPaul Chaignon p_err("several programs matched"); 920ec202509SPaul Chaignon goto exit_close; 921ec202509SPaul Chaignon } 922ec202509SPaul Chaignon 923ec202509SPaul Chaignon filepath = *argv; 924ec202509SPaul Chaignon NEXT_ARG(); 925ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 926ec202509SPaul Chaignon opcodes = true; 927ec202509SPaul Chaignon NEXT_ARG(); 928ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 929ec202509SPaul Chaignon if (nb_fds > 1) { 930ec202509SPaul Chaignon p_err("several programs matched"); 931ec202509SPaul Chaignon goto exit_close; 932ec202509SPaul Chaignon } 933ec202509SPaul Chaignon 934ec202509SPaul Chaignon visual = true; 935ec202509SPaul Chaignon NEXT_ARG(); 936ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 937ec202509SPaul Chaignon linum = true; 938ec202509SPaul Chaignon NEXT_ARG(); 939ec202509SPaul Chaignon } 940ec202509SPaul Chaignon 941ec202509SPaul Chaignon if (argc) { 942ec202509SPaul Chaignon usage(); 943ec202509SPaul Chaignon goto exit_close; 944ec202509SPaul Chaignon } 945ec202509SPaul Chaignon 946ec202509SPaul Chaignon if (json_output && nb_fds > 1) 947ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 948ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 949c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 950c59765cfSDave Marchevsky 951c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 952c59765cfSDave Marchevsky if (err) { 953c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 954c59765cfSDave Marchevsky break; 955c59765cfSDave Marchevsky } 956c59765cfSDave Marchevsky 957c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 958c59765cfSDave Marchevsky if (err) { 959c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 960c59765cfSDave Marchevsky break; 961c59765cfSDave Marchevsky } 962c59765cfSDave Marchevsky 963c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 964c59765cfSDave Marchevsky if (err) { 965ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 966ec202509SPaul Chaignon break; 967ec202509SPaul Chaignon } 968ec202509SPaul Chaignon 969ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 970ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 971b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 972ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 973ec202509SPaul Chaignon } else if (nb_fds > 1) { 974b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 975ec202509SPaul Chaignon } 976ec202509SPaul Chaignon 977c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 978ec202509SPaul Chaignon 979ec202509SPaul Chaignon if (json_output && nb_fds > 1) 980ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 981ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 982ec202509SPaul Chaignon printf("\n"); 983ec202509SPaul Chaignon 984ec202509SPaul Chaignon if (err) 985ec202509SPaul Chaignon break; 986ec202509SPaul Chaignon close(fds[i]); 987ec202509SPaul Chaignon } 988ec202509SPaul Chaignon if (json_output && nb_fds > 1) 989ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 990ec202509SPaul Chaignon 991ec202509SPaul Chaignon exit_close: 992ec202509SPaul Chaignon for (; i < nb_fds; i++) 993ec202509SPaul Chaignon close(fds[i]); 994ec202509SPaul Chaignon exit_free: 995c59765cfSDave Marchevsky free(info_data); 996ec202509SPaul Chaignon free(fds); 997ec202509SPaul Chaignon return err; 99871bb428fSJakub Kicinski } 99971bb428fSJakub Kicinski 100071bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 100171bb428fSJakub Kicinski { 1002004b45c0SQuentin Monnet int err; 1003004b45c0SQuentin Monnet 100475a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1005004b45c0SQuentin Monnet if (!err && json_output) 1006004b45c0SQuentin Monnet jsonw_null(json_wtr); 1007004b45c0SQuentin Monnet return err; 100871bb428fSJakub Kicinski } 100971bb428fSJakub Kicinski 10103ff5a4dcSJakub Kicinski struct map_replace { 10113ff5a4dcSJakub Kicinski int idx; 10123ff5a4dcSJakub Kicinski int fd; 10133ff5a4dcSJakub Kicinski char *name; 10143ff5a4dcSJakub Kicinski }; 10153ff5a4dcSJakub Kicinski 1016c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10173ff5a4dcSJakub Kicinski { 10183ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10193ff5a4dcSJakub Kicinski 10203ff5a4dcSJakub Kicinski return a->idx - b->idx; 10213ff5a4dcSJakub Kicinski } 10223ff5a4dcSJakub Kicinski 1023092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1024092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1025092f0892SStanislav Fomichev int *mapfd) 1026092f0892SStanislav Fomichev { 1027092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1028092f0892SStanislav Fomichev return -EINVAL; 1029092f0892SStanislav Fomichev 1030092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1031092f0892SStanislav Fomichev if (*progfd < 0) 1032092f0892SStanislav Fomichev return *progfd; 1033092f0892SStanislav Fomichev 1034092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1035092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1036092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1037092f0892SStanislav Fomichev return -EINVAL; 1038092f0892SStanislav Fomichev } 1039092f0892SStanislav Fomichev 1040092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1041f9b7ff0dSLorenz Bauer *mapfd = 0; 1042092f0892SStanislav Fomichev return 0; 1043092f0892SStanislav Fomichev } 1044092f0892SStanislav Fomichev 1045092f0892SStanislav Fomichev NEXT_ARG(); 1046092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1047092f0892SStanislav Fomichev return -EINVAL; 1048092f0892SStanislav Fomichev 1049092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1050092f0892SStanislav Fomichev if (*mapfd < 0) 1051092f0892SStanislav Fomichev return *mapfd; 1052092f0892SStanislav Fomichev 1053092f0892SStanislav Fomichev return 0; 1054092f0892SStanislav Fomichev } 1055092f0892SStanislav Fomichev 1056b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1057b7d3826cSJohn Fastabend { 1058b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1059092f0892SStanislav Fomichev int err, progfd; 1060092f0892SStanislav Fomichev int mapfd; 1061b7d3826cSJohn Fastabend 1062092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1063092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1064092f0892SStanislav Fomichev if (err) 1065092f0892SStanislav Fomichev return err; 1066b7d3826cSJohn Fastabend 1067b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1068b7d3826cSJohn Fastabend if (err) { 1069b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1070b7d3826cSJohn Fastabend return -EINVAL; 1071b7d3826cSJohn Fastabend } 1072b7d3826cSJohn Fastabend 1073b7d3826cSJohn Fastabend if (json_output) 1074b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1075b7d3826cSJohn Fastabend return 0; 1076b7d3826cSJohn Fastabend } 1077b7d3826cSJohn Fastabend 1078b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1079b7d3826cSJohn Fastabend { 1080b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1081092f0892SStanislav Fomichev int err, progfd; 1082092f0892SStanislav Fomichev int mapfd; 1083b7d3826cSJohn Fastabend 1084092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1085092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1086092f0892SStanislav Fomichev if (err) 1087092f0892SStanislav Fomichev return err; 1088b7d3826cSJohn Fastabend 1089b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1090b7d3826cSJohn Fastabend if (err) { 1091b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1092b7d3826cSJohn Fastabend return -EINVAL; 1093b7d3826cSJohn Fastabend } 1094b7d3826cSJohn Fastabend 1095b7d3826cSJohn Fastabend if (json_output) 1096b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1097b7d3826cSJohn Fastabend return 0; 1098b7d3826cSJohn Fastabend } 109977380998SStanislav Fomichev 1100ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1101ba95c745SQuentin Monnet { 1102ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1103ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1104ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1105ba95c745SQuentin Monnet return -1; 1106ba95c745SQuentin Monnet } 1107ba95c745SQuentin Monnet 1108ba95c745SQuentin Monnet return 0; 1109ba95c745SQuentin Monnet } 1110ba95c745SQuentin Monnet 1111ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1112ba95c745SQuentin Monnet { 1113ba95c745SQuentin Monnet size_t block_size = 256; 1114ba95c745SQuentin Monnet size_t buf_size = block_size; 1115ba95c745SQuentin Monnet size_t nb_read = 0; 1116ba95c745SQuentin Monnet void *tmp; 1117ba95c745SQuentin Monnet FILE *f; 1118ba95c745SQuentin Monnet 1119ba95c745SQuentin Monnet if (!fname) { 1120ba95c745SQuentin Monnet *data_ptr = NULL; 1121ba95c745SQuentin Monnet *size = 0; 1122ba95c745SQuentin Monnet return 0; 1123ba95c745SQuentin Monnet } 1124ba95c745SQuentin Monnet 1125ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1126ba95c745SQuentin Monnet f = stdin; 1127ba95c745SQuentin Monnet else 1128ba95c745SQuentin Monnet f = fopen(fname, "r"); 1129ba95c745SQuentin Monnet if (!f) { 1130ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1131ba95c745SQuentin Monnet return -1; 1132ba95c745SQuentin Monnet } 1133ba95c745SQuentin Monnet 1134ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1135ba95c745SQuentin Monnet if (!*data_ptr) { 1136ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1137ba95c745SQuentin Monnet strerror(errno)); 1138ba95c745SQuentin Monnet goto err_fclose; 1139ba95c745SQuentin Monnet } 1140ba95c745SQuentin Monnet 1141ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1142ba95c745SQuentin Monnet if (feof(f)) 1143ba95c745SQuentin Monnet break; 1144ba95c745SQuentin Monnet if (ferror(f)) { 1145ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1146ba95c745SQuentin Monnet fname, strerror(errno)); 1147ba95c745SQuentin Monnet goto err_free; 1148ba95c745SQuentin Monnet } 1149ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1150ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1151ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1152ba95c745SQuentin Monnet UINT32_MAX); 1153ba95c745SQuentin Monnet goto err_free; 1154ba95c745SQuentin Monnet } 1155ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1156ba95c745SQuentin Monnet buf_size *= 2; 1157ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1158ba95c745SQuentin Monnet if (!tmp) { 1159ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1160ba95c745SQuentin Monnet strerror(errno)); 1161ba95c745SQuentin Monnet goto err_free; 1162ba95c745SQuentin Monnet } 1163ba95c745SQuentin Monnet *data_ptr = tmp; 1164ba95c745SQuentin Monnet } 1165ba95c745SQuentin Monnet } 1166ba95c745SQuentin Monnet if (f != stdin) 1167ba95c745SQuentin Monnet fclose(f); 1168ba95c745SQuentin Monnet 1169ba95c745SQuentin Monnet *size = nb_read; 1170ba95c745SQuentin Monnet return 0; 1171ba95c745SQuentin Monnet 1172ba95c745SQuentin Monnet err_free: 1173ba95c745SQuentin Monnet free(*data_ptr); 1174ba95c745SQuentin Monnet *data_ptr = NULL; 1175ba95c745SQuentin Monnet err_fclose: 1176ba95c745SQuentin Monnet if (f != stdin) 1177ba95c745SQuentin Monnet fclose(f); 1178ba95c745SQuentin Monnet return -1; 1179ba95c745SQuentin Monnet } 1180ba95c745SQuentin Monnet 1181ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1182ba95c745SQuentin Monnet { 1183ba95c745SQuentin Monnet size_t i, j; 1184ba95c745SQuentin Monnet char c; 1185ba95c745SQuentin Monnet 1186ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1187ba95c745SQuentin Monnet /* Row offset */ 1188ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1189ba95c745SQuentin Monnet 1190ba95c745SQuentin Monnet /* Hexadecimal values */ 1191ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1192ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1193ba95c745SQuentin Monnet j % 2 ? " " : ""); 1194ba95c745SQuentin Monnet for (; j < i + 16; j++) 1195ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1196ba95c745SQuentin Monnet 1197ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1198ba95c745SQuentin Monnet fprintf(f, "| "); 1199ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1200ba95c745SQuentin Monnet c = *(char *)(data + j); 1201ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1202ba95c745SQuentin Monnet c = '.'; 1203ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1204ba95c745SQuentin Monnet } 1205ba95c745SQuentin Monnet 1206ba95c745SQuentin Monnet fprintf(f, "\n"); 1207ba95c745SQuentin Monnet } 1208ba95c745SQuentin Monnet } 1209ba95c745SQuentin Monnet 1210ba95c745SQuentin Monnet static int 1211ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1212ba95c745SQuentin Monnet const char *json_key) 1213ba95c745SQuentin Monnet { 1214ba95c745SQuentin Monnet size_t nb_written; 1215ba95c745SQuentin Monnet FILE *f; 1216ba95c745SQuentin Monnet 1217ba95c745SQuentin Monnet if (!fname) 1218ba95c745SQuentin Monnet return 0; 1219ba95c745SQuentin Monnet 1220ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1221ba95c745SQuentin Monnet f = stdout; 1222ba95c745SQuentin Monnet if (json_output) { 1223ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1224ba95c745SQuentin Monnet print_data_json(data, size); 1225ba95c745SQuentin Monnet } else { 1226ba95c745SQuentin Monnet hex_print(data, size, f); 1227ba95c745SQuentin Monnet } 1228ba95c745SQuentin Monnet return 0; 1229ba95c745SQuentin Monnet } 1230ba95c745SQuentin Monnet 1231ba95c745SQuentin Monnet f = fopen(fname, "w"); 1232ba95c745SQuentin Monnet if (!f) { 1233ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1234ba95c745SQuentin Monnet return -1; 1235ba95c745SQuentin Monnet } 1236ba95c745SQuentin Monnet 1237ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1238ba95c745SQuentin Monnet fclose(f); 1239ba95c745SQuentin Monnet if (nb_written != size) { 1240ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1241ba95c745SQuentin Monnet return -1; 1242ba95c745SQuentin Monnet } 1243ba95c745SQuentin Monnet 1244ba95c745SQuentin Monnet return 0; 1245ba95c745SQuentin Monnet } 1246ba95c745SQuentin Monnet 1247ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1248ba95c745SQuentin Monnet { 1249ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1250ba95c745SQuentin Monnet if (!*data_ptr) { 1251ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1252ba95c745SQuentin Monnet strerror(errno)); 1253ba95c745SQuentin Monnet return -1; 1254ba95c745SQuentin Monnet } 1255ba95c745SQuentin Monnet 1256ba95c745SQuentin Monnet return 0; 1257ba95c745SQuentin Monnet } 1258ba95c745SQuentin Monnet 1259ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1260ba95c745SQuentin Monnet { 1261ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1262ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1263ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1264ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1265ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1266ba95c745SQuentin Monnet unsigned int repeat = 1; 1267ba95c745SQuentin Monnet int fd, err; 12689cce5313SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, test_attr); 1269ba95c745SQuentin Monnet 1270ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1271ba95c745SQuentin Monnet return -1; 1272ba95c745SQuentin Monnet 1273ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1274ba95c745SQuentin Monnet if (fd < 0) 1275ba95c745SQuentin Monnet return -1; 1276ba95c745SQuentin Monnet 1277ba95c745SQuentin Monnet while (argc) { 1278ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1279ba95c745SQuentin Monnet "data_size_out", NULL)) 1280ba95c745SQuentin Monnet return -1; 1281ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1282ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1283ba95c745SQuentin Monnet return -1; 1284ba95c745SQuentin Monnet 1285ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1286ba95c745SQuentin Monnet NEXT_ARG(); 1287ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1288ba95c745SQuentin Monnet return -1; 1289ba95c745SQuentin Monnet 1290ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1291ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1292ba95c745SQuentin Monnet return -1; 1293ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1294ba95c745SQuentin Monnet NEXT_ARG(); 1295ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1296ba95c745SQuentin Monnet return -1; 1297ba95c745SQuentin Monnet 1298ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1299ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1300ba95c745SQuentin Monnet char *endptr; 1301ba95c745SQuentin Monnet 1302ba95c745SQuentin Monnet NEXT_ARG(); 1303ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1304ba95c745SQuentin Monnet return -1; 1305ba95c745SQuentin Monnet 1306ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1307ba95c745SQuentin Monnet if (*endptr) { 1308ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1309ba95c745SQuentin Monnet *argv); 1310ba95c745SQuentin Monnet return -1; 1311ba95c745SQuentin Monnet } 1312ba95c745SQuentin Monnet NEXT_ARG(); 1313ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1314ba95c745SQuentin Monnet NEXT_ARG(); 1315ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1316ba95c745SQuentin Monnet return -1; 1317ba95c745SQuentin Monnet 1318ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1319ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1320ba95c745SQuentin Monnet return -1; 1321ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1322ba95c745SQuentin Monnet NEXT_ARG(); 1323ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1324ba95c745SQuentin Monnet return -1; 1325ba95c745SQuentin Monnet 1326ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1327ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1328ba95c745SQuentin Monnet char *endptr; 1329ba95c745SQuentin Monnet 1330ba95c745SQuentin Monnet NEXT_ARG(); 1331ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1332ba95c745SQuentin Monnet return -1; 1333ba95c745SQuentin Monnet 1334ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1335ba95c745SQuentin Monnet if (*endptr) { 1336ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1337ba95c745SQuentin Monnet *argv); 1338ba95c745SQuentin Monnet return -1; 1339ba95c745SQuentin Monnet } 1340ba95c745SQuentin Monnet NEXT_ARG(); 1341ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1342ba95c745SQuentin Monnet char *endptr; 1343ba95c745SQuentin Monnet 1344ba95c745SQuentin Monnet NEXT_ARG(); 1345ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1346ba95c745SQuentin Monnet return -1; 1347ba95c745SQuentin Monnet 1348ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1349ba95c745SQuentin Monnet if (*endptr) { 1350ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1351ba95c745SQuentin Monnet *argv); 1352ba95c745SQuentin Monnet return -1; 1353ba95c745SQuentin Monnet } 1354ba95c745SQuentin Monnet NEXT_ARG(); 1355ba95c745SQuentin Monnet } else { 1356ba95c745SQuentin Monnet p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1357ba95c745SQuentin Monnet *argv); 1358ba95c745SQuentin Monnet return -1; 1359ba95c745SQuentin Monnet } 1360ba95c745SQuentin Monnet } 1361ba95c745SQuentin Monnet 1362ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1363ba95c745SQuentin Monnet if (err) 1364ba95c745SQuentin Monnet return -1; 1365ba95c745SQuentin Monnet 1366ba95c745SQuentin Monnet if (data_in) { 1367ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1368ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1369ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1370ba95c745SQuentin Monnet if (err) 1371ba95c745SQuentin Monnet goto free_data_in; 1372ba95c745SQuentin Monnet } 1373ba95c745SQuentin Monnet 1374ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1375ba95c745SQuentin Monnet if (err) 1376ba95c745SQuentin Monnet goto free_data_out; 1377ba95c745SQuentin Monnet 1378ba95c745SQuentin Monnet if (ctx_in) { 1379ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1380ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1381ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1382ba95c745SQuentin Monnet if (err) 1383ba95c745SQuentin Monnet goto free_ctx_in; 1384ba95c745SQuentin Monnet } 1385ba95c745SQuentin Monnet 1386ba95c745SQuentin Monnet test_attr.repeat = repeat; 1387ba95c745SQuentin Monnet test_attr.data_in = data_in; 1388ba95c745SQuentin Monnet test_attr.data_out = data_out; 1389ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1390ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1391ba95c745SQuentin Monnet 13929cce5313SDelyan Kratunov err = bpf_prog_test_run_opts(fd, &test_attr); 1393ba95c745SQuentin Monnet if (err) { 1394ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1395ba95c745SQuentin Monnet goto free_ctx_out; 1396ba95c745SQuentin Monnet } 1397ba95c745SQuentin Monnet 1398ba95c745SQuentin Monnet err = 0; 1399ba95c745SQuentin Monnet 1400ba95c745SQuentin Monnet if (json_output) 1401ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1402ba95c745SQuentin Monnet 1403ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1404ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1405ba95c745SQuentin Monnet */ 1406ba95c745SQuentin Monnet if (test_attr.data_size_out) 1407ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1408ba95c745SQuentin Monnet test_attr.data_size_out, 1409ba95c745SQuentin Monnet data_fname_out, "data_out"); 1410ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1411ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1412ba95c745SQuentin Monnet test_attr.ctx_size_out, 1413ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1414ba95c745SQuentin Monnet 1415ba95c745SQuentin Monnet if (json_output) { 1416ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1417ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1418ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1419ba95c745SQuentin Monnet } else { 1420ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1421ba95c745SQuentin Monnet test_attr.retval, 1422ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1423ba95c745SQuentin Monnet } 1424ba95c745SQuentin Monnet 1425ba95c745SQuentin Monnet free_ctx_out: 1426ba95c745SQuentin Monnet free(ctx_out); 1427ba95c745SQuentin Monnet free_ctx_in: 1428ba95c745SQuentin Monnet free(ctx_in); 1429ba95c745SQuentin Monnet free_data_out: 1430ba95c745SQuentin Monnet free(data_out); 1431ba95c745SQuentin Monnet free_data_in: 1432ba95c745SQuentin Monnet free(data_in); 1433ba95c745SQuentin Monnet 1434ba95c745SQuentin Monnet return err; 1435ba95c745SQuentin Monnet } 1436ba95c745SQuentin Monnet 14376ae32b29SQuentin Monnet static int 14386ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14396ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14406ae32b29SQuentin Monnet { 14416ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14426ae32b29SQuentin Monnet int ret; 14436ae32b29SQuentin Monnet 14446ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14456ae32b29SQuentin Monnet if (!ret) 14466ae32b29SQuentin Monnet return ret; 14476ae32b29SQuentin Monnet 14486ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14496ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14506ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14516ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14526ae32b29SQuentin Monnet 14536ae32b29SQuentin Monnet return ret; 14546ae32b29SQuentin Monnet } 14556ae32b29SQuentin Monnet 145677380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 145749a086c2SRoman Gushchin { 145832e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1459e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1460e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1461e00aca65SAndrii Nakryiko ); 146255d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 14633ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 146477380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 14653ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 14663767a94bSStanislav Fomichev const char *pinmaps = NULL; 146749a086c2SRoman Gushchin struct bpf_object *obj; 1468c8406848SJakub Kicinski struct bpf_map *map; 1469c8406848SJakub Kicinski const char *pinfile; 14703ff5a4dcSJakub Kicinski unsigned int i, j; 1471c8406848SJakub Kicinski __u32 ifindex = 0; 147232e3e58eSAndrii Nakryiko const char *file; 14733ff5a4dcSJakub Kicinski int idx, err; 147449a086c2SRoman Gushchin 147532e3e58eSAndrii Nakryiko 14768d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 14778d1fc3deSJakub Kicinski return -1; 147832e3e58eSAndrii Nakryiko file = GET_ARG(); 14798d1fc3deSJakub Kicinski pinfile = GET_ARG(); 148049a086c2SRoman Gushchin 1481ba6dd679SJakub Kicinski while (argc) { 148249f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 148349f2cba3SJakub Kicinski NEXT_ARG(); 148449f2cba3SJakub Kicinski 148532e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 148649f2cba3SJakub Kicinski p_err("program type already specified"); 14873ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 148849f2cba3SJakub Kicinski } 148949f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 14903ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 149149f2cba3SJakub Kicinski 1492314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1493314f14abSStanislav Fomichev &expected_attach_type); 1494314f14abSStanislav Fomichev if (err < 0) { 149549f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1496314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1497314f14abSStanislav Fomichev 149849f2cba3SJakub Kicinski if (!type) { 149949f2cba3SJakub Kicinski p_err("mem alloc failed"); 15003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 150149f2cba3SJakub Kicinski } 150249f2cba3SJakub Kicinski *type = 0; 150349f2cba3SJakub Kicinski strcat(type, *argv); 150449f2cba3SJakub Kicinski strcat(type, "/"); 150549f2cba3SJakub Kicinski 15066ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1507c8406848SJakub Kicinski &expected_attach_type); 150849f2cba3SJakub Kicinski free(type); 1509c76e4c22STaeung Song if (err < 0) 15103ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1511314f14abSStanislav Fomichev } 1512c76e4c22STaeung Song 151349f2cba3SJakub Kicinski NEXT_ARG(); 15143ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1515dde7011aSJakub Kicinski void *new_map_replace; 15163ff5a4dcSJakub Kicinski char *endptr, *name; 15173ff5a4dcSJakub Kicinski int fd; 15183ff5a4dcSJakub Kicinski 15193ff5a4dcSJakub Kicinski NEXT_ARG(); 15203ff5a4dcSJakub Kicinski 15213ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15223ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15233ff5a4dcSJakub Kicinski 15243ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15253ff5a4dcSJakub Kicinski NEXT_ARG(); 15263ff5a4dcSJakub Kicinski 15273ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15283ff5a4dcSJakub Kicinski if (*endptr) { 15293ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15303ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15313ff5a4dcSJakub Kicinski } 15323ff5a4dcSJakub Kicinski name = NULL; 15333ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 15343ff5a4dcSJakub Kicinski NEXT_ARG(); 15353ff5a4dcSJakub Kicinski 15363ff5a4dcSJakub Kicinski name = *argv; 15373ff5a4dcSJakub Kicinski idx = -1; 15383ff5a4dcSJakub Kicinski } else { 15393ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 15403ff5a4dcSJakub Kicinski *argv); 15413ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15423ff5a4dcSJakub Kicinski } 15433ff5a4dcSJakub Kicinski NEXT_ARG(); 15443ff5a4dcSJakub Kicinski 15453ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 15463ff5a4dcSJakub Kicinski if (fd < 0) 15473ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15483ff5a4dcSJakub Kicinski 1549a19df713SMauricio Vásquez new_map_replace = libbpf_reallocarray(map_replace, 1550dde7011aSJakub Kicinski old_map_fds + 1, 15513ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1552dde7011aSJakub Kicinski if (!new_map_replace) { 15533ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 15543ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15553ff5a4dcSJakub Kicinski } 1556dde7011aSJakub Kicinski map_replace = new_map_replace; 1557dde7011aSJakub Kicinski 15583ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 15593ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 15603ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 15613ff5a4dcSJakub Kicinski old_map_fds++; 156249f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1563ba6dd679SJakub Kicinski NEXT_ARG(); 1564ba6dd679SJakub Kicinski 1565c8406848SJakub Kicinski if (ifindex) { 1566ba6dd679SJakub Kicinski p_err("offload device already specified"); 15673ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1568ba6dd679SJakub Kicinski } 1569ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 15703ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1571ba6dd679SJakub Kicinski 1572c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1573c8406848SJakub Kicinski if (!ifindex) { 1574ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1575ba6dd679SJakub Kicinski *argv, strerror(errno)); 15763ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1577ba6dd679SJakub Kicinski } 1578ba6dd679SJakub Kicinski NEXT_ARG(); 15793767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 15803767a94bSStanislav Fomichev NEXT_ARG(); 15813767a94bSStanislav Fomichev 15823767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 15833767a94bSStanislav Fomichev goto err_free_reuse_maps; 15843767a94bSStanislav Fomichev 15853767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1586ba6dd679SJakub Kicinski } else { 15873ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1588ba6dd679SJakub Kicinski *argv); 15893ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1590ba6dd679SJakub Kicinski } 1591ba6dd679SJakub Kicinski } 1592ba6dd679SJakub Kicinski 1593b59e4ce8SAndrii Nakryiko if (verifier_logs) 1594b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1595b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1596b59e4ce8SAndrii Nakryiko 159732e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1598d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1599c8406848SJakub Kicinski p_err("failed to open object file"); 16003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 160149a086c2SRoman Gushchin } 160249a086c2SRoman Gushchin 160377380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 160432e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1605c8406848SJakub Kicinski 160632e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1607fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1608c8406848SJakub Kicinski 16096ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1610c8406848SJakub Kicinski &expected_attach_type); 1611c76e4c22STaeung Song if (err < 0) 1612c8406848SJakub Kicinski goto err_close_obj; 1613c8406848SJakub Kicinski } 161477380998SStanislav Fomichev 161577380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 161677380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 161777380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 161877380998SStanislav Fomichev } 1619c8406848SJakub Kicinski 16203ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16213ff5a4dcSJakub Kicinski map_replace_compar); 16223ff5a4dcSJakub Kicinski 16233ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16243ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16253ff5a4dcSJakub Kicinski */ 16263ff5a4dcSJakub Kicinski j = 0; 16273ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 16283ff5a4dcSJakub Kicinski i = 0; 1629f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16303ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 16313ff5a4dcSJakub Kicinski map_replace[j].idx = i; 16323ff5a4dcSJakub Kicinski break; 16333ff5a4dcSJakub Kicinski } 16343ff5a4dcSJakub Kicinski i++; 16353ff5a4dcSJakub Kicinski } 16363ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 16373ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 16383ff5a4dcSJakub Kicinski goto err_close_obj; 16393ff5a4dcSJakub Kicinski } 16403ff5a4dcSJakub Kicinski j++; 16413ff5a4dcSJakub Kicinski } 16423ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 16433ff5a4dcSJakub Kicinski if (j) 16443ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16453ff5a4dcSJakub Kicinski map_replace_compar); 16463ff5a4dcSJakub Kicinski 16473ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 16483ff5a4dcSJakub Kicinski j = 0; 16493ff5a4dcSJakub Kicinski idx = 0; 1650f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16519855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1652c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1653c8406848SJakub Kicinski 16543ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 16553ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 16563ff5a4dcSJakub Kicinski if (err) { 16573ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 16583ff5a4dcSJakub Kicinski goto err_close_obj; 16593ff5a4dcSJakub Kicinski } 16603ff5a4dcSJakub Kicinski 16613ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 16623ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 16633ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 16643ff5a4dcSJakub Kicinski idx); 16653ff5a4dcSJakub Kicinski goto err_close_obj; 16663ff5a4dcSJakub Kicinski } 16673ff5a4dcSJakub Kicinski } 16683ff5a4dcSJakub Kicinski 16693ff5a4dcSJakub Kicinski idx++; 16703ff5a4dcSJakub Kicinski } 16713ff5a4dcSJakub Kicinski if (j < old_map_fds) { 16723ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 16733ff5a4dcSJakub Kicinski goto err_close_obj; 16743ff5a4dcSJakub Kicinski } 16753ff5a4dcSJakub Kicinski 1676b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1677c8406848SJakub Kicinski if (err) { 1678c8406848SJakub Kicinski p_err("failed to load object file"); 1679c8406848SJakub Kicinski goto err_close_obj; 1680c8406848SJakub Kicinski } 1681c8406848SJakub Kicinski 168277380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 168377380998SStanislav Fomichev if (err) 1684bfee71fbSJakub Kicinski goto err_close_obj; 168549a086c2SRoman Gushchin 168677380998SStanislav Fomichev if (first_prog_only) { 16876f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 168877380998SStanislav Fomichev if (!prog) { 168977380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 169077380998SStanislav Fomichev goto err_close_obj; 169177380998SStanislav Fomichev } 169277380998SStanislav Fomichev 169377380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 169477380998SStanislav Fomichev if (err) { 169577380998SStanislav Fomichev p_err("failed to pin program %s", 1696fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 169777380998SStanislav Fomichev goto err_close_obj; 169877380998SStanislav Fomichev } 169977380998SStanislav Fomichev } else { 170077380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 170177380998SStanislav Fomichev if (err) { 170277380998SStanislav Fomichev p_err("failed to pin all programs"); 170377380998SStanislav Fomichev goto err_close_obj; 170477380998SStanislav Fomichev } 170577380998SStanislav Fomichev } 170677380998SStanislav Fomichev 17073767a94bSStanislav Fomichev if (pinmaps) { 17083767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 17093767a94bSStanislav Fomichev if (err) { 17103767a94bSStanislav Fomichev p_err("failed to pin all maps"); 17113767a94bSStanislav Fomichev goto err_unpin; 17123767a94bSStanislav Fomichev } 17133767a94bSStanislav Fomichev } 17143767a94bSStanislav Fomichev 171549a086c2SRoman Gushchin if (json_output) 171649a086c2SRoman Gushchin jsonw_null(json_wtr); 171749a086c2SRoman Gushchin 1718bfee71fbSJakub Kicinski bpf_object__close(obj); 17193ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17203ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17213ff5a4dcSJakub Kicinski free(map_replace); 1722bfee71fbSJakub Kicinski 172349a086c2SRoman Gushchin return 0; 1724bfee71fbSJakub Kicinski 17253767a94bSStanislav Fomichev err_unpin: 17263767a94bSStanislav Fomichev if (first_prog_only) 17273767a94bSStanislav Fomichev unlink(pinfile); 17283767a94bSStanislav Fomichev else 17293767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1730bfee71fbSJakub Kicinski err_close_obj: 1731314f14abSStanislav Fomichev if (!legacy_libbpf) { 1732314f14abSStanislav Fomichev p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n" 1733314f14abSStanislav Fomichev "If it used to work for this object file but now doesn't, see --legacy option for more details.\n"); 1734314f14abSStanislav Fomichev } 1735314f14abSStanislav Fomichev 1736bfee71fbSJakub Kicinski bpf_object__close(obj); 17373ff5a4dcSJakub Kicinski err_free_reuse_maps: 17383ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17393ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17403ff5a4dcSJakub Kicinski free(map_replace); 1741bfee71fbSJakub Kicinski return -1; 174249a086c2SRoman Gushchin } 174349a086c2SRoman Gushchin 1744d510296dSAlexei Starovoitov static int count_open_fds(void) 1745d510296dSAlexei Starovoitov { 1746d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1747d510296dSAlexei Starovoitov struct dirent *de; 1748d510296dSAlexei Starovoitov int cnt = -3; 1749d510296dSAlexei Starovoitov 1750d510296dSAlexei Starovoitov if (!dp) 1751d510296dSAlexei Starovoitov return -1; 1752d510296dSAlexei Starovoitov 1753d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1754d510296dSAlexei Starovoitov cnt++; 1755d510296dSAlexei Starovoitov 1756d510296dSAlexei Starovoitov closedir(dp); 1757d510296dSAlexei Starovoitov return cnt; 1758d510296dSAlexei Starovoitov } 1759d510296dSAlexei Starovoitov 1760d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1761d510296dSAlexei Starovoitov { 1762d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1763d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1764d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1765d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1766d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1767d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1768942df4dcSAlexei Starovoitov char *log_buf = NULL; 1769d510296dSAlexei Starovoitov 1770d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1771d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1772d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1773942df4dcSAlexei Starovoitov if (verifier_logs) { 1774942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1775d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1776d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1777d510296dSAlexei Starovoitov if (!log_buf) 1778d510296dSAlexei Starovoitov return -ENOMEM; 1779d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1780942df4dcSAlexei Starovoitov } 1781d510296dSAlexei Starovoitov opts.ctx = ctx; 1782d510296dSAlexei Starovoitov opts.data = gen->data; 1783d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1784d510296dSAlexei Starovoitov opts.insns = gen->insns; 1785d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1786d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1787d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1788d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1789942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1790d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1791942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1792d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1793d510296dSAlexei Starovoitov fd_delta); 1794d510296dSAlexei Starovoitov } 1795d510296dSAlexei Starovoitov free(log_buf); 1796d510296dSAlexei Starovoitov return err; 1797d510296dSAlexei Starovoitov } 1798d510296dSAlexei Starovoitov 1799d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1800d510296dSAlexei Starovoitov { 1801d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1802d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1803d510296dSAlexei Starovoitov struct bpf_object *obj; 1804d510296dSAlexei Starovoitov const char *file; 1805d510296dSAlexei Starovoitov int err = 0; 1806d510296dSAlexei Starovoitov 1807d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1808d510296dSAlexei Starovoitov return -1; 1809d510296dSAlexei Starovoitov file = GET_ARG(); 1810d510296dSAlexei Starovoitov 1811b59e4ce8SAndrii Nakryiko if (verifier_logs) 1812b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1813b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1814b59e4ce8SAndrii Nakryiko 1815d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1816d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1817d510296dSAlexei Starovoitov p_err("failed to open object file"); 1818d510296dSAlexei Starovoitov goto err_close_obj; 1819d510296dSAlexei Starovoitov } 1820d510296dSAlexei Starovoitov 1821d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1822d510296dSAlexei Starovoitov if (err) 1823d510296dSAlexei Starovoitov goto err_close_obj; 1824d510296dSAlexei Starovoitov 1825b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1826d510296dSAlexei Starovoitov if (err) { 1827d510296dSAlexei Starovoitov p_err("failed to load object file"); 1828d510296dSAlexei Starovoitov goto err_close_obj; 1829d510296dSAlexei Starovoitov } 1830d510296dSAlexei Starovoitov 1831d510296dSAlexei Starovoitov if (verifier_logs) { 1832d510296dSAlexei Starovoitov struct dump_data dd = {}; 1833d510296dSAlexei Starovoitov 1834d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1835d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1836d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1837d510296dSAlexei Starovoitov } 1838d510296dSAlexei Starovoitov err = try_loader(&gen); 1839d510296dSAlexei Starovoitov err_close_obj: 1840d510296dSAlexei Starovoitov bpf_object__close(obj); 1841d510296dSAlexei Starovoitov return err; 1842d510296dSAlexei Starovoitov } 1843d510296dSAlexei Starovoitov 184477380998SStanislav Fomichev static int do_load(int argc, char **argv) 184577380998SStanislav Fomichev { 1846d510296dSAlexei Starovoitov if (use_loader) 1847d510296dSAlexei Starovoitov return do_loader(argc, argv); 184877380998SStanislav Fomichev return load_with_options(argc, argv, true); 184977380998SStanislav Fomichev } 185077380998SStanislav Fomichev 185177380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 185277380998SStanislav Fomichev { 185377380998SStanislav Fomichev return load_with_options(argc, argv, false); 185477380998SStanislav Fomichev } 185577380998SStanislav Fomichev 185647c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 185747c09d6aSSong Liu 185847c09d6aSSong Liu static int do_profile(int argc, char **argv) 185947c09d6aSSong Liu { 186014e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 186147c09d6aSSong Liu return 0; 186247c09d6aSSong Liu } 186347c09d6aSSong Liu 186447c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 186547c09d6aSSong Liu 186647c09d6aSSong Liu #include "profiler.skel.h" 186747c09d6aSSong Liu 186847c09d6aSSong Liu struct profile_metric { 186947c09d6aSSong Liu const char *name; 187047c09d6aSSong Liu struct bpf_perf_event_value val; 187147c09d6aSSong Liu struct perf_event_attr attr; 187247c09d6aSSong Liu bool selected; 187347c09d6aSSong Liu 187447c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 187547c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 187647c09d6aSSong Liu const char *ratio_desc; 187747c09d6aSSong Liu const float ratio_mul; 187847c09d6aSSong Liu } metrics[] = { 187947c09d6aSSong Liu { 188047c09d6aSSong Liu .name = "cycles", 188147c09d6aSSong Liu .attr = { 188247c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 188347c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 188447c09d6aSSong Liu .exclude_user = 1, 188547c09d6aSSong Liu }, 188647c09d6aSSong Liu }, 188747c09d6aSSong Liu { 188847c09d6aSSong Liu .name = "instructions", 188947c09d6aSSong Liu .attr = { 189047c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 189147c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 189247c09d6aSSong Liu .exclude_user = 1, 189347c09d6aSSong Liu }, 189447c09d6aSSong Liu .ratio_metric = 1, 189547c09d6aSSong Liu .ratio_desc = "insns per cycle", 189647c09d6aSSong Liu .ratio_mul = 1.0, 189747c09d6aSSong Liu }, 189847c09d6aSSong Liu { 189947c09d6aSSong Liu .name = "l1d_loads", 190047c09d6aSSong Liu .attr = { 190147c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 190247c09d6aSSong Liu .config = 190347c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 190447c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 190547c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 190647c09d6aSSong Liu .exclude_user = 1, 190747c09d6aSSong Liu }, 190847c09d6aSSong Liu }, 190947c09d6aSSong Liu { 191047c09d6aSSong Liu .name = "llc_misses", 191147c09d6aSSong Liu .attr = { 191247c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 191347c09d6aSSong Liu .config = 191447c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 191547c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 191647c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 191747c09d6aSSong Liu .exclude_user = 1 191847c09d6aSSong Liu }, 191947c09d6aSSong Liu .ratio_metric = 2, 192047c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 192147c09d6aSSong Liu .ratio_mul = 1e6, 192247c09d6aSSong Liu }, 1923450d060eSYonghong Song { 1924450d060eSYonghong Song .name = "itlb_misses", 1925450d060eSYonghong Song .attr = { 1926450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1927450d060eSYonghong Song .config = 1928450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 1929450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1930450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1931450d060eSYonghong Song .exclude_user = 1 1932450d060eSYonghong Song }, 1933450d060eSYonghong Song .ratio_metric = 2, 1934450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 1935450d060eSYonghong Song .ratio_mul = 1e6, 1936450d060eSYonghong Song }, 1937450d060eSYonghong Song { 1938450d060eSYonghong Song .name = "dtlb_misses", 1939450d060eSYonghong Song .attr = { 1940450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1941450d060eSYonghong Song .config = 1942450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 1943450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1944450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1945450d060eSYonghong Song .exclude_user = 1 1946450d060eSYonghong Song }, 1947450d060eSYonghong Song .ratio_metric = 2, 1948450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 1949450d060eSYonghong Song .ratio_mul = 1e6, 1950450d060eSYonghong Song }, 195147c09d6aSSong Liu }; 195247c09d6aSSong Liu 195347c09d6aSSong Liu static __u64 profile_total_count; 195447c09d6aSSong Liu 195547c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 195647c09d6aSSong Liu 195747c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 195847c09d6aSSong Liu { 195947c09d6aSSong Liu unsigned int metric_cnt; 196047c09d6aSSong Liu int selected_cnt = 0; 196147c09d6aSSong Liu unsigned int i; 196247c09d6aSSong Liu 196347c09d6aSSong Liu metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 196447c09d6aSSong Liu 196547c09d6aSSong Liu while (argc > 0) { 196647c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 196747c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 196847c09d6aSSong Liu if (!metrics[i].selected) 196947c09d6aSSong Liu selected_cnt++; 197047c09d6aSSong Liu metrics[i].selected = true; 197147c09d6aSSong Liu break; 197247c09d6aSSong Liu } 197347c09d6aSSong Liu } 197447c09d6aSSong Liu if (i == metric_cnt) { 197547c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 197647c09d6aSSong Liu return -1; 197747c09d6aSSong Liu } 197847c09d6aSSong Liu NEXT_ARG(); 197947c09d6aSSong Liu } 198047c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 198147c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 198247c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 198347c09d6aSSong Liu return -1; 198447c09d6aSSong Liu } 198547c09d6aSSong Liu return selected_cnt; 198647c09d6aSSong Liu } 198747c09d6aSSong Liu 198847c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 198947c09d6aSSong Liu { 199047c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 199147c09d6aSSong Liu int reading_map_fd, count_map_fd; 199247c09d6aSSong Liu __u64 counts[num_cpu]; 199347c09d6aSSong Liu __u32 key = 0; 199447c09d6aSSong Liu int err; 199547c09d6aSSong Liu 199647c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 199747c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 199847c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 199947c09d6aSSong Liu p_err("failed to get fd for map"); 200047c09d6aSSong Liu return; 200147c09d6aSSong Liu } 200247c09d6aSSong Liu 200347c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 200447c09d6aSSong Liu if (err) { 200547c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 200647c09d6aSSong Liu return; 200747c09d6aSSong Liu } 200847c09d6aSSong Liu 200947c09d6aSSong Liu profile_total_count = 0; 201047c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 201147c09d6aSSong Liu profile_total_count += counts[cpu]; 201247c09d6aSSong Liu 201347c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 201447c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 201547c09d6aSSong Liu 201647c09d6aSSong Liu if (!metrics[m].selected) 201747c09d6aSSong Liu continue; 201847c09d6aSSong Liu 201947c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 202047c09d6aSSong Liu if (err) { 202147c09d6aSSong Liu p_err("failed to read reading_map: %s", 202247c09d6aSSong Liu strerror(errno)); 202347c09d6aSSong Liu return; 202447c09d6aSSong Liu } 202547c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 202647c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 202747c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 202847c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 202947c09d6aSSong Liu } 203047c09d6aSSong Liu key++; 203147c09d6aSSong Liu } 203247c09d6aSSong Liu } 203347c09d6aSSong Liu 203447c09d6aSSong Liu static void profile_print_readings_json(void) 203547c09d6aSSong Liu { 203647c09d6aSSong Liu __u32 m; 203747c09d6aSSong Liu 203847c09d6aSSong Liu jsonw_start_array(json_wtr); 203947c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 204047c09d6aSSong Liu if (!metrics[m].selected) 204147c09d6aSSong Liu continue; 204247c09d6aSSong Liu jsonw_start_object(json_wtr); 204347c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 204447c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 204547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 204647c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 204747c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 204847c09d6aSSong Liu 204947c09d6aSSong Liu jsonw_end_object(json_wtr); 205047c09d6aSSong Liu } 205147c09d6aSSong Liu jsonw_end_array(json_wtr); 205247c09d6aSSong Liu } 205347c09d6aSSong Liu 205447c09d6aSSong Liu static void profile_print_readings_plain(void) 205547c09d6aSSong Liu { 205647c09d6aSSong Liu __u32 m; 205747c09d6aSSong Liu 205847c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 205947c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 206047c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 206147c09d6aSSong Liu int r; 206247c09d6aSSong Liu 206347c09d6aSSong Liu if (!metrics[m].selected) 206447c09d6aSSong Liu continue; 206547c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 206647c09d6aSSong Liu 206747c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 206847c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 206947c09d6aSSong Liu metrics[r].val.counter > 0) { 207047c09d6aSSong Liu printf("# %8.2f %-30s", 207147c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 207247c09d6aSSong Liu metrics[r].val.counter, 207347c09d6aSSong Liu metrics[m].ratio_desc); 207447c09d6aSSong Liu } else { 207547c09d6aSSong Liu printf("%-41s", ""); 207647c09d6aSSong Liu } 207747c09d6aSSong Liu 207847c09d6aSSong Liu if (val->enabled > val->running) 207947c09d6aSSong Liu printf("(%4.2f%%)", 208047c09d6aSSong Liu val->running * 100.0 / val->enabled); 208147c09d6aSSong Liu printf("\n"); 208247c09d6aSSong Liu } 208347c09d6aSSong Liu } 208447c09d6aSSong Liu 208547c09d6aSSong Liu static void profile_print_readings(void) 208647c09d6aSSong Liu { 208747c09d6aSSong Liu if (json_output) 208847c09d6aSSong Liu profile_print_readings_json(); 208947c09d6aSSong Liu else 209047c09d6aSSong Liu profile_print_readings_plain(); 209147c09d6aSSong Liu } 209247c09d6aSSong Liu 209347c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 209447c09d6aSSong Liu { 2095c59765cfSDave Marchevsky struct bpf_func_info func_info; 2096c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2097c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 209847c09d6aSSong Liu const struct btf_type *t; 2099c59765cfSDave Marchevsky __u32 func_info_rec_size; 2100369e955bSQuentin Monnet struct btf *btf = NULL; 210147c09d6aSSong Liu char *name = NULL; 2102c59765cfSDave Marchevsky int err; 210347c09d6aSSong Liu 2104c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2105c59765cfSDave Marchevsky if (err) { 2106c59765cfSDave Marchevsky p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd); 2107c59765cfSDave Marchevsky goto out; 210847c09d6aSSong Liu } 210947c09d6aSSong Liu 2110c59765cfSDave Marchevsky if (info.btf_id == 0) { 211147c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 211247c09d6aSSong Liu goto out; 211347c09d6aSSong Liu } 211447c09d6aSSong Liu 2115c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2116c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2117c59765cfSDave Marchevsky p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd); 2118c59765cfSDave Marchevsky goto out; 2119c59765cfSDave Marchevsky } 2120c59765cfSDave Marchevsky 2121c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2122c59765cfSDave Marchevsky info.nr_func_info = 1; 2123c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2124c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2125c59765cfSDave Marchevsky 2126c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2127c59765cfSDave Marchevsky if (err) { 2128c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2129c59765cfSDave Marchevsky goto out; 2130c59765cfSDave Marchevsky } 2131c59765cfSDave Marchevsky 2132c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 213386f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 213486f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 213586f4b7f2SQuentin Monnet goto out; 213686f4b7f2SQuentin Monnet } 213786f4b7f2SQuentin Monnet 2138c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 213947c09d6aSSong Liu if (!t) { 214047c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2141c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 214247c09d6aSSong Liu goto out; 214347c09d6aSSong Liu } 214447c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 214547c09d6aSSong Liu out: 2146369e955bSQuentin Monnet btf__free(btf); 214747c09d6aSSong Liu return name; 214847c09d6aSSong Liu } 214947c09d6aSSong Liu 215047c09d6aSSong Liu static struct profiler_bpf *profile_obj; 215147c09d6aSSong Liu static int profile_tgt_fd = -1; 215247c09d6aSSong Liu static char *profile_tgt_name; 215347c09d6aSSong Liu static int *profile_perf_events; 215447c09d6aSSong Liu static int profile_perf_event_cnt; 215547c09d6aSSong Liu 215647c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 215747c09d6aSSong Liu { 215847c09d6aSSong Liu int i; 215947c09d6aSSong Liu 216047c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 216147c09d6aSSong Liu close(profile_perf_events[i]); 216247c09d6aSSong Liu 216347c09d6aSSong Liu free(profile_perf_events); 216447c09d6aSSong Liu profile_perf_event_cnt = 0; 216547c09d6aSSong Liu } 216647c09d6aSSong Liu 216747c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 216847c09d6aSSong Liu { 216947c09d6aSSong Liu unsigned int cpu, m; 217047c09d6aSSong Liu int map_fd, pmu_fd; 217147c09d6aSSong Liu 217247c09d6aSSong Liu profile_perf_events = calloc( 217347c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 217447c09d6aSSong Liu if (!profile_perf_events) { 217547c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 217647c09d6aSSong Liu strerror(errno)); 217747c09d6aSSong Liu return -1; 217847c09d6aSSong Liu } 217947c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 218047c09d6aSSong Liu if (map_fd < 0) { 218147c09d6aSSong Liu p_err("failed to get fd for events map"); 218247c09d6aSSong Liu return -1; 218347c09d6aSSong Liu } 218447c09d6aSSong Liu 218547c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 218647c09d6aSSong Liu if (!metrics[m].selected) 218747c09d6aSSong Liu continue; 218847c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 218947c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 219047c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 219147c09d6aSSong Liu if (pmu_fd < 0 || 219247c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 219347c09d6aSSong Liu &pmu_fd, BPF_ANY) || 219447c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 219547c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 219647c09d6aSSong Liu metrics[m].name, cpu); 219747c09d6aSSong Liu return -1; 219847c09d6aSSong Liu } 219947c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 220047c09d6aSSong Liu } 220147c09d6aSSong Liu } 220247c09d6aSSong Liu return 0; 220347c09d6aSSong Liu } 220447c09d6aSSong Liu 220547c09d6aSSong Liu static void profile_print_and_cleanup(void) 220647c09d6aSSong Liu { 220747c09d6aSSong Liu profile_close_perf_events(profile_obj); 220847c09d6aSSong Liu profile_read_values(profile_obj); 220947c09d6aSSong Liu profile_print_readings(); 221047c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 221147c09d6aSSong Liu 221247c09d6aSSong Liu close(profile_tgt_fd); 221347c09d6aSSong Liu free(profile_tgt_name); 221447c09d6aSSong Liu } 221547c09d6aSSong Liu 221647c09d6aSSong Liu static void int_exit(int signo) 221747c09d6aSSong Liu { 221847c09d6aSSong Liu profile_print_and_cleanup(); 221947c09d6aSSong Liu exit(0); 222047c09d6aSSong Liu } 222147c09d6aSSong Liu 222247c09d6aSSong Liu static int do_profile(int argc, char **argv) 222347c09d6aSSong Liu { 222447c09d6aSSong Liu int num_metric, num_cpu, err = -1; 222547c09d6aSSong Liu struct bpf_program *prog; 222647c09d6aSSong Liu unsigned long duration; 222747c09d6aSSong Liu char *endptr; 222847c09d6aSSong Liu 222947c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 223047c09d6aSSong Liu if (!REQ_ARGS(3)) 223147c09d6aSSong Liu return -EINVAL; 223247c09d6aSSong Liu 223347c09d6aSSong Liu /* parse target fd */ 223447c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 223547c09d6aSSong Liu if (profile_tgt_fd < 0) { 223647c09d6aSSong Liu p_err("failed to parse fd"); 223747c09d6aSSong Liu return -1; 223847c09d6aSSong Liu } 223947c09d6aSSong Liu 224047c09d6aSSong Liu /* parse profiling optional duration */ 224147c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 224247c09d6aSSong Liu NEXT_ARG(); 224347c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 224447c09d6aSSong Liu if (*endptr) 224547c09d6aSSong Liu usage(); 224647c09d6aSSong Liu NEXT_ARG(); 224747c09d6aSSong Liu } else { 224847c09d6aSSong Liu duration = UINT_MAX; 224947c09d6aSSong Liu } 225047c09d6aSSong Liu 225147c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 225247c09d6aSSong Liu if (num_metric <= 0) 225347c09d6aSSong Liu goto out; 225447c09d6aSSong Liu 225547c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 225647c09d6aSSong Liu if (num_cpu <= 0) { 225747c09d6aSSong Liu p_err("failed to identify number of CPUs"); 225847c09d6aSSong Liu goto out; 225947c09d6aSSong Liu } 226047c09d6aSSong Liu 226147c09d6aSSong Liu profile_obj = profiler_bpf__open(); 226247c09d6aSSong Liu if (!profile_obj) { 226347c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 226447c09d6aSSong Liu goto out; 226547c09d6aSSong Liu } 226647c09d6aSSong Liu 226747c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 226847c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 226947c09d6aSSong Liu 227047c09d6aSSong Liu /* adjust map sizes */ 227139748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 227239748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 227339748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 227439748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.counts, 1); 227547c09d6aSSong Liu 227647c09d6aSSong Liu /* change target name */ 227747c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 227847c09d6aSSong Liu if (!profile_tgt_name) 227947c09d6aSSong Liu goto out; 228047c09d6aSSong Liu 228147c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 228247c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 228347c09d6aSSong Liu profile_tgt_name); 228447c09d6aSSong Liu if (err) { 228547c09d6aSSong Liu p_err("failed to set attach target\n"); 228647c09d6aSSong Liu goto out; 228747c09d6aSSong Liu } 228847c09d6aSSong Liu } 228947c09d6aSSong Liu 229047c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 229147c09d6aSSong Liu if (err) { 229247c09d6aSSong Liu p_err("failed to load profile_obj"); 229347c09d6aSSong Liu goto out; 229447c09d6aSSong Liu } 229547c09d6aSSong Liu 229647c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 229747c09d6aSSong Liu if (err) 229847c09d6aSSong Liu goto out; 229947c09d6aSSong Liu 230047c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 230147c09d6aSSong Liu if (err) { 230247c09d6aSSong Liu p_err("failed to attach profile_obj"); 230347c09d6aSSong Liu goto out; 230447c09d6aSSong Liu } 230547c09d6aSSong Liu signal(SIGINT, int_exit); 230647c09d6aSSong Liu 230747c09d6aSSong Liu sleep(duration); 230847c09d6aSSong Liu profile_print_and_cleanup(); 230947c09d6aSSong Liu return 0; 231047c09d6aSSong Liu 231147c09d6aSSong Liu out: 231247c09d6aSSong Liu profile_close_perf_events(profile_obj); 231347c09d6aSSong Liu if (profile_obj) 231447c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 231547c09d6aSSong Liu close(profile_tgt_fd); 231647c09d6aSSong Liu free(profile_tgt_name); 231747c09d6aSSong Liu return err; 231847c09d6aSSong Liu } 231947c09d6aSSong Liu 232047c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 232147c09d6aSSong Liu 232271bb428fSJakub Kicinski static int do_help(int argc, char **argv) 232371bb428fSJakub Kicinski { 2324004b45c0SQuentin Monnet if (json_output) { 2325004b45c0SQuentin Monnet jsonw_null(json_wtr); 2326004b45c0SQuentin Monnet return 0; 2327004b45c0SQuentin Monnet } 2328004b45c0SQuentin Monnet 232971bb428fSJakub Kicinski fprintf(stderr, 233090040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 233190040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 233290040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 233390040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 233490040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 233577380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 23363767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 23373767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 233890040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 233990040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 234090040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2341ba95c745SQuentin Monnet " data_in FILE \\\n" 2342ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2343ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2344ba95c745SQuentin Monnet " [repeat N]\n" 234590040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 234690040351SQuentin Monnet " %1$s %2$s tracelog\n" 234790040351SQuentin Monnet " %1$s %2$s help\n" 234871bb428fSJakub Kicinski "\n" 23493ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 235071bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 235149f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 235249f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 235349f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 235449f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2355f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 235649f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 235749f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 235805ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 235905ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 236005ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2361a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 236293a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 2363*1ba5ad36SDaniel Müller " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n" 2364*1ba5ad36SDaniel Müller " sk_skb_stream_parser | flow_dissector }\n" 2365450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2366c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 23678cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 23688cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 236971bb428fSJakub Kicinski "", 237090040351SQuentin Monnet bin_name, argv[-2]); 237171bb428fSJakub Kicinski 237271bb428fSJakub Kicinski return 0; 237371bb428fSJakub Kicinski } 237471bb428fSJakub Kicinski 237571bb428fSJakub Kicinski static const struct cmd cmds[] = { 237671bb428fSJakub Kicinski { "show", do_show }, 23776ebe6dbdSJakub Kicinski { "list", do_show }, 23789f606179SQuentin Monnet { "help", do_help }, 237971bb428fSJakub Kicinski { "dump", do_dump }, 238071bb428fSJakub Kicinski { "pin", do_pin }, 238149a086c2SRoman Gushchin { "load", do_load }, 238277380998SStanislav Fomichev { "loadall", do_loadall }, 2383b7d3826cSJohn Fastabend { "attach", do_attach }, 2384b7d3826cSJohn Fastabend { "detach", do_detach }, 238530da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2386ba95c745SQuentin Monnet { "run", do_run }, 238747c09d6aSSong Liu { "profile", do_profile }, 238871bb428fSJakub Kicinski { 0 } 238971bb428fSJakub Kicinski }; 239071bb428fSJakub Kicinski 239171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 239271bb428fSJakub Kicinski { 239371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 239471bb428fSJakub Kicinski } 2395